Finished JWT/JWS implementation.
This commit is contained in:
parent
9fdfa5caa2
commit
dc363f1854
10 changed files with 1052 additions and 223 deletions
|
@ -8,7 +8,8 @@
|
|||
"symfony/mailer": "^6.0",
|
||||
"matomo/device-detector": "^6.1",
|
||||
"sentry/sdk": "^4.0",
|
||||
"flashwave/syokuhou": "dev-master"
|
||||
"flashwave/syokuhou": "dev-master",
|
||||
"phpseclib/phpseclib": "~3.0"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
|
|
364
composer.lock
generated
364
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "cb1b8aba5b1b619c5fd4d7187ac2018c",
|
||||
"content-hash": "ce2957bfc51cf8af01d85ba4676d1655",
|
||||
"packages": [
|
||||
{
|
||||
"name": "chillerlan/php-qrcode",
|
||||
|
@ -89,16 +89,16 @@
|
|||
},
|
||||
{
|
||||
"name": "chillerlan/php-settings-container",
|
||||
"version": "3.2.0",
|
||||
"version": "3.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/chillerlan/php-settings-container.git",
|
||||
"reference": "8f93648fac8e6bacac8e00a8d325eba4950295e6"
|
||||
"reference": "95ed3e9676a1d47cab2e3174d19b43f5dbf52681"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/8f93648fac8e6bacac8e00a8d325eba4950295e6",
|
||||
"reference": "8f93648fac8e6bacac8e00a8d325eba4950295e6",
|
||||
"url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/95ed3e9676a1d47cab2e3174d19b43f5dbf52681",
|
||||
"reference": "95ed3e9676a1d47cab2e3174d19b43f5dbf52681",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -106,15 +106,16 @@
|
|||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phan/phan": "^5.4",
|
||||
"phpmd/phpmd": "^2.15",
|
||||
"phpstan/phpstan": "^1.11",
|
||||
"phpstan/phpstan-deprecation-rules": "^1.2",
|
||||
"phpunit/phpunit": "^10.5",
|
||||
"squizlabs/php_codesniffer": "^3.9"
|
||||
"squizlabs/php_codesniffer": "^3.10"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"chillerlan\\Settings\\": "src/"
|
||||
"chillerlan\\Settings\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
|
@ -150,7 +151,7 @@
|
|||
"type": "ko_fi"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-02T20:07:15+00:00"
|
||||
"time": "2024-07-16T11:13:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/lexer",
|
||||
|
@ -720,6 +721,233 @@
|
|||
},
|
||||
"time": "2019-09-10T13:16:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/constant_time_encoding",
|
||||
"version": "v3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/constant_time_encoding.git",
|
||||
"reference": "df1e7fde177501eee2037dd159cf04f5f301a512"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/df1e7fde177501eee2037dd159cf04f5f301a512",
|
||||
"reference": "df1e7fde177501eee2037dd159cf04f5f301a512",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9",
|
||||
"vimeo/psalm": "^4|^5"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"ParagonIE\\ConstantTime\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Paragon Initiative Enterprises",
|
||||
"email": "security@paragonie.com",
|
||||
"homepage": "https://paragonie.com",
|
||||
"role": "Maintainer"
|
||||
},
|
||||
{
|
||||
"name": "Steve 'Sc00bz' Thomas",
|
||||
"email": "steve@tobtu.com",
|
||||
"homepage": "https://www.tobtu.com",
|
||||
"role": "Original Developer"
|
||||
}
|
||||
],
|
||||
"description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)",
|
||||
"keywords": [
|
||||
"base16",
|
||||
"base32",
|
||||
"base32_decode",
|
||||
"base32_encode",
|
||||
"base64",
|
||||
"base64_decode",
|
||||
"base64_encode",
|
||||
"bin2hex",
|
||||
"encoding",
|
||||
"hex",
|
||||
"hex2bin",
|
||||
"rfc4648"
|
||||
],
|
||||
"support": {
|
||||
"email": "info@paragonie.com",
|
||||
"issues": "https://github.com/paragonie/constant_time_encoding/issues",
|
||||
"source": "https://github.com/paragonie/constant_time_encoding"
|
||||
},
|
||||
"time": "2024-05-08T12:36:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/random_compat",
|
||||
"version": "v9.99.100",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/random_compat.git",
|
||||
"reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
|
||||
"reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">= 7"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.*|5.*",
|
||||
"vimeo/psalm": "^1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
|
||||
},
|
||||
"type": "library",
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Paragon Initiative Enterprises",
|
||||
"email": "security@paragonie.com",
|
||||
"homepage": "https://paragonie.com"
|
||||
}
|
||||
],
|
||||
"description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
|
||||
"keywords": [
|
||||
"csprng",
|
||||
"polyfill",
|
||||
"pseudorandom",
|
||||
"random"
|
||||
],
|
||||
"support": {
|
||||
"email": "info@paragonie.com",
|
||||
"issues": "https://github.com/paragonie/random_compat/issues",
|
||||
"source": "https://github.com/paragonie/random_compat"
|
||||
},
|
||||
"time": "2020-10-15T08:29:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpseclib/phpseclib",
|
||||
"version": "3.0.39",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpseclib/phpseclib.git",
|
||||
"reference": "211ebc399c6e73c225a018435fe5ae209d1d1485"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/211ebc399c6e73c225a018435fe5ae209d1d1485",
|
||||
"reference": "211ebc399c6e73c225a018435fe5ae209d1d1485",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"paragonie/constant_time_encoding": "^1|^2|^3",
|
||||
"paragonie/random_compat": "^1.4|^2.0|^9.99.99",
|
||||
"php": ">=5.6.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "Install the DOM extension to load XML formatted public keys.",
|
||||
"ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
|
||||
"ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
|
||||
"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."
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"phpseclib/bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"phpseclib3\\": "phpseclib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jim Wigginton",
|
||||
"email": "terrafrost@php.net",
|
||||
"role": "Lead Developer"
|
||||
},
|
||||
{
|
||||
"name": "Patrick Monnerat",
|
||||
"email": "pm@datasphere.ch",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Andreas Fischer",
|
||||
"email": "bantu@phpbb.com",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Hans-Jürgen Petrich",
|
||||
"email": "petrich@tronic-media.com",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Graham Campbell",
|
||||
"email": "graham@alt-three.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",
|
||||
"homepage": "http://phpseclib.sourceforge.net",
|
||||
"keywords": [
|
||||
"BigInteger",
|
||||
"aes",
|
||||
"asn.1",
|
||||
"asn1",
|
||||
"blowfish",
|
||||
"crypto",
|
||||
"cryptography",
|
||||
"encryption",
|
||||
"rsa",
|
||||
"security",
|
||||
"sftp",
|
||||
"signature",
|
||||
"signing",
|
||||
"ssh",
|
||||
"twofish",
|
||||
"x.509",
|
||||
"x509"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpseclib/phpseclib/issues",
|
||||
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.39"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/terrafrost",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/phpseclib",
|
||||
"type": "patreon"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-06-24T06:27:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/container",
|
||||
"version": "2.0.2",
|
||||
|
@ -1082,16 +1310,16 @@
|
|||
},
|
||||
{
|
||||
"name": "sentry/sentry",
|
||||
"version": "4.8.0",
|
||||
"version": "4.8.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/getsentry/sentry-php.git",
|
||||
"reference": "3cf5778ff425a23f2d22ed41b423691d36f47163"
|
||||
"reference": "61770efd8b7888e0bdd7d234f0ba67b066e47d04"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/getsentry/sentry-php/zipball/3cf5778ff425a23f2d22ed41b423691d36f47163",
|
||||
"reference": "3cf5778ff425a23f2d22ed41b423691d36f47163",
|
||||
"url": "https://api.github.com/repos/getsentry/sentry-php/zipball/61770efd8b7888e0bdd7d234f0ba67b066e47d04",
|
||||
"reference": "61770efd8b7888e0bdd7d234f0ba67b066e47d04",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1155,7 +1383,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/getsentry/sentry-php/issues",
|
||||
"source": "https://github.com/getsentry/sentry-php/tree/4.8.0"
|
||||
"source": "https://github.com/getsentry/sentry-php/tree/4.8.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1167,7 +1395,7 @@
|
|||
"type": "custom"
|
||||
}
|
||||
],
|
||||
"time": "2024-06-05T13:18:43+00:00"
|
||||
"time": "2024-07-16T13:45:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
|
@ -1394,16 +1622,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/mailer",
|
||||
"version": "v6.4.8",
|
||||
"version": "v6.4.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/mailer.git",
|
||||
"reference": "76326421d44c07f7824b19487cfbf87870b37efc"
|
||||
"reference": "e2d56f180f5b8c5e7c0fbea872bb1f529b6d6d45"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/mailer/zipball/76326421d44c07f7824b19487cfbf87870b37efc",
|
||||
"reference": "76326421d44c07f7824b19487cfbf87870b37efc",
|
||||
"url": "https://api.github.com/repos/symfony/mailer/zipball/e2d56f180f5b8c5e7c0fbea872bb1f529b6d6d45",
|
||||
"reference": "e2d56f180f5b8c5e7c0fbea872bb1f529b6d6d45",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1454,7 +1682,7 @@
|
|||
"description": "Helps sending emails",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/mailer/tree/v6.4.8"
|
||||
"source": "https://github.com/symfony/mailer/tree/v6.4.9"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1470,20 +1698,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-05-31T14:49:08+00:00"
|
||||
"time": "2024-06-28T07:59:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/mime",
|
||||
"version": "v7.1.1",
|
||||
"version": "v7.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/mime.git",
|
||||
"reference": "21027eaacc1a8a20f5e616c25c3580f5dd3a15df"
|
||||
"reference": "26a00b85477e69a4bab63b66c5dce64f18b0cbfc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/mime/zipball/21027eaacc1a8a20f5e616c25c3580f5dd3a15df",
|
||||
"reference": "21027eaacc1a8a20f5e616c25c3580f5dd3a15df",
|
||||
"url": "https://api.github.com/repos/symfony/mime/zipball/26a00b85477e69a4bab63b66c5dce64f18b0cbfc",
|
||||
"reference": "26a00b85477e69a4bab63b66c5dce64f18b0cbfc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1538,7 +1766,7 @@
|
|||
"mime-type"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/mime/tree/v7.1.1"
|
||||
"source": "https://github.com/symfony/mime/tree/v7.1.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1554,7 +1782,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-06-04T06:40:14+00:00"
|
||||
"time": "2024-06-28T10:03:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/options-resolver",
|
||||
|
@ -1625,16 +1853,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.29.0",
|
||||
"version": "v1.30.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4"
|
||||
"reference": "0424dff1c58f028c451efff2045f5d92410bd540"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4",
|
||||
"reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540",
|
||||
"reference": "0424dff1c58f028c451efff2045f5d92410bd540",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1684,7 +1912,7 @@
|
|||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0"
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1700,20 +1928,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-01-29T20:11:03+00:00"
|
||||
"time": "2024-05-31T15:07:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-idn",
|
||||
"version": "v1.29.0",
|
||||
"version": "v1.30.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-idn.git",
|
||||
"reference": "a287ed7475f85bf6f61890146edbc932c0fff919"
|
||||
"reference": "a6e83bdeb3c84391d1dfe16f42e40727ce524a5c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/a287ed7475f85bf6f61890146edbc932c0fff919",
|
||||
"reference": "a287ed7475f85bf6f61890146edbc932c0fff919",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/a6e83bdeb3c84391d1dfe16f42e40727ce524a5c",
|
||||
"reference": "a6e83bdeb3c84391d1dfe16f42e40727ce524a5c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1768,7 +1996,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.29.0"
|
||||
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.30.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1784,20 +2012,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-01-29T20:11:03+00:00"
|
||||
"time": "2024-05-31T15:07:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-normalizer",
|
||||
"version": "v1.29.0",
|
||||
"version": "v1.30.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
|
||||
"reference": "bc45c394692b948b4d383a08d7753968bed9a83d"
|
||||
"reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d",
|
||||
"reference": "bc45c394692b948b4d383a08d7753968bed9a83d",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/a95281b0be0d9ab48050ebd988b967875cdb9fdb",
|
||||
"reference": "a95281b0be0d9ab48050ebd988b967875cdb9fdb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1849,7 +2077,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0"
|
||||
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.30.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1865,20 +2093,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-01-29T20:11:03+00:00"
|
||||
"time": "2024-05-31T15:07:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.29.0",
|
||||
"version": "v1.30.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec"
|
||||
"reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
|
||||
"reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c",
|
||||
"reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1929,7 +2157,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0"
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1945,20 +2173,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-01-29T20:11:03+00:00"
|
||||
"time": "2024-06-19T12:30:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php72",
|
||||
"version": "v1.29.0",
|
||||
"version": "v1.30.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php72.git",
|
||||
"reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25"
|
||||
"reference": "10112722600777e02d2745716b70c5db4ca70442"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/861391a8da9a04cbad2d232ddd9e4893220d6e25",
|
||||
"reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/10112722600777e02d2745716b70c5db4ca70442",
|
||||
"reference": "10112722600777e02d2745716b70c5db4ca70442",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2002,7 +2230,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php72/tree/v1.29.0"
|
||||
"source": "https://github.com/symfony/polyfill-php72/tree/v1.30.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -2018,20 +2246,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-01-29T20:11:03+00:00"
|
||||
"time": "2024-06-19T12:30:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php80",
|
||||
"version": "v1.29.0",
|
||||
"version": "v1.30.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php80.git",
|
||||
"reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b"
|
||||
"reference": "77fa7995ac1b21ab60769b7323d600a991a90433"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
|
||||
"reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/77fa7995ac1b21ab60769b7323d600a991a90433",
|
||||
"reference": "77fa7995ac1b21ab60769b7323d600a991a90433",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2082,7 +2310,7 @@
|
|||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0"
|
||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.30.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -2098,7 +2326,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-01-29T20:11:03+00:00"
|
||||
"time": "2024-05-31T15:07:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/service-contracts",
|
||||
|
@ -2334,16 +2562,16 @@
|
|||
"packages-dev": [
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.11.4",
|
||||
"version": "1.11.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "9100a76ce8015b9aa7125b9171ae3a76887b6c82"
|
||||
"reference": "52d2bbfdcae7f895915629e4694e9497d0f8e28d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/9100a76ce8015b9aa7125b9171ae3a76887b6c82",
|
||||
"reference": "9100a76ce8015b9aa7125b9171ae3a76887b6c82",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/52d2bbfdcae7f895915629e4694e9497d0f8e28d",
|
||||
"reference": "52d2bbfdcae7f895915629e4694e9497d0f8e28d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2388,7 +2616,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-06-06T12:19:22+00:00"
|
||||
"time": "2024-07-06T11:17:41+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
|
|
420
package-lock.json
generated
420
package-lock.json
generated
File diff suppressed because it is too large
Load diff
44
src/Jose/HmacJwsHandler.php
Normal file
44
src/Jose/HmacJwsHandler.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
namespace Hanyuu\Jose;
|
||||
|
||||
class HmacJwsHandler implements IJwsHandler {
|
||||
public const HS256 = 'HS256';
|
||||
public const HS384 = 'HS384';
|
||||
public const HS512 = 'HS512';
|
||||
|
||||
private const MAPPINGS = [
|
||||
self::HS256 => 'sha256',
|
||||
self::HS384 => 'sha384',
|
||||
self::HS512 => 'sha512',
|
||||
];
|
||||
|
||||
private string $realAlgo;
|
||||
private $getSecret;
|
||||
|
||||
public function __construct(
|
||||
private string $algo,
|
||||
callable $getSecret
|
||||
) {
|
||||
if(!array_key_exists($algo, self::MAPPINGS))
|
||||
throw new InvalidArgumentException('algorithm specified in $algo is not supported');
|
||||
|
||||
$this->realAlgo = self::MAPPINGS[$algo];
|
||||
$this->getSecret = $getSecret;
|
||||
}
|
||||
|
||||
public function getAlgorithm(): string {
|
||||
return $this->algo;
|
||||
}
|
||||
|
||||
public function match(object $header): bool {
|
||||
return $header->alg === $this->algo;
|
||||
}
|
||||
|
||||
public function sign(string $data): string {
|
||||
return hash_hmac($this->realAlgo, $data, ($this->getSecret)(), true);
|
||||
}
|
||||
|
||||
public function verify(string $data, string $userSignature): bool {
|
||||
return hash_equals($this->sign($data), $userSignature);
|
||||
}
|
||||
}
|
9
src/Jose/IJwsHandler.php
Normal file
9
src/Jose/IJwsHandler.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
namespace Hanyuu\Jose;
|
||||
|
||||
interface IJwsHandler {
|
||||
function getAlgorithm(): string;
|
||||
function match(object $header): bool; // alg is guaranteed to be present, you may make assumptions
|
||||
function sign(string $data): string;
|
||||
function verify(string $data, string $userSignature): bool;
|
||||
}
|
69
src/Jose/Jws.php
Normal file
69
src/Jose/Jws.php
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
namespace Hanyuu\Jose;
|
||||
|
||||
final class Jws {
|
||||
private static function hmac(string $algo, callable|string $secret): IJwsHandler {
|
||||
if(is_string($secret))
|
||||
$secret = fn() => $secret;
|
||||
|
||||
return new HmacJwsHandler($algo, $secret);
|
||||
}
|
||||
|
||||
public static function hs256(callable|string $secret): IJwsHandler {
|
||||
return self::hmac(HmacJwsHandler::HS256, $secret);
|
||||
}
|
||||
public static function hs384(callable|string $secret): IJwsHandler {
|
||||
return self::hmac(HmacJwsHandler::HS384, $secret);
|
||||
}
|
||||
public static function hs512(callable|string $secret): IJwsHandler {
|
||||
return self::hmac(HmacJwsHandler::HS512, $secret);
|
||||
}
|
||||
|
||||
private static function openSsl(string $algo, callable|string $privateKey, callable|string $publicKey): IJwsHandler {
|
||||
if(is_string($privateKey))
|
||||
$privateKey = fn() => $privateKey;
|
||||
if(is_string($publicKey))
|
||||
$publicKey = fn() => $publicKey;
|
||||
|
||||
return new OpenSslJwsHandler($algo, $privateKey, $publicKey);
|
||||
}
|
||||
|
||||
public static function rs256(callable|string $privateKey, callable|string $publicKey): IJwsHandler {
|
||||
return self::openSsl(OpenSslJwsHandler::RS256, $privateKey, $publicKey);
|
||||
}
|
||||
public static function rs384(callable|string $privateKey, callable|string $publicKey): IJwsHandler {
|
||||
return self::openSsl(OpenSslJwsHandler::RS384, $privateKey, $publicKey);
|
||||
}
|
||||
public static function rs512(callable|string $privateKey, callable|string $publicKey): IJwsHandler {
|
||||
return self::openSsl(OpenSslJwsHandler::RS512, $privateKey, $publicKey);
|
||||
}
|
||||
|
||||
public static function es256(callable|string $privateKey, callable|string $publicKey): IJwsHandler {
|
||||
return self::openSsl(OpenSslJwsHandler::ES256, $privateKey, $publicKey);
|
||||
}
|
||||
public static function es384(callable|string $privateKey, callable|string $publicKey): IJwsHandler {
|
||||
return self::openSsl(OpenSslJwsHandler::ES384, $privateKey, $publicKey);
|
||||
}
|
||||
public static function es512(callable|string $privateKey, callable|string $publicKey): IJwsHandler {
|
||||
return self::openSsl(OpenSslJwsHandler::ES512, $privateKey, $publicKey);
|
||||
}
|
||||
|
||||
private static function phpSecLib(string $algo, callable|string $privateKey, callable|string $publicKey): IJwsHandler {
|
||||
if(is_string($privateKey))
|
||||
$privateKey = fn() => $privateKey;
|
||||
if(is_string($publicKey))
|
||||
$publicKey = fn() => $publicKey;
|
||||
|
||||
return new PhpSecLibJwsHandler($algo, $privateKey, $publicKey);
|
||||
}
|
||||
|
||||
public static function ps256(callable|string $privateKey, callable|string $publicKey): IJwsHandler {
|
||||
return self::phpSecLib(PhpSecLibJwsHandler::PS256, $privateKey, $publicKey);
|
||||
}
|
||||
public static function ps384(callable|string $privateKey, callable|string $publicKey): IJwsHandler {
|
||||
return self::phpSecLib(PhpSecLibJwsHandler::PS384, $privateKey, $publicKey);
|
||||
}
|
||||
public static function ps512(callable|string $privateKey, callable|string $publicKey): IJwsHandler {
|
||||
return self::phpSecLib(PhpSecLibJwsHandler::PS512, $privateKey, $publicKey);
|
||||
}
|
||||
}
|
44
src/Jose/JwsHandlers.php
Normal file
44
src/Jose/JwsHandlers.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
namespace Hanyuu\Jose;
|
||||
|
||||
class JwsHandlers {
|
||||
private array $handlers = [];
|
||||
|
||||
public function register(IJwsHandler $handler): void {
|
||||
$this->handlers[] = $handler;
|
||||
}
|
||||
|
||||
public function clear(): void {
|
||||
$this->handlers = [];
|
||||
}
|
||||
|
||||
public function getFirstAlgorithm(): ?IJwsHandler {
|
||||
return empty($this->handlers) ? null : $this->handlers[0];
|
||||
}
|
||||
|
||||
public function getOneByAlgorithm(string $name): ?IJwsHandler {
|
||||
foreach($this->handlers as $handler)
|
||||
if($handler->getAlgorithm() === $name)
|
||||
return $handler;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function match(object $header): array {
|
||||
$handlers = [];
|
||||
|
||||
foreach($this->handlers as $handler)
|
||||
if($handler->match($header))
|
||||
$handlers[] = $handler;
|
||||
|
||||
return $handlers;
|
||||
}
|
||||
|
||||
public function verify(object $header, string $data, string $userHash): bool {
|
||||
foreach($this->handlers as $handler)
|
||||
if($handler->match($header) && $handler->verify($data, $userHash))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
139
src/Jose/JwtHandler.php
Normal file
139
src/Jose/JwtHandler.php
Normal file
|
@ -0,0 +1,139 @@
|
|||
<?php
|
||||
namespace Hanyuu\Jose;
|
||||
|
||||
use stdClass;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use Index\Serialisation\UriBase64;
|
||||
|
||||
class JwtHandler {
|
||||
private JwsHandlers $jwsHandlers;
|
||||
|
||||
public function __construct() {
|
||||
$this->jwsHandlers = new JwsHandlers;
|
||||
}
|
||||
|
||||
public function getJwsHandlers(): JwsHandlers {
|
||||
return $this->jwsHandlers;
|
||||
}
|
||||
|
||||
public function registerJwsHandler(IJwsHandler $handler): void {
|
||||
$this->jwsHandlers->register($handler);
|
||||
}
|
||||
|
||||
public function encoded(
|
||||
mixed $payload,
|
||||
object|array|null $header = null,
|
||||
bool $payloadToJson = true
|
||||
): string {
|
||||
if(!is_object($header)) {
|
||||
if(is_array($header))
|
||||
$header = (object)$header;
|
||||
else
|
||||
$header = new stdClass;
|
||||
}
|
||||
|
||||
$header->alg = 'none';
|
||||
|
||||
$header = UriBase64::encode(json_encode($header, JSON_UNESCAPED_UNICODE));
|
||||
$payload = UriBase64::encode($payloadToJson ? json_encode($payload, JSON_UNESCAPED_UNICODE) : (string)$payload);
|
||||
|
||||
return "{$header}.{$payload}.";
|
||||
}
|
||||
|
||||
public function signed(
|
||||
mixed $payload,
|
||||
object|array|null $header = null,
|
||||
bool $payloadToJson = true,
|
||||
string|IJwsHandler|null $handler = null
|
||||
): string {
|
||||
if(!is_object($header)) {
|
||||
if(is_array($header))
|
||||
$header = (object)$header;
|
||||
else
|
||||
$header = new stdClass;
|
||||
}
|
||||
|
||||
if($handler === null)
|
||||
$handler = $this->jwsHandlers->getFirstAlgorithm();
|
||||
elseif(is_string($handler))
|
||||
$handler = $this->jwsHandlers->getOneByAlgorithm($handler);
|
||||
|
||||
if($handler === null)
|
||||
throw new InvalidArgumentException('no JWS handler is associated with the algorithm specified in $handler');
|
||||
|
||||
$header->alg = $handler->getAlgorithm();
|
||||
$header->typ = 'JWT';
|
||||
|
||||
$header = UriBase64::encode(json_encode($header, JSON_UNESCAPED_UNICODE));
|
||||
$payload = UriBase64::encode($payloadToJson ? json_encode($payload, JSON_UNESCAPED_UNICODE) : (string)$payload);
|
||||
|
||||
$token = "{$header}.{$payload}";
|
||||
$signature = UriBase64::encode($handler->sign($token));
|
||||
|
||||
return "{$token}.{$signature}";
|
||||
}
|
||||
|
||||
public function decodeStrict(string $token, bool $verify = true): object {
|
||||
if(strpos($token, '.') === false)
|
||||
throw new InvalidArgumentException('$token is not a JWT');
|
||||
|
||||
$parts = explode('.', $token);
|
||||
foreach($parts as $key => $value)
|
||||
$parts[$key] = trim($value);
|
||||
|
||||
$header = json_decode(UriBase64::decode($parts[0]));
|
||||
if(!is_object($header))
|
||||
throw new InvalidArgumentException('unable to decode header field of $token');
|
||||
if(!isset($header->alg) || !is_string($header->alg))
|
||||
throw new InvalidArgumentException('alg claim missing from header in $token');
|
||||
|
||||
$tokenParts = count($parts);
|
||||
if($tokenParts === 5)
|
||||
$type = 'enc';
|
||||
elseif($tokenParts === 3)
|
||||
$type = $parts[2] === '' ? 'raw' : 'sig';
|
||||
elseif($tokenParts === 2) // should this be supported? the spec is at least a little clear about the trailing dot
|
||||
$type = 'raw';
|
||||
else
|
||||
throw new InvalidArgumentException('$token does not contain a supported amount of segments');
|
||||
|
||||
$info = new stdClass;
|
||||
$info->success = true;
|
||||
$info->type = $type;
|
||||
$info->header = $header;
|
||||
|
||||
if($type === 'sig') {
|
||||
if($verify && !$this->jwsHandlers->verify($header, "{$parts[0]}.{$parts[1]}", UriBase64::decode($parts[2])))
|
||||
throw new InvalidArgumentException('could not verify signature of $token');
|
||||
|
||||
$info->payload = UriBase64::decode($parts[1]);
|
||||
} elseif($type === 'enc') {
|
||||
$info->success = false;
|
||||
} elseif($type === 'raw') {
|
||||
if($verify && $header->alg !== 'none')
|
||||
throw new InvalidArgumentException('format of $token indicates that it should be an unsecured JWT, but "alg" is not set to "none"');
|
||||
|
||||
$info->payload = UriBase64::decode($parts[1]);
|
||||
}
|
||||
|
||||
if(isset($info->payload)) {
|
||||
$decoded = json_decode($info->payload);
|
||||
if($decoded !== null)
|
||||
$info->payload = $decoded;
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
public function decode(string $token, bool $verify = true): object {
|
||||
try {
|
||||
return $this->decodeStrict($token, $verify);
|
||||
} catch(InvalidArgumentException $ex) {
|
||||
$info = new stdClass;
|
||||
$info->success = false;
|
||||
$info->message = $ex->getMessage();
|
||||
return $info;
|
||||
}
|
||||
}
|
||||
}
|
110
src/Jose/OpenSslJwsHandler.php
Normal file
110
src/Jose/OpenSslJwsHandler.php
Normal file
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
namespace Hanyuu\Jose;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use OpenSSLAsymmetricKey;
|
||||
use RuntimeException;
|
||||
|
||||
class OpenSslJwsHandler implements IJwsHandler {
|
||||
public const RS256 = 'RS256';
|
||||
public const RS384 = 'RS384';
|
||||
public const RS512 = 'RS512';
|
||||
|
||||
public const ES256 = 'ES256';
|
||||
public const ES384 = 'ES384';
|
||||
public const ES512 = 'ES512';
|
||||
|
||||
private const OPENSSL_HASH_ALGO = [
|
||||
self::RS256 => OPENSSL_ALGO_SHA256,
|
||||
self::RS384 => OPENSSL_ALGO_SHA384,
|
||||
self::RS512 => OPENSSL_ALGO_SHA512,
|
||||
|
||||
self::ES256 => OPENSSL_ALGO_SHA256,
|
||||
self::ES384 => OPENSSL_ALGO_SHA384,
|
||||
self::ES512 => OPENSSL_ALGO_SHA512,
|
||||
];
|
||||
|
||||
private const OPENSSL_KEY_INFO = [
|
||||
self::RS256 => ['type' => OPENSSL_KEYTYPE_RSA],
|
||||
self::RS384 => ['type' => OPENSSL_KEYTYPE_RSA],
|
||||
self::RS512 => ['type' => OPENSSL_KEYTYPE_RSA],
|
||||
|
||||
self::ES256 => ['type' => OPENSSL_KEYTYPE_EC, 'bits' => 256],
|
||||
self::ES384 => ['type' => OPENSSL_KEYTYPE_EC, 'bits' => 384],
|
||||
self::ES512 => ['type' => OPENSSL_KEYTYPE_EC, 'bits' => 521],
|
||||
];
|
||||
|
||||
private $opensslHashAlgo;
|
||||
private $getPrivateKey;
|
||||
private $getPublicKey;
|
||||
|
||||
public function __construct(
|
||||
private string $algo,
|
||||
?callable $getPrivateKey,
|
||||
?callable $getPublicKey
|
||||
) {
|
||||
if(!array_key_exists($algo, self::OPENSSL_HASH_ALGO))
|
||||
throw new InvalidArgumentException('algorithm specified in $algo is not supported');
|
||||
|
||||
$this->opensslHashAlgo = self::OPENSSL_HASH_ALGO[$algo];
|
||||
$this->getPrivateKey = $getPrivateKey;
|
||||
$this->getPublicKey = $getPublicKey;
|
||||
}
|
||||
|
||||
public function getAlgorithm(): string {
|
||||
return $this->algo;
|
||||
}
|
||||
|
||||
public function match(object $header): bool {
|
||||
return $header->alg === $this->algo;
|
||||
}
|
||||
|
||||
private function ensureValidKey(OpenSSLAsymmetricKey $key): void {
|
||||
if(!array_key_exists($this->algo, self::OPENSSL_KEY_INFO))
|
||||
throw new RuntimeException('missing key requirements for selected algorithm');
|
||||
|
||||
$require = self::OPENSSL_KEY_INFO[$this->algo];
|
||||
$details = openssl_pkey_get_details($key);
|
||||
|
||||
foreach($require as $key => $value)
|
||||
if($details[$key] !== $value)
|
||||
throw new RuntimeException('provided asymmetric key is not suitable for this algorithm');
|
||||
}
|
||||
|
||||
public function sign(string $data): string {
|
||||
$privateKey = $this->getPrivateKey;
|
||||
if($privateKey !== null)
|
||||
$privateKey = ($privateKey)();
|
||||
if($privateKey === null)
|
||||
throw new RuntimeException('no private key available for signing');
|
||||
|
||||
if(is_string($privateKey))
|
||||
$privateKey = openssl_pkey_get_private($privateKey);
|
||||
$this->ensureValidKey($privateKey);
|
||||
|
||||
if(!openssl_sign($data, $signature, $privateKey, $this->opensslHashAlgo))
|
||||
throw new RuntimeException((string)openssl_error_string());
|
||||
|
||||
return $signature;
|
||||
}
|
||||
|
||||
public function verify(string $data, string $userSignature): bool {
|
||||
$publicKey = $this->getPublicKey;
|
||||
if($publicKey !== null)
|
||||
$publicKey = ($publicKey)();
|
||||
if($publicKey === null)
|
||||
throw new RuntimeException('no public key available for verification');
|
||||
|
||||
if(is_string($publicKey))
|
||||
$publicKey = openssl_pkey_get_public($publicKey);
|
||||
$this->ensureValidKey($publicKey);
|
||||
|
||||
$result = openssl_verify($data, $userSignature, $publicKey, $this->opensslHashAlgo);
|
||||
if($result === 1)
|
||||
return true;
|
||||
if($result === 0)
|
||||
return false;
|
||||
|
||||
throw new RuntimeException((string)openssl_error_string());
|
||||
}
|
||||
}
|
73
src/Jose/PhpSecLibJwsHandler.php
Normal file
73
src/Jose/PhpSecLibJwsHandler.php
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
namespace Hanyuu\Jose;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use phpseclib3\Crypt\RSA;
|
||||
|
||||
class PhpSecLibJwsHandler implements IJwsHandler {
|
||||
public const PS256 = 'PS256';
|
||||
public const PS384 = 'PS384';
|
||||
public const PS512 = 'PS512';
|
||||
|
||||
private const PHPSECLIB_HASH_ALGOS = [
|
||||
self::PS256 => 'sha256',
|
||||
self::PS384 => 'sha384',
|
||||
self::PS512 => 'sha512',
|
||||
];
|
||||
|
||||
private $phpSecLibHashAlgo;
|
||||
private $getPrivateKey;
|
||||
private $getPublicKey;
|
||||
|
||||
public function __construct(
|
||||
private string $algo,
|
||||
?callable $getPrivateKey,
|
||||
?callable $getPublicKey
|
||||
) {
|
||||
if(!array_key_exists($algo, self::PHPSECLIB_HASH_ALGOS))
|
||||
throw new InvalidArgumentException('algorithm specified in $algo is not supported');
|
||||
|
||||
$this->phpSecLibHashAlgo = self::PHPSECLIB_HASH_ALGOS[$algo];
|
||||
$this->getPrivateKey = $getPrivateKey;
|
||||
$this->getPublicKey = $getPublicKey;
|
||||
}
|
||||
|
||||
public function getAlgorithm(): string {
|
||||
return $this->algo;
|
||||
}
|
||||
|
||||
public function match(object $header): bool {
|
||||
return $header->alg === $this->algo;
|
||||
}
|
||||
|
||||
public function sign(string $data): string {
|
||||
$privateKey = $this->getPrivateKey;
|
||||
if($privateKey !== null)
|
||||
$privateKey = ($privateKey)();
|
||||
if($privateKey === null)
|
||||
throw new RuntimeException('no private key available for signing');
|
||||
|
||||
$privateKey = RSA::load($privateKey);
|
||||
$privateKey->withPadding(RSA::SIGNATURE_PSS);
|
||||
$privateKey->withHash($this->phpSecLibHashAlgo);
|
||||
$privateKey->withMGFHash($this->phpSecLibHashAlgo);
|
||||
|
||||
return $privateKey->sign($data);
|
||||
}
|
||||
|
||||
public function verify(string $data, string $userSignature): bool {
|
||||
$publicKey = $this->getPublicKey;
|
||||
if($publicKey !== null)
|
||||
$publicKey = ($publicKey)();
|
||||
if($publicKey === null)
|
||||
throw new RuntimeException('no public key available for verification');
|
||||
|
||||
$publicKey = RSA::load($publicKey);
|
||||
$publicKey->withPadding(RSA::SIGNATURE_PSS);
|
||||
$publicKey->withHash($this->phpSecLibHashAlgo);
|
||||
$publicKey->withMGFHash($this->phpSecLibHashAlgo);
|
||||
|
||||
return $publicKey->verify($data, $userSignature);
|
||||
}
|
||||
}
|
Reference in a new issue