From 9637c2dff6aba6a8a2a1f51ed43651cab22ae477 Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Sun, 24 Nov 2019 09:45:57 +0100 Subject: [PATCH] webauthn --- lam-packaging/debian/copyright | 87 +- lam/composer.lock | 901 ++++++ lam/copyright | 87 +- lam/lib/3rdParty/composer/autoload.php | 7 + .../3rdParty/composer/beberlei/assert/LICENSE | 11 + .../composer/beberlei/assert/composer.json | 63 + .../beberlei/assert/lib/Assert/Assert.php | 96 + .../beberlei/assert/lib/Assert/Assertion.php | 2825 +++++++++++++++++ .../assert/lib/Assert/AssertionChain.php | 254 ++ .../lib/Assert/AssertionFailedException.php | 35 + .../lib/Assert/InvalidArgumentException.php | 76 + .../assert/lib/Assert/LazyAssertion.php | 230 ++ .../lib/Assert/LazyAssertionException.php | 55 + .../beberlei/assert/lib/Assert/functions.php | 80 + .../beberlei/assert/phpstan-code.neon | 10 + .../beberlei/assert/phpstan-tests.neon | 10 + .../composer/composer/ClassLoader.php | 445 +++ lam/lib/3rdParty/composer/composer/LICENSE | 56 + .../composer/composer/autoload_classmap.php | 9 + .../composer/composer/autoload_files.php | 11 + .../composer/composer/autoload_namespaces.php | 9 + .../composer/composer/autoload_psr4.php | 22 + .../composer/composer/autoload_real.php | 70 + .../composer/composer/autoload_static.php | 124 + .../3rdParty/composer/composer/installed.json | 915 ++++++ .../composer/fgrosse/phpasn1/CHANGELOG.md | 38 + .../3rdParty/composer/fgrosse/phpasn1/LICENSE | 19 + .../composer/fgrosse/phpasn1/README.md | 167 + .../composer/fgrosse/phpasn1/composer.json | 47 + .../fgrosse/phpasn1/lib/ASN1/ASNObject.php | 355 +++ .../phpasn1/lib/ASN1/AbstractString.php | 136 + .../fgrosse/phpasn1/lib/ASN1/AbstractTime.php | 78 + .../fgrosse/phpasn1/lib/ASN1/Base128.php | 63 + .../ASN1/Composite/AttributeTypeAndValue.php | 35 + .../phpasn1/lib/ASN1/Composite/RDNString.php | 37 + .../Composite/RelativeDistinguishedName.php | 50 + .../fgrosse/phpasn1/lib/ASN1/Construct.php | 191 ++ .../Exception/NotImplementedException.php | 15 + .../lib/ASN1/Exception/ParserException.php | 29 + .../lib/ASN1/ExplicitlyTaggedObject.php | 131 + .../fgrosse/phpasn1/lib/ASN1/Identifier.php | 339 ++ .../composer/fgrosse/phpasn1/lib/ASN1/OID.php | 198 ++ .../fgrosse/phpasn1/lib/ASN1/Parsable.php | 32 + .../phpasn1/lib/ASN1/TemplateParser.php | 70 + .../phpasn1/lib/ASN1/Universal/BMPString.php | 41 + .../phpasn1/lib/ASN1/Universal/BitString.php | 88 + .../phpasn1/lib/ASN1/Universal/Boolean.php | 75 + .../lib/ASN1/Universal/CharacterString.php | 28 + .../phpasn1/lib/ASN1/Universal/Enumerated.php | 21 + .../lib/ASN1/Universal/GeneralString.php | 34 + .../lib/ASN1/Universal/GeneralizedTime.php | 134 + .../lib/ASN1/Universal/GraphicString.php | 34 + .../phpasn1/lib/ASN1/Universal/IA5String.php | 35 + .../phpasn1/lib/ASN1/Universal/Integer.php | 130 + .../phpasn1/lib/ASN1/Universal/NullObject.php | 54 + .../lib/ASN1/Universal/NumericString.php | 38 + .../lib/ASN1/Universal/ObjectDescriptor.php | 26 + .../lib/ASN1/Universal/ObjectIdentifier.php | 138 + .../lib/ASN1/Universal/OctetString.php | 91 + .../lib/ASN1/Universal/PrintableString.php | 53 + .../Universal/RelativeObjectIdentifier.php | 57 + .../phpasn1/lib/ASN1/Universal/Sequence.php | 23 + .../phpasn1/lib/ASN1/Universal/Set.php | 21 + .../phpasn1/lib/ASN1/Universal/T61String.php | 36 + .../phpasn1/lib/ASN1/Universal/UTCTime.php | 77 + .../phpasn1/lib/ASN1/Universal/UTF8String.php | 34 + .../lib/ASN1/Universal/UniversalString.php | 36 + .../lib/ASN1/Universal/VisibleString.php | 34 + .../lib/ASN1/UnknownConstructedObject.php | 59 + .../phpasn1/lib/ASN1/UnknownObject.php | 59 + .../phpasn1/lib/Utility/BigInteger.php | 197 ++ .../phpasn1/lib/Utility/BigIntegerBcmath.php | 133 + .../phpasn1/lib/Utility/BigIntegerGmp.php | 133 + .../phpasn1/lib/X509/AlgorithmIdentifier.php | 22 + .../phpasn1/lib/X509/CSR/Attributes.php | 68 + .../fgrosse/phpasn1/lib/X509/CSR/CSR.php | 137 + .../lib/X509/CertificateExtensions.php | 100 + .../phpasn1/lib/X509/CertificateSubject.php | 108 + .../fgrosse/phpasn1/lib/X509/PrivateKey.php | 35 + .../fgrosse/phpasn1/lib/X509/PublicKey.php | 35 + .../fgrosse/phpasn1/lib/X509/SAN/DNSName.php | 28 + .../phpasn1/lib/X509/SAN/IPAddress.php | 73 + .../lib/X509/SAN/SubjectAlternativeNames.php | 96 + .../composer/nyholm/psr7/CHANGELOG.md | 85 + lam/lib/3rdParty/composer/nyholm/psr7/LICENSE | 21 + .../3rdParty/composer/nyholm/psr7/README.md | 111 + .../composer/nyholm/psr7/composer.json | 51 + .../psr7/src/Factory/HttplugFactory.php | 40 + .../nyholm/psr7/src/Factory/Psr17Factory.php | 73 + .../composer/nyholm/psr7/src/MessageTrait.php | 202 ++ .../composer/nyholm/psr7/src/Request.php | 45 + .../composer/nyholm/psr7/src/RequestTrait.php | 113 + .../composer/nyholm/psr7/src/Response.php | 88 + .../nyholm/psr7/src/ServerRequest.php | 162 + .../composer/nyholm/psr7/src/Stream.php | 257 ++ .../composer/nyholm/psr7/src/UploadedFile.php | 171 + .../3rdParty/composer/nyholm/psr7/src/Uri.php | 310 ++ .../composer/paragonie/random_compat/LICENSE | 22 + .../paragonie/random_compat/build-phar.sh | 5 + .../paragonie/random_compat/composer.json | 34 + .../dist/random_compat.phar.pubkey | 5 + .../dist/random_compat.phar.pubkey.asc | 11 + .../paragonie/random_compat/lib/random.php | 32 + .../random_compat/other/build_phar.php | 57 + .../random_compat/psalm-autoload.php | 9 + .../paragonie/random_compat/psalm.xml | 19 + .../php-http/message-factory/CHANGELOG.md | 65 + .../composer/php-http/message-factory/LICENSE | 19 + .../php-http/message-factory/README.md | 36 + .../php-http/message-factory/composer.json | 27 + .../php-http/message-factory/puli.json | 43 + .../message-factory/src/MessageFactory.php | 12 + .../message-factory/src/RequestFactory.php | 34 + .../message-factory/src/ResponseFactory.php | 35 + .../message-factory/src/StreamFactory.php | 25 + .../message-factory/src/UriFactory.php | 24 + .../composer/psr/http-client/CHANGELOG.md | 19 + .../3rdParty/composer/psr/http-client/LICENSE | 19 + .../composer/psr/http-client/README.md | 14 + .../composer/psr/http-client/composer.json | 27 + .../src/ClientExceptionInterface.php | 10 + .../psr/http-client/src/ClientInterface.php | 20 + .../src/NetworkExceptionInterface.php | 24 + .../src/RequestExceptionInterface.php | 24 + .../composer/psr/http-factory/.gitignore | 2 + .../psr/http-factory/.pullapprove.yml | 7 + .../composer/psr/http-factory/LICENSE | 21 + .../composer/psr/http-factory/README.md | 10 + .../composer/psr/http-factory/composer.json | 35 + .../src/RequestFactoryInterface.php | 18 + .../src/ResponseFactoryInterface.php | 18 + .../src/ServerRequestFactoryInterface.php | 24 + .../src/StreamFactoryInterface.php | 45 + .../src/UploadedFileFactoryInterface.php | 34 + .../http-factory/src/UriFactoryInterface.php | 17 + .../composer/psr/http-message/CHANGELOG.md | 36 + .../composer/psr/http-message/LICENSE | 19 + .../composer/psr/http-message/README.md | 13 + .../composer/psr/http-message/composer.json | 26 + .../psr/http-message/src/MessageInterface.php | 187 ++ .../psr/http-message/src/RequestInterface.php | 129 + .../http-message/src/ResponseInterface.php | 68 + .../src/ServerRequestInterface.php | 261 ++ .../psr/http-message/src/StreamInterface.php | 158 + .../src/UploadedFileInterface.php | 123 + .../psr/http-message/src/UriInterface.php | 323 ++ .../composer/ramsey/uuid/CHANGELOG.md | 376 +++ .../composer/ramsey/uuid/CODE_OF_CONDUCT.md | 74 + .../composer/ramsey/uuid/CONTRIBUTING.md | 75 + lam/lib/3rdParty/composer/ramsey/uuid/LICENSE | 19 + .../3rdParty/composer/ramsey/uuid/README.md | 159 + .../composer/ramsey/uuid/composer.json | 80 + .../composer/ramsey/uuid/src/BinaryUtils.php | 43 + .../uuid/src/Builder/DefaultUuidBuilder.php | 54 + .../uuid/src/Builder/DegradedUuidBuilder.php | 53 + .../uuid/src/Builder/UuidBuilderInterface.php | 34 + .../ramsey/uuid/src/Codec/CodecInterface.php | 58 + .../ramsey/uuid/src/Codec/GuidStringCodec.php | 102 + .../uuid/src/Codec/OrderedTimeCodec.php | 68 + .../ramsey/uuid/src/Codec/StringCodec.php | 170 + .../src/Codec/TimestampFirstCombCodec.php | 107 + .../uuid/src/Codec/TimestampLastCombCodec.php | 23 + .../Converter/Number/BigNumberConverter.php | 54 + .../Number/DegradedNumberConverter.php | 58 + .../Converter/NumberConverterInterface.php | 46 + .../Converter/Time/BigNumberTimeConverter.php | 58 + .../Converter/Time/DegradedTimeConverter.php | 42 + .../src/Converter/Time/PhpTimeConverter.php | 47 + .../src/Converter/TimeConverterInterface.php | 35 + .../composer/ramsey/uuid/src/DegradedUuid.php | 114 + .../Exception/InvalidUuidStringException.php | 22 + .../UnsatisfiedDependencyException.php | 23 + .../UnsupportedOperationException.php | 22 + .../composer/ramsey/uuid/src/FeatureSet.php | 333 ++ .../uuid/src/Generator/CombGenerator.php | 88 + .../src/Generator/DefaultTimeGenerator.php | 138 + .../uuid/src/Generator/MtRandGenerator.php | 41 + .../uuid/src/Generator/OpenSslGenerator.php | 38 + .../src/Generator/PeclUuidRandomGenerator.php | 37 + .../src/Generator/PeclUuidTimeGenerator.php | 38 + .../src/Generator/RandomBytesGenerator.php | 37 + .../src/Generator/RandomGeneratorFactory.php | 31 + .../Generator/RandomGeneratorInterface.php | 33 + .../uuid/src/Generator/RandomLibAdapter.php | 62 + .../src/Generator/SodiumRandomGenerator.php | 36 + .../src/Generator/TimeGeneratorFactory.php | 72 + .../src/Generator/TimeGeneratorInterface.php | 39 + .../Provider/Node/FallbackNodeProvider.php | 58 + .../src/Provider/Node/RandomNodeProvider.php | 42 + .../src/Provider/Node/SystemNodeProvider.php | 125 + .../src/Provider/NodeProviderInterface.php | 30 + .../src/Provider/Time/FixedTimeProvider.php | 76 + .../src/Provider/Time/SystemTimeProvider.php | 33 + .../src/Provider/TimeProviderInterface.php | 29 + .../composer/ramsey/uuid/src/Uuid.php | 740 +++++ .../composer/ramsey/uuid/src/UuidFactory.php | 314 ++ .../ramsey/uuid/src/UuidFactoryInterface.php | 103 + .../ramsey/uuid/src/UuidInterface.php | 270 ++ .../spomky-labs/base64url/.php_cs.dist | 61 + .../composer/spomky-labs/base64url/LICENSE | 22 + .../spomky-labs/base64url/composer.json | 31 + .../spomky-labs/base64url/src/Base64Url.php | 50 + .../cbor-php/.github/CONTRIBUTING.md | 25 + .../spomky-labs/cbor-php/.github/FUNDING.yml | 1 + .../cbor-php/.github/ISSUE_TEMPLATE.md | 16 + .../cbor-php/.github/PULL_REQUEST_TEMPLATE.md | 17 + .../spomky-labs/cbor-php/.php_cs.dist | 61 + .../spomky-labs/cbor-php/CODE_OF_CONDUCT.md | 46 + .../composer/spomky-labs/cbor-php/LICENSE | 21 + .../spomky-labs/cbor-php/composer.json | 50 + .../spomky-labs/cbor-php/infection.json.dist | 11 + .../spomky-labs/cbor-php/phpstan.neon | 11 + .../cbor-php/src/AbstractCBORObject.php | 48 + .../cbor-php/src/ByteStringObject.php | 64 + .../src/ByteStringWithChunkObject.php | 87 + .../spomky-labs/cbor-php/src/CBORObject.php | 28 + .../spomky-labs/cbor-php/src/Decoder.php | 159 + .../cbor-php/src/InfiniteListObject.php | 69 + .../cbor-php/src/InfiniteMapObject.php | 73 + .../cbor-php/src/LengthCalculator.php | 66 + .../spomky-labs/cbor-php/src/ListObject.php | 93 + .../spomky-labs/cbor-php/src/MapItem.php | 43 + .../spomky-labs/cbor-php/src/MapObject.php | 88 + .../spomky-labs/cbor-php/src/OtherObject.php | 47 + .../cbor-php/src/OtherObject/BreakObject.php | 39 + .../DoublePrecisionFloatObject.php | 100 + .../cbor-php/src/OtherObject/FalseObject.php | 39 + .../src/OtherObject/GenericObject.php | 34 + .../OtherObject/HalfPrecisionFloatObject.php | 89 + .../cbor-php/src/OtherObject/NullObject.php | 38 + .../src/OtherObject/OtherObjectManager.php | 48 + .../cbor-php/src/OtherObject/SimpleObject.php | 54 + .../SinglePrecisionFloatObject.php | 89 + .../cbor-php/src/OtherObject/TrueObject.php | 39 + .../src/OtherObject/UndefinedObject.php | 39 + .../cbor-php/src/SignedIntegerObject.php | 113 + .../spomky-labs/cbor-php/src/Stream.php | 19 + .../spomky-labs/cbor-php/src/StringStream.php | 58 + .../cbor-php/src/Tag/Base16EncodingTag.php | 57 + .../cbor-php/src/Tag/Base64EncodingTag.php | 62 + .../cbor-php/src/Tag/Base64UrlEncodingTag.php | 58 + .../cbor-php/src/Tag/BigFloatTag.php | 100 + .../cbor-php/src/Tag/DecimalFractionTag.php | 95 + .../spomky-labs/cbor-php/src/Tag/EpochTag.php | 44 + .../cbor-php/src/Tag/GenericTag.php | 35 + .../src/Tag/NegativeBigIntegerTag.php | 56 + .../src/Tag/PositiveBigIntegerTag.php | 54 + .../cbor-php/src/Tag/TagObjectManager.php | 53 + .../cbor-php/src/Tag/TimestampTag.php | 61 + .../spomky-labs/cbor-php/src/TagObject.php | 56 + .../cbor-php/src/TextStringObject.php | 64 + .../src/TextStringWithChunkObject.php | 87 + .../cbor-php/src/UnsignedIntegerObject.php | 116 + .../composer/symfony/polyfill-ctype/Ctype.php | 227 ++ .../composer/symfony/polyfill-ctype/LICENSE | 19 + .../composer/symfony/polyfill-ctype/README.md | 12 + .../symfony/polyfill-ctype/bootstrap.php | 26 + .../symfony/polyfill-ctype/composer.json | 34 + .../composer/web-auth/cose-lib/LICENSE | 21 + .../composer/web-auth/cose-lib/README.md | 31 + .../composer/web-auth/cose-lib/composer.json | 45 + .../cose-lib/src/Algorithm/Algorithm.php | 19 + .../cose-lib/src/Algorithm/Mac/HS256.php | 34 + .../src/Algorithm/Mac/HS256Truncated64.php | 34 + .../cose-lib/src/Algorithm/Mac/HS384.php | 34 + .../cose-lib/src/Algorithm/Mac/HS512.php | 34 + .../cose-lib/src/Algorithm/Mac/Hmac.php | 43 + .../cose-lib/src/Algorithm/Mac/Mac.php | 24 + .../cose-lib/src/Algorithm/Manager.php | 63 + .../cose-lib/src/Algorithm/ManagerFactory.php | 50 + .../src/Algorithm/Signature/ECDSA/ECDSA.php | 58 + .../Algorithm/Signature/ECDSA/ECSignature.php | 133 + .../src/Algorithm/Signature/ECDSA/ES256.php | 60 + .../src/Algorithm/Signature/ECDSA/ES256K.php | 60 + .../src/Algorithm/Signature/ECDSA/ES384.php | 60 + .../src/Algorithm/Signature/ECDSA/ES512.php | 60 + .../src/Algorithm/Signature/EdDSA/ED256.php | 40 + .../src/Algorithm/Signature/EdDSA/ED512.php | 40 + .../src/Algorithm/Signature/EdDSA/Ed25519.php | 24 + .../src/Algorithm/Signature/EdDSA/EdDSA.php | 65 + .../src/Algorithm/Signature/RSA/PS256.php | 31 + .../src/Algorithm/Signature/RSA/PS384.php | 31 + .../src/Algorithm/Signature/RSA/PS512.php | 31 + .../src/Algorithm/Signature/RSA/PSSRSA.php | 182 ++ .../src/Algorithm/Signature/RSA/RS1.php | 29 + .../src/Algorithm/Signature/RSA/RS256.php | 29 + .../src/Algorithm/Signature/RSA/RS384.php | 29 + .../src/Algorithm/Signature/RSA/RS512.php | 29 + .../src/Algorithm/Signature/RSA/RSA.php | 47 + .../src/Algorithm/Signature/Signature.php | 24 + .../web-auth/cose-lib/src/Algorithms.php | 157 + .../web-auth/cose-lib/src/Key/Ec2Key.php | 144 + .../web-auth/cose-lib/src/Key/Key.php | 90 + .../web-auth/cose-lib/src/Key/OkpKey.php | 66 + .../web-auth/cose-lib/src/Key/RsaKey.php | 197 ++ .../cose-lib/src/Key/SymmetricKey.php | 33 + .../web-auth/cose-lib/src/Verifier.php | 18 + .../web-auth/metadata-service/LICENSE | 21 + .../web-auth/metadata-service/README.md | 31 + .../web-auth/metadata-service/composer.json | 39 + .../src/AuthenticatorStatus.php | 33 + .../src/BiometricAccuracyDescriptor.php | 94 + .../src/BiometricStatusReport.php | 101 + .../src/CodeAccuracyDescriptor.php | 68 + .../DisplayPNGCharacteristicsDescriptor.php | 124 + .../src/DistantSingleMetadata.php | 60 + .../src/DistantSingleMetadataFactory.php | 43 + .../metadata-service/src/EcdaaTrustAnchor.php | 90 + .../src/ExtensionDescriptor.php | 68 + .../metadata-service/src/MetadataService.php | 84 + .../src/MetadataServiceFactory.php | 43 + .../src/MetadataStatement.php | 489 +++ .../src/MetadataStatementFetcher.php | 79 + .../src/MetadataStatementRepository.php | 19 + .../src/MetadataTOCPayload.php | 76 + .../src/MetadataTOCPayloadEntry.php | 145 + .../src/PatternAccuracyDescriptor.php | 57 + .../metadata-service/src/RgbPaletteEntry.php | 57 + .../metadata-service/src/RogueListEntry.php | 45 + .../src/SimpleMetadataStatementRepository.php | 138 + .../metadata-service/src/SingleMetadata.php | 54 + .../metadata-service/src/StatusReport.php | 114 + .../src/VerificationMethodANDCombinations.php | 44 + .../src/VerificationMethodDescriptor.php | 80 + .../web-auth/metadata-service/src/Version.php | 46 + .../composer/web-auth/webauthn-lib/LICENSE | 21 + .../composer/web-auth/webauthn-lib/README.md | 31 + .../web-auth/webauthn-lib/composer.json | 59 + .../AndroidKeyAttestationStatementSupport.php | 161 + ...idSafetyNetAttestationStatementSupport.php | 252 ++ .../AttestationObject.php | 54 + .../AttestationObjectLoader.php | 98 + .../AttestationStatement.php | 140 + .../AttestationStatementSupport.php | 25 + .../AttestationStatementSupportManager.php | 41 + .../FidoU2FAttestationStatementSupport.php | 134 + .../NoneAttestationStatementSupport.php | 38 + .../PackedAttestationStatementSupport.php | 204 ++ .../TPMAttestationStatementSupport.php | 325 ++ .../src/AttestedCredentialData.php | 98 + .../AuthenticationExtension.php | 59 + .../AuthenticationExtensionsClientInputs.php | 75 + .../AuthenticationExtensionsClientOutputs.php | 83 + ...nticationExtensionsClientOutputsLoader.php | 34 + .../ExtensionOutputChecker.php | 22 + .../ExtensionOutputCheckerHandler.php | 37 + .../ExtensionOutputError.php | 36 + .../src/AuthenticatorAssertionResponse.php | 67 + ...uthenticatorAssertionResponseValidator.php | 205 ++ .../src/AuthenticatorAttestationResponse.php | 38 + ...henticatorAttestationResponseValidator.php | 152 + .../webauthn-lib/src/AuthenticatorData.php | 124 + .../src/AuthenticatorResponse.php | 35 + .../src/AuthenticatorSelectionCriteria.php | 96 + .../webauthn-lib/src/CertificateToolbox.php | 209 ++ .../webauthn-lib/src/CollectedClientData.php | 138 + .../web-auth/webauthn-lib/src/Credential.php | 46 + .../webauthn-lib/src/PublicKeyCredential.php | 65 + .../PublicKeyCredentialCreationOptions.php | 177 ++ .../src/PublicKeyCredentialDescriptor.php | 105 + ...ublicKeyCredentialDescriptorCollection.php | 82 + .../src/PublicKeyCredentialEntity.php | 57 + .../src/PublicKeyCredentialLoader.php | 130 + .../src/PublicKeyCredentialOptions.php | 61 + .../src/PublicKeyCredentialParameters.php | 76 + .../src/PublicKeyCredentialRequestOptions.php | 127 + .../src/PublicKeyCredentialRpEntity.php | 56 + .../src/PublicKeyCredentialSource.php | 233 ++ .../PublicKeyCredentialSourceRepository.php | 26 + .../src/PublicKeyCredentialUserEntity.php | 80 + .../web-auth/webauthn-lib/src/Server.php | 264 ++ .../webauthn-lib/src/StringStream.php | 72 + .../IgnoreTokenBindingHandler.php | 24 + .../src/TokenBinding/TokenBinding.php | 77 + .../src/TokenBinding/TokenBindingHandler.php | 21 + .../TokenBindingNotSupportedHandler.php | 25 + .../src/TrustPath/CertificateTrustPath.php | 55 + .../src/TrustPath/EcdaaKeyIdTrustPath.php | 49 + .../src/TrustPath/EmptyTrustPath.php | 29 + .../webauthn-lib/src/TrustPath/TrustPath.php | 21 + .../src/TrustPath/TrustPathLoader.php | 48 + .../src/Util/CoseSignatureFixer.php | 54 + lam/lib/webauthn.inc | 80 +- lam/templates/config/confmain.php | 5 +- lam/templates/lib/500_lam.js | 30 + lam/templates/misc/ajax.php | 25 +- 386 files changed, 33146 insertions(+), 60 deletions(-) create mode 100644 lam/composer.lock create mode 100644 lam/lib/3rdParty/composer/autoload.php create mode 100644 lam/lib/3rdParty/composer/beberlei/assert/LICENSE create mode 100644 lam/lib/3rdParty/composer/beberlei/assert/composer.json create mode 100644 lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/Assert.php create mode 100644 lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/Assertion.php create mode 100644 lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/AssertionChain.php create mode 100644 lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/AssertionFailedException.php create mode 100644 lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/InvalidArgumentException.php create mode 100644 lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/LazyAssertion.php create mode 100644 lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/LazyAssertionException.php create mode 100644 lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/functions.php create mode 100644 lam/lib/3rdParty/composer/beberlei/assert/phpstan-code.neon create mode 100644 lam/lib/3rdParty/composer/beberlei/assert/phpstan-tests.neon create mode 100644 lam/lib/3rdParty/composer/composer/ClassLoader.php create mode 100644 lam/lib/3rdParty/composer/composer/LICENSE create mode 100644 lam/lib/3rdParty/composer/composer/autoload_classmap.php create mode 100644 lam/lib/3rdParty/composer/composer/autoload_files.php create mode 100644 lam/lib/3rdParty/composer/composer/autoload_namespaces.php create mode 100644 lam/lib/3rdParty/composer/composer/autoload_psr4.php create mode 100644 lam/lib/3rdParty/composer/composer/autoload_real.php create mode 100644 lam/lib/3rdParty/composer/composer/autoload_static.php create mode 100644 lam/lib/3rdParty/composer/composer/installed.json create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/CHANGELOG.md create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/LICENSE create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/README.md create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/composer.json create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/ASNObject.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/AbstractString.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/AbstractTime.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Base128.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Composite/AttributeTypeAndValue.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Composite/RDNString.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Composite/RelativeDistinguishedName.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Construct.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Exception/NotImplementedException.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Exception/ParserException.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/ExplicitlyTaggedObject.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Identifier.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/OID.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Parsable.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/TemplateParser.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/BMPString.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/BitString.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Boolean.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/CharacterString.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Enumerated.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GeneralString.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GeneralizedTime.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GraphicString.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/IA5String.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Integer.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/NullObject.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/NumericString.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/ObjectDescriptor.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/ObjectIdentifier.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/OctetString.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/PrintableString.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/RelativeObjectIdentifier.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Sequence.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Set.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/T61String.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/UTCTime.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/UTF8String.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/UniversalString.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/VisibleString.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/UnknownConstructedObject.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/UnknownObject.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/Utility/BigInteger.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/Utility/BigIntegerBcmath.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/Utility/BigIntegerGmp.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/AlgorithmIdentifier.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CSR/Attributes.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CSR/CSR.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CertificateExtensions.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CertificateSubject.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/PrivateKey.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/PublicKey.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/SAN/DNSName.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/SAN/IPAddress.php create mode 100644 lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/SAN/SubjectAlternativeNames.php create mode 100644 lam/lib/3rdParty/composer/nyholm/psr7/CHANGELOG.md create mode 100644 lam/lib/3rdParty/composer/nyholm/psr7/LICENSE create mode 100644 lam/lib/3rdParty/composer/nyholm/psr7/README.md create mode 100644 lam/lib/3rdParty/composer/nyholm/psr7/composer.json create mode 100644 lam/lib/3rdParty/composer/nyholm/psr7/src/Factory/HttplugFactory.php create mode 100644 lam/lib/3rdParty/composer/nyholm/psr7/src/Factory/Psr17Factory.php create mode 100644 lam/lib/3rdParty/composer/nyholm/psr7/src/MessageTrait.php create mode 100644 lam/lib/3rdParty/composer/nyholm/psr7/src/Request.php create mode 100644 lam/lib/3rdParty/composer/nyholm/psr7/src/RequestTrait.php create mode 100644 lam/lib/3rdParty/composer/nyholm/psr7/src/Response.php create mode 100644 lam/lib/3rdParty/composer/nyholm/psr7/src/ServerRequest.php create mode 100644 lam/lib/3rdParty/composer/nyholm/psr7/src/Stream.php create mode 100644 lam/lib/3rdParty/composer/nyholm/psr7/src/UploadedFile.php create mode 100644 lam/lib/3rdParty/composer/nyholm/psr7/src/Uri.php create mode 100644 lam/lib/3rdParty/composer/paragonie/random_compat/LICENSE create mode 100755 lam/lib/3rdParty/composer/paragonie/random_compat/build-phar.sh create mode 100644 lam/lib/3rdParty/composer/paragonie/random_compat/composer.json create mode 100644 lam/lib/3rdParty/composer/paragonie/random_compat/dist/random_compat.phar.pubkey create mode 100644 lam/lib/3rdParty/composer/paragonie/random_compat/dist/random_compat.phar.pubkey.asc create mode 100644 lam/lib/3rdParty/composer/paragonie/random_compat/lib/random.php create mode 100644 lam/lib/3rdParty/composer/paragonie/random_compat/other/build_phar.php create mode 100644 lam/lib/3rdParty/composer/paragonie/random_compat/psalm-autoload.php create mode 100644 lam/lib/3rdParty/composer/paragonie/random_compat/psalm.xml create mode 100644 lam/lib/3rdParty/composer/php-http/message-factory/CHANGELOG.md create mode 100644 lam/lib/3rdParty/composer/php-http/message-factory/LICENSE create mode 100644 lam/lib/3rdParty/composer/php-http/message-factory/README.md create mode 100644 lam/lib/3rdParty/composer/php-http/message-factory/composer.json create mode 100644 lam/lib/3rdParty/composer/php-http/message-factory/puli.json create mode 100644 lam/lib/3rdParty/composer/php-http/message-factory/src/MessageFactory.php create mode 100644 lam/lib/3rdParty/composer/php-http/message-factory/src/RequestFactory.php create mode 100644 lam/lib/3rdParty/composer/php-http/message-factory/src/ResponseFactory.php create mode 100644 lam/lib/3rdParty/composer/php-http/message-factory/src/StreamFactory.php create mode 100644 lam/lib/3rdParty/composer/php-http/message-factory/src/UriFactory.php create mode 100644 lam/lib/3rdParty/composer/psr/http-client/CHANGELOG.md create mode 100644 lam/lib/3rdParty/composer/psr/http-client/LICENSE create mode 100644 lam/lib/3rdParty/composer/psr/http-client/README.md create mode 100644 lam/lib/3rdParty/composer/psr/http-client/composer.json create mode 100644 lam/lib/3rdParty/composer/psr/http-client/src/ClientExceptionInterface.php create mode 100644 lam/lib/3rdParty/composer/psr/http-client/src/ClientInterface.php create mode 100644 lam/lib/3rdParty/composer/psr/http-client/src/NetworkExceptionInterface.php create mode 100644 lam/lib/3rdParty/composer/psr/http-client/src/RequestExceptionInterface.php create mode 100644 lam/lib/3rdParty/composer/psr/http-factory/.gitignore create mode 100644 lam/lib/3rdParty/composer/psr/http-factory/.pullapprove.yml create mode 100644 lam/lib/3rdParty/composer/psr/http-factory/LICENSE create mode 100644 lam/lib/3rdParty/composer/psr/http-factory/README.md create mode 100644 lam/lib/3rdParty/composer/psr/http-factory/composer.json create mode 100644 lam/lib/3rdParty/composer/psr/http-factory/src/RequestFactoryInterface.php create mode 100644 lam/lib/3rdParty/composer/psr/http-factory/src/ResponseFactoryInterface.php create mode 100644 lam/lib/3rdParty/composer/psr/http-factory/src/ServerRequestFactoryInterface.php create mode 100644 lam/lib/3rdParty/composer/psr/http-factory/src/StreamFactoryInterface.php create mode 100644 lam/lib/3rdParty/composer/psr/http-factory/src/UploadedFileFactoryInterface.php create mode 100644 lam/lib/3rdParty/composer/psr/http-factory/src/UriFactoryInterface.php create mode 100644 lam/lib/3rdParty/composer/psr/http-message/CHANGELOG.md create mode 100644 lam/lib/3rdParty/composer/psr/http-message/LICENSE create mode 100644 lam/lib/3rdParty/composer/psr/http-message/README.md create mode 100644 lam/lib/3rdParty/composer/psr/http-message/composer.json create mode 100644 lam/lib/3rdParty/composer/psr/http-message/src/MessageInterface.php create mode 100644 lam/lib/3rdParty/composer/psr/http-message/src/RequestInterface.php create mode 100644 lam/lib/3rdParty/composer/psr/http-message/src/ResponseInterface.php create mode 100644 lam/lib/3rdParty/composer/psr/http-message/src/ServerRequestInterface.php create mode 100644 lam/lib/3rdParty/composer/psr/http-message/src/StreamInterface.php create mode 100644 lam/lib/3rdParty/composer/psr/http-message/src/UploadedFileInterface.php create mode 100644 lam/lib/3rdParty/composer/psr/http-message/src/UriInterface.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/CHANGELOG.md create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/CODE_OF_CONDUCT.md create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/CONTRIBUTING.md create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/LICENSE create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/README.md create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/composer.json create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/BinaryUtils.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Builder/DefaultUuidBuilder.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Builder/DegradedUuidBuilder.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Builder/UuidBuilderInterface.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/CodecInterface.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/GuidStringCodec.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/OrderedTimeCodec.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/StringCodec.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/TimestampFirstCombCodec.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/TimestampLastCombCodec.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/Number/BigNumberConverter.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/Number/DegradedNumberConverter.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/NumberConverterInterface.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/Time/BigNumberTimeConverter.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/Time/DegradedTimeConverter.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/Time/PhpTimeConverter.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/TimeConverterInterface.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/DegradedUuid.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Exception/InvalidUuidStringException.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Exception/UnsatisfiedDependencyException.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Exception/UnsupportedOperationException.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/FeatureSet.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/CombGenerator.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/DefaultTimeGenerator.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/MtRandGenerator.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/OpenSslGenerator.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/PeclUuidRandomGenerator.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/PeclUuidTimeGenerator.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/RandomBytesGenerator.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/RandomGeneratorFactory.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/RandomGeneratorInterface.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/RandomLibAdapter.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/SodiumRandomGenerator.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/TimeGeneratorFactory.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/TimeGeneratorInterface.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/Node/FallbackNodeProvider.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/Node/RandomNodeProvider.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/Node/SystemNodeProvider.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/NodeProviderInterface.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/Time/FixedTimeProvider.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/Time/SystemTimeProvider.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/TimeProviderInterface.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/Uuid.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/UuidFactory.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/UuidFactoryInterface.php create mode 100644 lam/lib/3rdParty/composer/ramsey/uuid/src/UuidInterface.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/base64url/.php_cs.dist create mode 100644 lam/lib/3rdParty/composer/spomky-labs/base64url/LICENSE create mode 100644 lam/lib/3rdParty/composer/spomky-labs/base64url/composer.json create mode 100644 lam/lib/3rdParty/composer/spomky-labs/base64url/src/Base64Url.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/.github/CONTRIBUTING.md create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/.github/FUNDING.yml create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/.github/ISSUE_TEMPLATE.md create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/.php_cs.dist create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/CODE_OF_CONDUCT.md create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/LICENSE create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/composer.json create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/infection.json.dist create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/phpstan.neon create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/AbstractCBORObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/ByteStringObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/ByteStringWithChunkObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/CBORObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Decoder.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/InfiniteListObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/InfiniteMapObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/LengthCalculator.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/ListObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/MapItem.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/MapObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/BreakObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/DoublePrecisionFloatObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/FalseObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/GenericObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/HalfPrecisionFloatObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/NullObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/OtherObjectManager.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/SimpleObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/SinglePrecisionFloatObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/TrueObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/UndefinedObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/SignedIntegerObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Stream.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/StringStream.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/Base16EncodingTag.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/Base64EncodingTag.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/Base64UrlEncodingTag.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/BigFloatTag.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/DecimalFractionTag.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/EpochTag.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/GenericTag.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/NegativeBigIntegerTag.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/PositiveBigIntegerTag.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/TagObjectManager.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/TimestampTag.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/TagObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/TextStringObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/TextStringWithChunkObject.php create mode 100644 lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/UnsignedIntegerObject.php create mode 100644 lam/lib/3rdParty/composer/symfony/polyfill-ctype/Ctype.php create mode 100644 lam/lib/3rdParty/composer/symfony/polyfill-ctype/LICENSE create mode 100644 lam/lib/3rdParty/composer/symfony/polyfill-ctype/README.md create mode 100644 lam/lib/3rdParty/composer/symfony/polyfill-ctype/bootstrap.php create mode 100644 lam/lib/3rdParty/composer/symfony/polyfill-ctype/composer.json create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/LICENSE create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/README.md create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/composer.json create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Algorithm.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Mac/HS256.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Mac/HS256Truncated64.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Mac/HS384.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Mac/HS512.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Mac/Hmac.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Mac/Mac.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Manager.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/ManagerFactory.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ECDSA.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ECSignature.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ES256.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ES256K.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ES384.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ES512.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/EdDSA/ED256.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/EdDSA/ED512.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/EdDSA/Ed25519.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/EdDSA/EdDSA.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/PS256.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/PS384.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/PS512.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/PSSRSA.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/RS1.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/RS256.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/RS384.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/RS512.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/RSA.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/Signature.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithms.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/Ec2Key.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/Key.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/OkpKey.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/RsaKey.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/SymmetricKey.php create mode 100644 lam/lib/3rdParty/composer/web-auth/cose-lib/src/Verifier.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/LICENSE create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/README.md create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/composer.json create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/AuthenticatorStatus.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/BiometricAccuracyDescriptor.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/BiometricStatusReport.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/CodeAccuracyDescriptor.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/DisplayPNGCharacteristicsDescriptor.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/DistantSingleMetadata.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/DistantSingleMetadataFactory.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/EcdaaTrustAnchor.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/ExtensionDescriptor.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataService.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataServiceFactory.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataStatement.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataStatementFetcher.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataStatementRepository.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataTOCPayload.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataTOCPayloadEntry.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/PatternAccuracyDescriptor.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/RgbPaletteEntry.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/RogueListEntry.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/SimpleMetadataStatementRepository.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/SingleMetadata.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/StatusReport.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/VerificationMethodANDCombinations.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/VerificationMethodDescriptor.php create mode 100644 lam/lib/3rdParty/composer/web-auth/metadata-service/src/Version.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/LICENSE create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/README.md create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/composer.json create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AndroidKeyAttestationStatementSupport.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AndroidSafetyNetAttestationStatementSupport.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationObject.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationObjectLoader.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationStatement.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationStatementSupport.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationStatementSupportManager.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/FidoU2FAttestationStatementSupport.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/NoneAttestationStatementSupport.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/PackedAttestationStatementSupport.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/TPMAttestationStatementSupport.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestedCredentialData.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtension.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtensionsClientInputs.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtensionsClientOutputs.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtensionsClientOutputsLoader.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/ExtensionOutputChecker.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/ExtensionOutputCheckerHandler.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/ExtensionOutputError.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAssertionResponse.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAssertionResponseValidator.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAttestationResponse.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAttestationResponseValidator.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorData.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorResponse.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorSelectionCriteria.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CertificateToolbox.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CollectedClientData.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Credential.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredential.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialCreationOptions.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialDescriptor.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialDescriptorCollection.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialEntity.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialLoader.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialOptions.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialParameters.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialRequestOptions.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialRpEntity.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialSource.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialSourceRepository.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialUserEntity.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Server.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/StringStream.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/IgnoreTokenBindingHandler.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/TokenBinding.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/TokenBindingHandler.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/TokenBindingNotSupportedHandler.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/CertificateTrustPath.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/EcdaaKeyIdTrustPath.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/EmptyTrustPath.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/TrustPath.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/TrustPathLoader.php create mode 100644 lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Util/CoseSignatureFixer.php diff --git a/lam-packaging/debian/copyright b/lam-packaging/debian/copyright index cafeac9d..e39b6552 100644 --- a/lam-packaging/debian/copyright +++ b/lam-packaging/debian/copyright @@ -179,6 +179,7 @@ A: information, contact: tavmjong @ free . fr. B: + MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -200,6 +201,7 @@ B: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. C: + New BSD License Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -391,6 +393,7 @@ D: Library. E: + Duo Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -415,37 +418,73 @@ E: (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: - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: +F: + 3-Clause BSD License -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. 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. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: -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. + 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. 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. + +G: + 2-Clause BSD License + + 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. + + 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. Programs and licenses with other licenses and/or authors than the main license and authors: +lib/3rdParty/composer/beberlei G 2013 Benjamin Eberlei +lib/3rdParty/composer/composer B Nils Adermann, Jordi Boggiano +lib/3rdParty/composer/fgrosse B 2015 Friedrich Große +lib/3rdParty/composer/nyholm B 2016 Tobias Nyholm +lib/3rdParty/composer/paragonie B 2015 Paragon Initiative Enterprises +lib/3rdParty/composer/php-http B 2015 PHP HTTP Team +lib/3rdParty/composer/psr B 2018 PHP Framework Interoperability Group +lib/3rdParty/composer/ramsey B 2018 Ben Ramsey +lib/3rdParty/composer/spomky-labs B 2018 Spomky-Labs +lib/3rdParty/composer/symfony B 2019 Fabien Potencier +lib/3rdParty/composer/web-auth B 2018 Spomky-Labs lib/3rdParty/tcpdf D 2018 Nicola Asuni - Tecnick.com LTD lib/3rdParty/tcpdf/fonts/DejaVu*.ttf A Public Domain, Bitstream, Inc., Tavmjong Bah lib/3rdParty/tcpdf/fonts/DejaVu*.z A Public Domain, Bitstream, Inc., Tavmjong Bah diff --git a/lam/composer.lock b/lam/composer.lock new file mode 100644 index 00000000..c7cd584c --- /dev/null +++ b/lam/composer.lock @@ -0,0 +1,901 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "df09efa5a29ab9799e4e0c0ff066bfef", + "packages": [ + { + "name": "beberlei/assert", + "version": "v3.2.6", + "source": { + "type": "git", + "url": "https://github.com/beberlei/assert.git", + "reference": "99508be011753690fe108ded450f5caaae180cfa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/beberlei/assert/zipball/99508be011753690fe108ded450f5caaae180cfa", + "reference": "99508be011753690fe108ded450f5caaae180cfa", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "php": "^7" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "*", + "phpstan/phpstan-shim": "*", + "phpunit/phpunit": ">=6.0.0 <8" + }, + "suggest": { + "ext-intl": "Needed to allow Assertion::count(), Assertion::isCountable(), Assertion::minCount(), and Assertion::maxCount() to operate on ResourceBundles" + }, + "type": "library", + "autoload": { + "psr-4": { + "Assert\\": "lib/Assert" + }, + "files": [ + "lib/Assert/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de", + "role": "Lead Developer" + }, + { + "name": "Richard Quadling", + "email": "rquadling@gmail.com", + "role": "Collaborator" + } + ], + "description": "Thin assertion library for input validation in business models.", + "keywords": [ + "assert", + "assertion", + "validation" + ], + "time": "2019-10-10T10:33:57+00:00" + }, + { + "name": "fgrosse/phpasn1", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/fgrosse/PHPASN1.git", + "reference": "7ebf2a09084a7bbdb7b879c66fdf7ad80461bbe8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fgrosse/PHPASN1/zipball/7ebf2a09084a7bbdb7b879c66fdf7ad80461bbe8", + "reference": "7ebf2a09084a7bbdb7b879c66fdf7ad80461bbe8", + "shasum": "" + }, + "require": { + "php": ">=7.0.0" + }, + "require-dev": { + "phpunit/phpunit": "~6.3", + "satooshi/php-coveralls": "~2.0" + }, + "suggest": { + "ext-gmp": "GMP is the preferred extension for big integer calculations", + "php-curl": "For loading OID information from the web if they have not bee defined statically" + }, + "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" + ], + "time": "2018-12-02T01:34:34+00:00" + }, + { + "name": "nyholm/psr7", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/Nyholm/psr7.git", + "reference": "55ff6b76573f5b242554c9775792bd59fb52e11c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Nyholm/psr7/zipball/55ff6b76573f5b242554c9775792bd59fb52e11c", + "reference": "55ff6b76573f5b242554c9775792bd59fb52e11c", + "shasum": "" + }, + "require": { + "php": "^7.1", + "php-http/message-factory": "^1.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "http-interop/http-factory-tests": "dev-master", + "php-http/psr7-integration-tests": "dev-master", + "phpunit/phpunit": "^7.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Nyholm\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com" + }, + { + "name": "Martijn van der Ven", + "email": "martijn@vanderven.se" + } + ], + "description": "A fast PHP7 implementation of PSR-7", + "homepage": "http://tnyholm.se", + "keywords": [ + "psr-17", + "psr-7" + ], + "time": "2019-09-05T13:24:16+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v9.99.99", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", + "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", + "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" + ], + "time": "2018-07-02T15:55:56+00:00" + }, + { + "name": "php-http/message-factory", + "version": "v1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-http/message-factory.git", + "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/message-factory/zipball/a478cb11f66a6ac48d8954216cfed9aa06a501a1", + "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "Factory interfaces for PSR-7 HTTP Message", + "homepage": "http://php-http.org", + "keywords": [ + "factory", + "http", + "message", + "stream", + "uri" + ], + "time": "2015-12-19T14:08:53+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "496a823ef742b632934724bf769560c2a5c7c44e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/496a823ef742b632934724bf769560c2a5c7c44e", + "reference": "496a823ef742b632934724bf769560c2a5c7c44e", + "shasum": "" + }, + "require": { + "php": "^7.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "time": "2018-10-30T23:29:13+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "time": "2019-04-30T12:38:16+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "ramsey/uuid", + "version": "3.8.0", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid.git", + "reference": "d09ea80159c1929d75b3f9c60504d613aeb4a1e3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/d09ea80159c1929d75b3f9c60504d613aeb4a1e3", + "reference": "d09ea80159c1929d75b3f9c60504d613aeb4a1e3", + "shasum": "" + }, + "require": { + "paragonie/random_compat": "^1.0|^2.0|9.99.99", + "php": "^5.4 || ^7.0", + "symfony/polyfill-ctype": "^1.8" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "codeception/aspect-mock": "^1.0 | ~2.0.0", + "doctrine/annotations": "~1.2.0", + "goaop/framework": "1.0.0-alpha.2 | ^1.0 | ~2.1.0", + "ircmaxell/random-lib": "^1.1", + "jakub-onderka/php-parallel-lint": "^0.9.0", + "mockery/mockery": "^0.9.9", + "moontoast/math": "^1.1", + "php-mock/php-mock-phpunit": "^0.3|^1.1", + "phpunit/phpunit": "^4.7|^5.0|^6.5", + "squizlabs/php_codesniffer": "^2.3" + }, + "suggest": { + "ext-ctype": "Provides support for PHP Ctype functions", + "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator", + "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator", + "ircmaxell/random-lib": "Provides RandomLib for use with the RandomLibAdapter", + "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).", + "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid", + "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Ramsey\\Uuid\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marijn Huizendveld", + "email": "marijn.huizendveld@gmail.com" + }, + { + "name": "Thibaud Fabre", + "email": "thibaud@aztech.io" + }, + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + } + ], + "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).", + "homepage": "https://github.com/ramsey/uuid", + "keywords": [ + "guid", + "identifier", + "uuid" + ], + "time": "2018-07-19T23:38:55+00:00" + }, + { + "name": "spomky-labs/base64url", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/Spomky-Labs/base64url.git", + "reference": "3eb46a1de803f0078962d910e3a2759224a68c61" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Spomky-Labs/base64url/zipball/3eb46a1de803f0078962d910e3a2759224a68c61", + "reference": "3eb46a1de803f0078962d910e3a2759224a68c61", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.0", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Base64Url\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky-Labs/base64url/contributors" + } + ], + "description": "Base 64 URL Safe Encoding/Decoding PHP Library", + "homepage": "https://github.com/Spomky-Labs/base64url", + "keywords": [ + "base64", + "rfc4648", + "safe", + "url" + ], + "time": "2018-08-16T15:44:20+00:00" + }, + { + "name": "spomky-labs/cbor-php", + "version": "v1.0.7", + "source": { + "type": "git", + "url": "https://github.com/Spomky-Labs/cbor-php.git", + "reference": "f937d527b05bb3ec3f6b8670ece38ccaf9a0eddd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Spomky-Labs/cbor-php/zipball/f937d527b05bb3ec3f6b8670ece38ccaf9a0eddd", + "reference": "f937d527b05bb3ec3f6b8670ece38ccaf9a0eddd", + "shasum": "" + }, + "require": { + "beberlei/assert": "^3.2", + "ext-gmp": "*", + "php": "^7.1|^8.0", + "spomky-labs/base64url": "^1.0|^2.0" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.0", + "phpstan/phpstan": "^0.11", + "phpstan/phpstan-beberlei-assert": "^0.11.0", + "phpstan/phpstan-deprecation-rules": "^0.11", + "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-strict-rules": "^0.11", + "phpunit/phpunit": "^7.5|^8.0", + "rector/rector": "^0.5" + }, + "suggest": { + "ext-bcmath": "BCMath extension needed to handle the Big Float and Decimal Fraction Tags" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "CBOR\\": "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/Spomky-Labs/cbor-php/contributors" + } + ], + "description": "CBOR Encoder/Decoder for PHP", + "keywords": [ + "Concise Binary Object Representation", + "RFC7049", + "cbor" + ], + "time": "2019-08-15T14:53:55+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.12.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "550ebaac289296ce228a706d0867afc34687e3f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/550ebaac289296ce228a706d0867afc34687e3f4", + "reference": "550ebaac289296ce228a706d0867afc34687e3f4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.12-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "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" + ], + "time": "2019-08-06T08:03:45+00:00" + }, + { + "name": "web-auth/cose-lib", + "version": "v2.1.7", + "source": { + "type": "git", + "url": "https://github.com/web-auth/cose-lib.git", + "reference": "8d1c37bac6e5db8d502b7735448d416f05fb4c70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/web-auth/cose-lib/zipball/8d1c37bac6e5db8d502b7735448d416f05fb4c70", + "reference": "8d1c37bac6e5db8d502b7735448d416f05fb4c70", + "shasum": "" + }, + "require": { + "beberlei/assert": "^3.0", + "ext-json": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "fgrosse/phpasn1": "^2.1", + "php": "^7.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "v1.0": "1.0.x-dev", + "v1.1": "1.1.x-dev", + "v1.2": "1.2.x-dev", + "v2.0": "2.0.x-dev", + "v2.1": "2.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Cose\\": "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/cose/contributors" + } + ], + "description": "CBOR Object Signing and Encryption (COSE) For PHP", + "homepage": "https://github.com/web-auth", + "keywords": [ + "COSE", + "RFC8152" + ], + "time": "2019-09-04T20:53:12+00:00" + }, + { + "name": "web-auth/metadata-service", + "version": "v2.1.7", + "source": { + "type": "git", + "url": "https://github.com/web-auth/webauthn-metadata-service.git", + "reference": "5fc754d00dfa05913260dc3781227dfa8ed7dbdd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/web-auth/webauthn-metadata-service/zipball/5fc754d00dfa05913260dc3781227dfa8ed7dbdd", + "reference": "5fc754d00dfa05913260dc3781227dfa8ed7dbdd", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.1", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "v2.1": "2.1.x-dev" + } + }, + "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" + ], + "time": "2019-09-04T20:53:12+00:00" + }, + { + "name": "web-auth/webauthn-lib", + "version": "v2.1.7", + "source": { + "type": "git", + "url": "https://github.com/web-auth/webauthn-lib.git", + "reference": "4cd346f2ef4d282296e503b7b1b3ef200347437b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/web-auth/webauthn-lib/zipball/4cd346f2ef4d282296e503b7b1b3ef200347437b", + "reference": "4cd346f2ef4d282296e503b7b1b3ef200347437b", + "shasum": "" + }, + "require": { + "beberlei/assert": "^3.0", + "ext-json": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "nyholm/psr7": "^1.1", + "php": "^7.2", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "ramsey/uuid": "^3.8", + "spomky-labs/base64url": "^2.0", + "spomky-labs/cbor-php": "^1.0.2", + "web-auth/cose-lib": "self.version", + "web-auth/metadata-service": "self.version" + }, + "suggest": { + "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" + }, + "type": "library", + "extra": { + "branch-alias": { + "v1.0": "1.0.x-dev", + "v1.1": "1.1.x-dev", + "v1.2": "1.2.x-dev", + "v2.0": "2.0.x-dev", + "v2.1": "2.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Webauthn\\": "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/webauthn-library/contributors" + } + ], + "description": "FIDO2/Webauthn Support For PHP", + "homepage": "https://github.com/web-auth", + "keywords": [ + "FIDO2", + "fido", + "webauthn" + ], + "time": "2019-09-09T12:04:09+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/lam/copyright b/lam/copyright index d2a46ec4..fe3f4fcb 100644 --- a/lam/copyright +++ b/lam/copyright @@ -178,6 +178,7 @@ A: information, contact: tavmjong @ free . fr. B: + MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -199,6 +200,7 @@ B: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. C: + New BSD License Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -390,6 +392,7 @@ D: Library. E: + Duo Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -415,36 +418,72 @@ E: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. F: - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: + 3-Clause BSD License -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. 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. + 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. 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. + +G: + 2-Clause BSD License + + 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. + + 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. -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. - Programs and licenses with other licenses and/or authors than the main license and authors: +lib/3rdParty/composer/beberlei G 2013 Benjamin Eberlei +lib/3rdParty/composer/composer B Nils Adermann, Jordi Boggiano +lib/3rdParty/composer/fgrosse B 2015 Friedrich Große +lib/3rdParty/composer/nyholm B 2016 Tobias Nyholm +lib/3rdParty/composer/paragonie B 2015 Paragon Initiative Enterprises +lib/3rdParty/composer/php-http B 2015 PHP HTTP Team +lib/3rdParty/composer/psr B 2018 PHP Framework Interoperability Group +lib/3rdParty/composer/ramsey B 2018 Ben Ramsey +lib/3rdParty/composer/spomky-labs B 2018 Spomky-Labs +lib/3rdParty/composer/symfony B 2019 Fabien Potencier +lib/3rdParty/composer/web-auth B 2018 Spomky-Labs lib/3rdParty/tcpdf D 2018 Nicola Asuni - Tecnick.com LTD lib/3rdParty/tcpdf/fonts/DejaVu*.ttf A Public Domain, Bitstream, Inc., Tavmjong Bah lib/3rdParty/tcpdf/fonts/DejaVu*.z A Public Domain, Bitstream, Inc., Tavmjong Bah diff --git a/lam/lib/3rdParty/composer/autoload.php b/lam/lib/3rdParty/composer/autoload.php new file mode 100644 index 00000000..ef2a8557 --- /dev/null +++ b/lam/lib/3rdParty/composer/autoload.php @@ -0,0 +1,7 @@ +=6.0.0 <8" + }, + "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 new file mode 100644 index 00000000..6910258d --- /dev/null +++ b/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/Assert.php @@ -0,0 +1,96 @@ +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 + * @param string|null $defaultPropertyPath + * + * @return AssertionChain + */ + 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 + * @param string|null $defaultPropertyPath + * + * @return AssertionChain + */ + public static function thatNullOr($value, $defaultMessage = null, string $defaultPropertyPath = null): AssertionChain + { + return static::that($value, $defaultMessage, $defaultPropertyPath)->nullOr(); + } + + /** + * Create a lazy assertion object. + * + * @return LazyAssertion + */ + 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 new file mode 100644 index 00000000..a8b04e52 --- /dev/null +++ b/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/Assertion.php @@ -0,0 +1,2825 @@ + + * + * @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 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 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; + + /** + * 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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * + * @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 array $choices + * @param string|callable|null $message + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * + * @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 + * + * @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 + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * + * @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 + * + * @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 + * + * @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 + * + * @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 + * + * @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 + * + * @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 + * + * @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 + * + * @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 + * + * @return bool + * + * @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 + * + * @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 + * + * @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 + * + * @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 + * + * @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 + * + * @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, null, $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 + * + * @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, null, $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 + * + * @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, null, $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 + * + * @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, null, $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 array $choices + * @param string|callable|null $message + * @param string|null $propertyPath + * + * @return bool + * + * @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 array $choices + * @param string|callable|null $message + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * + * @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 + * + * @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 + * + * @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 + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 array|Countable|ResourceBundle|SimpleXMLElement $value + * @param string|callable|null $message + * @param string|null $propertyPath + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 key exists in an array/array-accessible object using isset(). + * + * @param mixed $value + * @param string|int $key + * @param string|callable|null $message + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * + * @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 + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * + * @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 + * + * @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 + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * + * @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 + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * + * @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 + * + * @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 + * + * @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 + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 array $values + * @param array $choices + * @param string|callable|null $message + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * + * @return bool + * + * @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 + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 array $properties + * @param string|callable|null $message + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 (!\filter_var($value, FILTER_VALIDATE_IP, $flag)) { + $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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * + * @return bool + */ + 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 + * @param string|null $propertyPath + * + * @return bool + * + * @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 + * @param string|null $propertyPath + * @param array $constraints + * + * @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 + * + * @return string + */ + 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 + * + * @return string + */ + 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 new file mode 100644 index 00000000..dbb6e839 --- /dev/null +++ b/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/AssertionChain.php @@ -0,0 +1,254 @@ + + * + * @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 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 + * @param string|null $defaultPropertyPath + */ + 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 + * + * @return AssertionChain + */ + public function __call($methodName, $args): AssertionChain + { + if (true === $this->alwaysValid) { + return $this; + } + + if (!\method_exists($this->assertionClassName, $methodName)) { + throw new \RuntimeException("Assertion '".$methodName."' does not exist."); + } + + $reflClass = new ReflectionClass($this->assertionClassName); + $method = $reflClass->getMethod($methodName); + + \array_unshift($args, $this->value); + $params = $method->getParameters(); + + foreach ($params as $idx => $param) { + if (isset($args[$idx])) { + continue; + } + + if ('message' == $param->getName()) { + $args[$idx] = $this->defaultMessage; + } + + if ('propertyPath' == $param->getName()) { + $args[$idx] = $this->defaultPropertyPath; + } + } + + 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. + * + * @return AssertionChain + */ + public function all(): AssertionChain + { + $this->all = true; + + return $this; + } + + /** + * Switch chain into mode allowing nulls, ignoring further assertions. + * + * @return AssertionChain + */ + 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 new file mode 100644 index 00000000..c1848388 --- /dev/null +++ b/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/AssertionFailedException.php @@ -0,0 +1,35 @@ +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. + * + * @return array + */ + 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 new file mode 100644 index 00000000..c032911a --- /dev/null +++ b/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/LazyAssertion.php @@ -0,0 +1,230 @@ + + * + * @method static static alnum(string|callable $message = null, string $propertyPath = null) Assert that value is alphanumeric. + * @method static static base64(string|callable $message = null, string $propertyPath = null) Assert that a constant is defined. + * @method static static 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 static static 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 static static 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 static static boolean(string|callable $message = null, string $propertyPath = null) Assert that value is php boolean. + * @method static static choice(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices. + * @method static static 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 static static classExists(string|callable $message = null, string $propertyPath = null) Assert that the class exists. + * @method static static contains(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string contains a sequence of chars. + * @method static static count(int $count, string|callable $message = null, string $propertyPath = null) Assert that the count of countable is equal to count. + * @method static static date(string $format, string|callable $message = null, string $propertyPath = null) Assert that date is valid and corresponds to the given format. + * @method static static defined(string|callable $message = null, string $propertyPath = null) Assert that a constant is defined. + * @method static static digit(string|callable $message = null, string $propertyPath = null) Validates if an integer or integerish is a digit. + * @method static static directory(string|callable $message = null, string $propertyPath = null) Assert that a directory exists. + * @method static static e164(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid E164 Phone Number. + * @method static static email(string|callable $message = null, string $propertyPath = null) Assert that value is an email address (using input_filter/FILTER_VALIDATE_EMAIL). + * @method static static endsWith(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string ends with a sequence of chars. + * @method static static eq(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are equal (using ==). + * @method static static eqArraySubset(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that the array contains the subset. + * @method static static extensionLoaded(string|callable $message = null, string $propertyPath = null) Assert that extension is loaded. + * @method static static extensionVersion(string $operator, mixed $version, string|callable $message = null, string $propertyPath = null) Assert that extension is loaded and a specific version is installed. + * @method static static false(string|callable $message = null, string $propertyPath = null) Assert that the value is boolean False. + * @method static static file(string|callable $message = null, string $propertyPath = null) Assert that a file exists. + * @method static static float(string|callable $message = null, string $propertyPath = null) Assert that value is a php float. + * @method static static greaterOrEqualThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater or equal than given limit. + * @method static static greaterThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater than given limit. + * @method static static implementsInterface(string $interfaceName, string|callable $message = null, string $propertyPath = null) Assert that the class implements the interface. + * @method static static 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 static static integer(string|callable $message = null, string $propertyPath = null) Assert that value is a php integer. + * @method static static integerish(string|callable $message = null, string $propertyPath = null) Assert that value is a php integer'ish. + * @method static static interfaceExists(string|callable $message = null, string $propertyPath = null) Assert that the interface exists. + * @method static static ip(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 or IPv6 address. + * @method static static ipv4(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 address. + * @method static static ipv6(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv6 address. + * @method static static isArray(string|callable $message = null, string $propertyPath = null) Assert that value is an array. + * @method static static isArrayAccessible(string|callable $message = null, string $propertyPath = null) Assert that value is an array or an array-accessible object. + * @method static static isCallable(string|callable $message = null, string $propertyPath = null) Determines that the provided value is callable. + * @method static static isCountable(string|callable $message = null, string $propertyPath = null) Assert that value is countable. + * @method static static isInstanceOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is instance of given class-name. + * @method static static isJsonString(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid json string. + * @method static static isObject(string|callable $message = null, string $propertyPath = null) Determines that the provided value is an object. + * @method static static isResource(string|callable $message = null, string $propertyPath = null) Assert that value is a resource. + * @method static static isTraversable(string|callable $message = null, string $propertyPath = null) Assert that value is an array or a traversable object. + * @method static static keyExists(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array. + * @method static static keyIsset(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object using isset(). + * @method static static keyNotExists(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key does not exist in an array. + * @method static static length(int $length, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string has a given length. + * @method static static lessOrEqualThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less or equal than given limit. + * @method static static lessThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less than given limit. + * @method static static max(mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that a number is smaller as a given limit. + * @method static static maxCount(int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at most $count elements. + * @method static static maxLength(int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string value is not longer than $maxLength chars. + * @method static static methodExists(mixed $object, string|callable $message = null, string $propertyPath = null) Determines that the named method is defined in the provided object. + * @method static static min(mixed $minValue, string|callable $message = null, string $propertyPath = null) Assert that a value is at least as big as a given limit. + * @method static static minCount(int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at least $count elements. + * @method static static minLength(int $minLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that a string is at least $minLength chars long. + * @method static static noContent(string|callable $message = null, string $propertyPath = null) Assert that value is empty. + * @method static static notBlank(string|callable $message = null, string $propertyPath = null) Assert that value is not blank. + * @method static static notContains(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string does not contains a sequence of chars. + * @method static static notEmpty(string|callable $message = null, string $propertyPath = null) Assert that value is not empty. + * @method static static 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 static static notEq(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not equal (using ==). + * @method static static notInArray(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is not in array of choices. + * @method static static notIsInstanceOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is not instance of given class-name. + * @method static static notNull(string|callable $message = null, string $propertyPath = null) Assert that value is not null. + * @method static static notRegex(string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value does not match a regex. + * @method static static notSame(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not the same (using ===). + * @method static static null(string|callable $message = null, string $propertyPath = null) Assert that value is null. + * @method static static numeric(string|callable $message = null, string $propertyPath = null) Assert that value is numeric. + * @method static static objectOrClass(string|callable $message = null, string $propertyPath = null) Assert that the value is an object, or a class that exists. + * @method static static phpVersion(mixed $version, string|callable $message = null, string $propertyPath = null) Assert on PHP version. + * @method static static 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 static static 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 static static range(mixed $minValue, mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that value is in range of numbers. + * @method static static readable(string|callable $message = null, string $propertyPath = null) Assert that the value is something readable. + * @method static static regex(string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value matches a regex. + * @method static static same(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are the same (using ===). + * @method static static satisfy(callable $callback, string|callable $message = null, string $propertyPath = null) Assert that the provided value is valid according to a callback. + * @method static static scalar(string|callable $message = null, string $propertyPath = null) Assert that value is a PHP scalar. + * @method static static startsWith(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string starts with a sequence of chars. + * @method static static string(string|callable $message = null, string $propertyPath = null) Assert that value is a string. + * @method static static subclassOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is subclass of given class-name. + * @method static static true(string|callable $message = null, string $propertyPath = null) Assert that the value is boolean True. + * @method static static url(string|callable $message = null, string $propertyPath = null) Assert that value is an URL. + * @method static static uuid(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid UUID. + * @method static static version(string $operator, string $version2, string|callable $message = null, string $propertyPath = null) Assert comparison of two versions. + * @method static static writeable(string|callable $message = null, string $propertyPath = null) Assert that the value is something writeable. + * @method static static all() Switch chain into validation mode for an array of values. + * @method static static 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|null $propertyPath + * @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; + } + + /** + * @return bool + * + * @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) + { + 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) + { + 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 new file mode 100644 index 00000000..f76ecc69 --- /dev/null +++ b/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/LazyAssertionException.php @@ -0,0 +1,55 @@ +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 new file mode 100644 index 00000000..e0ccbd7d --- /dev/null +++ b/lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/functions.php @@ -0,0 +1,80 @@ +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 + * + * @return AssertionChain + */ +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 + * + * @return AssertionChain + * + * @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. + * + * @return LazyAssertion + */ +function lazy(): LazyAssertion +{ + return Assert::lazy(); +} diff --git a/lam/lib/3rdParty/composer/beberlei/assert/phpstan-code.neon b/lam/lib/3rdParty/composer/beberlei/assert/phpstan-code.neon new file mode 100644 index 00000000..49aa5723 --- /dev/null +++ b/lam/lib/3rdParty/composer/beberlei/assert/phpstan-code.neon @@ -0,0 +1,10 @@ +parameters: + autoload_files: + - bin/MethodDocGenerator.php + ignoreErrors: + # is_countable() is available only in PHP 7.3+ + - '#Function is_countable not found#' + + # Calling count() on ResourceBundle and SimpleXMLElement is valid from PHP 7.0+, but does not correctly advertise + # the fact, and so PHPStan has an issue with this. This will be fixed in PHP 7.4+ + - '#Call to function count\(\) with argument type array|Countable|ResourceBundle|SimpleXMLElement will always result in number 1#' diff --git a/lam/lib/3rdParty/composer/beberlei/assert/phpstan-tests.neon b/lam/lib/3rdParty/composer/beberlei/assert/phpstan-tests.neon new file mode 100644 index 00000000..e9ab0bcf --- /dev/null +++ b/lam/lib/3rdParty/composer/beberlei/assert/phpstan-tests.neon @@ -0,0 +1,10 @@ +parameters: + ignoreErrors: + # The following errors are ignored as they are testing for errors and exceptions that static analysis correctly identifies as problems. + - '#Call to an undefined method Assert\\AssertionChain::unknownAssertion\(\)#' + - '#Call to an undefined static method Assert\\Assertion::nullOrAssertionDoesNotExist\(\)#' + - '#Class Foo not found#' + - '#Parameter \#1 $value of static method Assert\\Assertion::isCountable\(\) expects array|Countable|ResourceBundle|SimpleXMLElement, string given#' + - '#Parameter \#2 \$operator of static method Assert\\Assertion::version\(\) expects string, null given#' + - '#Static method Assert\\Assertion::allTrue\(\) invoked with 0 parameters, 1-3 required#' + - '#Static method Assert\\Assertion::nullOrMax\(\) invoked with 0 parameters, 2-4 required#' diff --git a/lam/lib/3rdParty/composer/composer/ClassLoader.php b/lam/lib/3rdParty/composer/composer/ClassLoader.php new file mode 100644 index 00000000..fce8549f --- /dev/null +++ b/lam/lib/3rdParty/composer/composer/ClassLoader.php @@ -0,0 +1,445 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see http://www.php-fig.org/psr/psr-0/ + * @see http://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + private $classMapAuthoritative = false; + private $missingClasses = array(); + private $apcuPrefix; + + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', $this->prefixesPsr0); + } + + return array(); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/lam/lib/3rdParty/composer/composer/LICENSE b/lam/lib/3rdParty/composer/composer/LICENSE new file mode 100644 index 00000000..4b615a38 --- /dev/null +++ b/lam/lib/3rdParty/composer/composer/LICENSE @@ -0,0 +1,56 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: Composer +Upstream-Contact: Jordi Boggiano +Source: https://github.com/composer/composer + +Files: * +Copyright: 2016, Nils Adermann + 2016, Jordi Boggiano +License: Expat + +Files: src/Composer/Util/TlsHelper.php +Copyright: 2016, Nils Adermann + 2016, Jordi Boggiano + 2013, Evan Coury +License: Expat and BSD-2-Clause + +License: BSD-2-Clause + 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. + . + 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. + +License: Expat + 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/composer/autoload_classmap.php b/lam/lib/3rdParty/composer/composer/autoload_classmap.php new file mode 100644 index 00000000..024622f7 --- /dev/null +++ b/lam/lib/3rdParty/composer/composer/autoload_classmap.php @@ -0,0 +1,9 @@ + $vendorDir . '/beberlei/assert/lib/Assert/functions.php', + '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', +); diff --git a/lam/lib/3rdParty/composer/composer/autoload_namespaces.php b/lam/lib/3rdParty/composer/composer/autoload_namespaces.php new file mode 100644 index 00000000..9bd4acee --- /dev/null +++ b/lam/lib/3rdParty/composer/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($vendorDir . '/web-auth/metadata-service/src'), + 'Webauthn\\' => array($vendorDir . '/web-auth/webauthn-lib/src'), + 'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'), + 'Ramsey\\Uuid\\' => array($vendorDir . '/ramsey/uuid/src'), + 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'), + 'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'), + 'Nyholm\\Psr7\\' => array($vendorDir . '/nyholm/psr7/src'), + 'Http\\Message\\' => array($vendorDir . '/php-http/message-factory/src'), + 'FG\\' => array($vendorDir . '/fgrosse/phpasn1/lib'), + 'Cose\\' => array($vendorDir . '/web-auth/cose-lib/src'), + 'CBOR\\' => array($vendorDir . '/spomky-labs/cbor-php/src'), + 'Base64Url\\' => array($vendorDir . '/spomky-labs/base64url/src'), + 'Assert\\' => array($vendorDir . '/beberlei/assert/lib/Assert'), +); diff --git a/lam/lib/3rdParty/composer/composer/autoload_real.php b/lam/lib/3rdParty/composer/composer/autoload_real.php new file mode 100644 index 00000000..9fc69849 --- /dev/null +++ b/lam/lib/3rdParty/composer/composer/autoload_real.php @@ -0,0 +1,70 @@ += 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require_once __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + if ($useStaticLoader) { + $includeFiles = Composer\Autoload\ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5::$files; + } else { + $includeFiles = require __DIR__ . '/autoload_files.php'; + } + foreach ($includeFiles as $fileIdentifier => $file) { + composerRequireed73ceb9c1bdec18b7c6d09764d1bce5($fileIdentifier, $file); + } + + return $loader; + } +} + +function composerRequireed73ceb9c1bdec18b7c6d09764d1bce5($fileIdentifier, $file) +{ + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + require $file; + + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + } +} diff --git a/lam/lib/3rdParty/composer/composer/autoload_static.php b/lam/lib/3rdParty/composer/composer/autoload_static.php new file mode 100644 index 00000000..5659a0d0 --- /dev/null +++ b/lam/lib/3rdParty/composer/composer/autoload_static.php @@ -0,0 +1,124 @@ + __DIR__ . '/..' . '/beberlei/assert/lib/Assert/functions.php', + '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', + ); + + public static $prefixLengthsPsr4 = array ( + 'W' => + array ( + 'Webauthn\\MetadataService\\' => 25, + 'Webauthn\\' => 9, + ), + 'S' => + array ( + 'Symfony\\Polyfill\\Ctype\\' => 23, + ), + 'R' => + array ( + 'Ramsey\\Uuid\\' => 12, + ), + 'P' => + array ( + 'Psr\\Http\\Message\\' => 17, + 'Psr\\Http\\Client\\' => 16, + ), + 'N' => + array ( + 'Nyholm\\Psr7\\' => 12, + ), + 'H' => + array ( + 'Http\\Message\\' => 13, + ), + 'F' => + array ( + 'FG\\' => 3, + ), + 'C' => + array ( + 'Cose\\' => 5, + 'CBOR\\' => 5, + ), + 'B' => + array ( + 'Base64Url\\' => 10, + ), + 'A' => + array ( + 'Assert\\' => 7, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Webauthn\\MetadataService\\' => + array ( + 0 => __DIR__ . '/..' . '/web-auth/metadata-service/src', + ), + 'Webauthn\\' => + array ( + 0 => __DIR__ . '/..' . '/web-auth/webauthn-lib/src', + ), + 'Symfony\\Polyfill\\Ctype\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-ctype', + ), + 'Ramsey\\Uuid\\' => + array ( + 0 => __DIR__ . '/..' . '/ramsey/uuid/src', + ), + 'Psr\\Http\\Message\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/http-factory/src', + 1 => __DIR__ . '/..' . '/psr/http-message/src', + ), + 'Psr\\Http\\Client\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/http-client/src', + ), + 'Nyholm\\Psr7\\' => + array ( + 0 => __DIR__ . '/..' . '/nyholm/psr7/src', + ), + 'Http\\Message\\' => + array ( + 0 => __DIR__ . '/..' . '/php-http/message-factory/src', + ), + 'FG\\' => + array ( + 0 => __DIR__ . '/..' . '/fgrosse/phpasn1/lib', + ), + 'Cose\\' => + array ( + 0 => __DIR__ . '/..' . '/web-auth/cose-lib/src', + ), + 'CBOR\\' => + array ( + 0 => __DIR__ . '/..' . '/spomky-labs/cbor-php/src', + ), + 'Base64Url\\' => + array ( + 0 => __DIR__ . '/..' . '/spomky-labs/base64url/src', + ), + 'Assert\\' => + array ( + 0 => __DIR__ . '/..' . '/beberlei/assert/lib/Assert', + ), + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInited73ceb9c1bdec18b7c6d09764d1bce5::$prefixDirsPsr4; + + }, null, ClassLoader::class); + } +} diff --git a/lam/lib/3rdParty/composer/composer/installed.json b/lam/lib/3rdParty/composer/composer/installed.json new file mode 100644 index 00000000..40511296 --- /dev/null +++ b/lam/lib/3rdParty/composer/composer/installed.json @@ -0,0 +1,915 @@ +[ + { + "name": "beberlei/assert", + "version": "v3.2.6", + "version_normalized": "3.2.6.0", + "source": { + "type": "git", + "url": "https://github.com/beberlei/assert.git", + "reference": "99508be011753690fe108ded450f5caaae180cfa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/beberlei/assert/zipball/99508be011753690fe108ded450f5caaae180cfa", + "reference": "99508be011753690fe108ded450f5caaae180cfa", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "php": "^7" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "*", + "phpstan/phpstan-shim": "*", + "phpunit/phpunit": ">=6.0.0 <8" + }, + "suggest": { + "ext-intl": "Needed to allow Assertion::count(), Assertion::isCountable(), Assertion::minCount(), and Assertion::maxCount() to operate on ResourceBundles" + }, + "time": "2019-10-10T10:33:57+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Assert\\": "lib/Assert" + }, + "files": [ + "lib/Assert/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de", + "role": "Lead Developer" + }, + { + "name": "Richard Quadling", + "email": "rquadling@gmail.com", + "role": "Collaborator" + } + ], + "description": "Thin assertion library for input validation in business models.", + "keywords": [ + "assert", + "assertion", + "validation" + ] + }, + { + "name": "fgrosse/phpasn1", + "version": "v2.1.1", + "version_normalized": "2.1.1.0", + "source": { + "type": "git", + "url": "https://github.com/fgrosse/PHPASN1.git", + "reference": "7ebf2a09084a7bbdb7b879c66fdf7ad80461bbe8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fgrosse/PHPASN1/zipball/7ebf2a09084a7bbdb7b879c66fdf7ad80461bbe8", + "reference": "7ebf2a09084a7bbdb7b879c66fdf7ad80461bbe8", + "shasum": "" + }, + "require": { + "php": ">=7.0.0" + }, + "require-dev": { + "phpunit/phpunit": "~6.3", + "satooshi/php-coveralls": "~2.0" + }, + "suggest": { + "ext-gmp": "GMP is the preferred extension for big integer calculations", + "php-curl": "For loading OID information from the web if they have not bee defined statically" + }, + "time": "2018-12-02T01:34:34+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" + ] + }, + { + "name": "nyholm/psr7", + "version": "1.2.1", + "version_normalized": "1.2.1.0", + "source": { + "type": "git", + "url": "https://github.com/Nyholm/psr7.git", + "reference": "55ff6b76573f5b242554c9775792bd59fb52e11c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Nyholm/psr7/zipball/55ff6b76573f5b242554c9775792bd59fb52e11c", + "reference": "55ff6b76573f5b242554c9775792bd59fb52e11c", + "shasum": "" + }, + "require": { + "php": "^7.1", + "php-http/message-factory": "^1.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "http-interop/http-factory-tests": "dev-master", + "php-http/psr7-integration-tests": "dev-master", + "phpunit/phpunit": "^7.5" + }, + "time": "2019-09-05T13:24:16+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Nyholm\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com" + }, + { + "name": "Martijn van der Ven", + "email": "martijn@vanderven.se" + } + ], + "description": "A fast PHP7 implementation of PSR-7", + "homepage": "http://tnyholm.se", + "keywords": [ + "psr-17", + "psr-7" + ] + }, + { + "name": "paragonie/random_compat", + "version": "v9.99.99", + "version_normalized": "9.99.99.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", + "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", + "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." + }, + "time": "2018-07-02T15:55:56+00:00", + "type": "library", + "installation-source": "dist", + "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" + ] + }, + { + "name": "php-http/message-factory", + "version": "v1.0.2", + "version_normalized": "1.0.2.0", + "source": { + "type": "git", + "url": "https://github.com/php-http/message-factory.git", + "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/message-factory/zipball/a478cb11f66a6ac48d8954216cfed9aa06a501a1", + "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "psr/http-message": "^1.0" + }, + "time": "2015-12-19T14:08:53+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "Factory interfaces for PSR-7 HTTP Message", + "homepage": "http://php-http.org", + "keywords": [ + "factory", + "http", + "message", + "stream", + "uri" + ] + }, + { + "name": "psr/http-client", + "version": "1.0.0", + "version_normalized": "1.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "496a823ef742b632934724bf769560c2a5c7c44e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/496a823ef742b632934724bf769560c2a5c7c44e", + "reference": "496a823ef742b632934724bf769560c2a5c7c44e", + "shasum": "" + }, + "require": { + "php": "^7.0", + "psr/http-message": "^1.0" + }, + "time": "2018-10-30T23:29:13+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ] + }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "time": "2019-04-30T12:38:16+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ] + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2016-08-06T14:39:51+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ] + }, + { + "name": "ramsey/uuid", + "version": "3.8.0", + "version_normalized": "3.8.0.0", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid.git", + "reference": "d09ea80159c1929d75b3f9c60504d613aeb4a1e3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/d09ea80159c1929d75b3f9c60504d613aeb4a1e3", + "reference": "d09ea80159c1929d75b3f9c60504d613aeb4a1e3", + "shasum": "" + }, + "require": { + "paragonie/random_compat": "^1.0|^2.0|9.99.99", + "php": "^5.4 || ^7.0", + "symfony/polyfill-ctype": "^1.8" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "codeception/aspect-mock": "^1.0 | ~2.0.0", + "doctrine/annotations": "~1.2.0", + "goaop/framework": "1.0.0-alpha.2 | ^1.0 | ~2.1.0", + "ircmaxell/random-lib": "^1.1", + "jakub-onderka/php-parallel-lint": "^0.9.0", + "mockery/mockery": "^0.9.9", + "moontoast/math": "^1.1", + "php-mock/php-mock-phpunit": "^0.3|^1.1", + "phpunit/phpunit": "^4.7|^5.0|^6.5", + "squizlabs/php_codesniffer": "^2.3" + }, + "suggest": { + "ext-ctype": "Provides support for PHP Ctype functions", + "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator", + "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator", + "ircmaxell/random-lib": "Provides RandomLib for use with the RandomLibAdapter", + "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).", + "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid", + "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." + }, + "time": "2018-07-19T23:38:55+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Ramsey\\Uuid\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marijn Huizendveld", + "email": "marijn.huizendveld@gmail.com" + }, + { + "name": "Thibaud Fabre", + "email": "thibaud@aztech.io" + }, + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + } + ], + "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).", + "homepage": "https://github.com/ramsey/uuid", + "keywords": [ + "guid", + "identifier", + "uuid" + ] + }, + { + "name": "spomky-labs/base64url", + "version": "v2.0.1", + "version_normalized": "2.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/Spomky-Labs/base64url.git", + "reference": "3eb46a1de803f0078962d910e3a2759224a68c61" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Spomky-Labs/base64url/zipball/3eb46a1de803f0078962d910e3a2759224a68c61", + "reference": "3eb46a1de803f0078962d910e3a2759224a68c61", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.0", + "phpunit/phpunit": "^7.0" + }, + "time": "2018-08-16T15:44:20+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Base64Url\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky-Labs/base64url/contributors" + } + ], + "description": "Base 64 URL Safe Encoding/Decoding PHP Library", + "homepage": "https://github.com/Spomky-Labs/base64url", + "keywords": [ + "base64", + "rfc4648", + "safe", + "url" + ] + }, + { + "name": "spomky-labs/cbor-php", + "version": "v1.0.7", + "version_normalized": "1.0.7.0", + "source": { + "type": "git", + "url": "https://github.com/Spomky-Labs/cbor-php.git", + "reference": "f937d527b05bb3ec3f6b8670ece38ccaf9a0eddd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Spomky-Labs/cbor-php/zipball/f937d527b05bb3ec3f6b8670ece38ccaf9a0eddd", + "reference": "f937d527b05bb3ec3f6b8670ece38ccaf9a0eddd", + "shasum": "" + }, + "require": { + "beberlei/assert": "^3.2", + "ext-gmp": "*", + "php": "^7.1|^8.0", + "spomky-labs/base64url": "^1.0|^2.0" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.0", + "phpstan/phpstan": "^0.11", + "phpstan/phpstan-beberlei-assert": "^0.11.0", + "phpstan/phpstan-deprecation-rules": "^0.11", + "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-strict-rules": "^0.11", + "phpunit/phpunit": "^7.5|^8.0", + "rector/rector": "^0.5" + }, + "suggest": { + "ext-bcmath": "BCMath extension needed to handle the Big Float and Decimal Fraction Tags" + }, + "time": "2019-08-15T14:53:55+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "CBOR\\": "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/Spomky-Labs/cbor-php/contributors" + } + ], + "description": "CBOR Encoder/Decoder for PHP", + "keywords": [ + "Concise Binary Object Representation", + "RFC7049", + "cbor" + ] + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.12.0", + "version_normalized": "1.12.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "550ebaac289296ce228a706d0867afc34687e3f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/550ebaac289296ce228a706d0867afc34687e3f4", + "reference": "550ebaac289296ce228a706d0867afc34687e3f4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "time": "2019-08-06T08:03:45+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.12-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "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" + ] + }, + { + "name": "web-auth/cose-lib", + "version": "v2.1.7", + "version_normalized": "2.1.7.0", + "source": { + "type": "git", + "url": "https://github.com/web-auth/cose-lib.git", + "reference": "8d1c37bac6e5db8d502b7735448d416f05fb4c70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/web-auth/cose-lib/zipball/8d1c37bac6e5db8d502b7735448d416f05fb4c70", + "reference": "8d1c37bac6e5db8d502b7735448d416f05fb4c70", + "shasum": "" + }, + "require": { + "beberlei/assert": "^3.0", + "ext-json": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "fgrosse/phpasn1": "^2.1", + "php": "^7.2" + }, + "time": "2019-09-04T20:53:12+00:00", + "type": "library", + "extra": { + "branch-alias": { + "v1.0": "1.0.x-dev", + "v1.1": "1.1.x-dev", + "v1.2": "1.2.x-dev", + "v2.0": "2.0.x-dev", + "v2.1": "2.1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Cose\\": "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/cose/contributors" + } + ], + "description": "CBOR Object Signing and Encryption (COSE) For PHP", + "homepage": "https://github.com/web-auth", + "keywords": [ + "COSE", + "RFC8152" + ] + }, + { + "name": "web-auth/metadata-service", + "version": "v2.1.7", + "version_normalized": "2.1.7.0", + "source": { + "type": "git", + "url": "https://github.com/web-auth/webauthn-metadata-service.git", + "reference": "5fc754d00dfa05913260dc3781227dfa8ed7dbdd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/web-auth/webauthn-metadata-service/zipball/5fc754d00dfa05913260dc3781227dfa8ed7dbdd", + "reference": "5fc754d00dfa05913260dc3781227dfa8ed7dbdd", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.1", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0" + }, + "time": "2019-09-04T20:53:12+00:00", + "type": "library", + "extra": { + "branch-alias": { + "v2.1": "2.1.x-dev" + } + }, + "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" + ] + }, + { + "name": "web-auth/webauthn-lib", + "version": "v2.1.7", + "version_normalized": "2.1.7.0", + "source": { + "type": "git", + "url": "https://github.com/web-auth/webauthn-lib.git", + "reference": "4cd346f2ef4d282296e503b7b1b3ef200347437b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/web-auth/webauthn-lib/zipball/4cd346f2ef4d282296e503b7b1b3ef200347437b", + "reference": "4cd346f2ef4d282296e503b7b1b3ef200347437b", + "shasum": "" + }, + "require": { + "beberlei/assert": "^3.0", + "ext-json": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "nyholm/psr7": "^1.1", + "php": "^7.2", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "ramsey/uuid": "^3.8", + "spomky-labs/base64url": "^2.0", + "spomky-labs/cbor-php": "^1.0.2", + "web-auth/cose-lib": "self.version", + "web-auth/metadata-service": "self.version" + }, + "suggest": { + "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" + }, + "time": "2019-09-09T12:04:09+00:00", + "type": "library", + "extra": { + "branch-alias": { + "v1.0": "1.0.x-dev", + "v1.1": "1.1.x-dev", + "v1.2": "1.2.x-dev", + "v2.0": "2.0.x-dev", + "v2.1": "2.1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Webauthn\\": "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/webauthn-library/contributors" + } + ], + "description": "FIDO2/Webauthn Support For PHP", + "homepage": "https://github.com/web-auth", + "keywords": [ + "FIDO2", + "fido", + "webauthn" + ] + } +] diff --git a/lam/lib/3rdParty/composer/fgrosse/phpasn1/CHANGELOG.md b/lam/lib/3rdParty/composer/fgrosse/phpasn1/CHANGELOG.md new file mode 100644 index 00000000..053edc2d --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/CHANGELOG.md @@ -0,0 +1,38 @@ +#### v.2.1.0 (2018-03) +* add support for `bcmath` extension (making `gmp` optional)
+ 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 new file mode 100644 index 00000000..1e17eb03 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/LICENSE @@ -0,0 +1,19 @@ +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 new file mode 100644 index 00000000..3931010a --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/README.md @@ -0,0 +1,167 @@ +PHPASN1 +======= + +[![Build Status](https://secure.travis-ci.org/fgrosse/PHPASN1.png?branch=master)](http://travis-ci.org/fgrosse/PHPASN1) +[![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) + +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? + +If you found an issue or have a question submit a github issue with detailed information. + +In case you already know what caused the issue and feel in the mood to fix it, your code contributions are always welcome. Just fork the repository, implement your changes and make sure that you covered everything with tests. +Afterwards submit a pull request via github and be a little patient :) I usually try to comment and/or merge as soon as possible. + +#### Mailing list + +New features or questions can be discussed in [this google group/mailing list][12]. + +### 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 new file mode 100644 index 00000000..079e07e5 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/composer.json @@ -0,0 +1,47 @@ +{ + "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.0.0" + }, + "require-dev": { + "phpunit/phpunit": "~6.3", + "satooshi/php-coveralls": "~2.0" + }, + "suggest": { + "ext-gmp": "GMP is the preferred extension for big integer calculations", + "php-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 new file mode 100644 index 00000000..3b7f1621 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/ASNObject.php @@ -0,0 +1,355 @@ + + * + * 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 new file mode 100644 index 00000000..7e0d7ddb --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/AbstractString.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 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 new file mode 100644 index 00000000..9fad5051 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/AbstractTime.php @@ -0,0 +1,78 @@ + + * + * 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(); + 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 new file mode 100644 index 00000000..119ee7b9 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Base128.php @@ -0,0 +1,63 @@ +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 new file mode 100644 index 00000000..3f4027c2 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Composite/AttributeTypeAndValue.php @@ -0,0 +1,35 @@ + + * + * 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 new file mode 100644 index 00000000..e95e7acd --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Composite/RDNString.php @@ -0,0 +1,37 @@ + + * + * 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 new file mode 100644 index 00000000..4185f41a --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Composite/RelativeDistinguishedName.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 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 new file mode 100644 index 00000000..58f96137 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Construct.php @@ -0,0 +1,191 @@ + + * + * 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; + } + + public function rewind() + { + $this->iteratorPosition = 0; + } + + public function current() + { + return $this->children[$this->iteratorPosition]; + } + + public function key() + { + return $this->iteratorPosition; + } + + public function next() + { + $this->iteratorPosition++; + } + + public function valid() + { + return isset($this->children[$this->iteratorPosition]); + } + + public function offsetExists($offset) + { + return array_key_exists($offset, $this->children); + } + + public function offsetGet($offset) + { + return $this->children[$offset]; + } + + public function offsetSet($offset, $value) + { + if ($offset === null) { + $offset = count($this->children); + } + + $this->children[$offset] = $value; + } + + 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 + */ + 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; + } + + public function count($mode = COUNT_NORMAL) + { + return count($this->children, $mode); + } + + public function getIterator() + { + return new ArrayIterator($this->children); + } +} 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 new file mode 100644 index 00000000..c9f8e82e --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Exception/NotImplementedException.php @@ -0,0 +1,15 @@ + + * + * 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 new file mode 100644 index 00000000..4bda4e87 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Exception/ParserException.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 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 new file mode 100644 index 00000000..b947a959 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/ExplicitlyTaggedObject.php @@ -0,0 +1,131 @@ + + * + * 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 new file mode 100644 index 00000000..b21caa34 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Identifier.php @@ -0,0 +1,339 @@ + + * + * 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 new file mode 100644 index 00000000..61ab01e1 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/OID.php @@ -0,0 +1,198 @@ + + * + * 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 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) + { + 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 new file mode 100644 index 00000000..fa66b558 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Parsable.php @@ -0,0 +1,32 @@ + + * + * 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 new file mode 100644 index 00000000..90a40b03 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/TemplateParser.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 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 new file mode 100644 index 00000000..83ec6a91 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/BMPString.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 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 new file mode 100644 index 00000000..226695c5 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/BitString.php @@ -0,0 +1,88 @@ + + * + * 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 new file mode 100644 index 00000000..b73c99f1 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Boolean.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 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 new file mode 100644 index 00000000..bfc170db --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/CharacterString.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 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 new file mode 100644 index 00000000..06d04a3a --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Enumerated.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 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 new file mode 100644 index 00000000..fb0346f0 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GeneralString.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 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 new file mode 100644 index 00000000..ca922097 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GeneralizedTime.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 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 new file mode 100644 index 00000000..4a01d67b --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GraphicString.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 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 new file mode 100644 index 00000000..33a80679 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/IA5String.php @@ -0,0 +1,35 @@ + + * + * 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 new file mode 100644 index 00000000..fe3806ba --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Integer.php @@ -0,0 +1,130 @@ + + * + * 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 new file mode 100644 index 00000000..b5293e4b --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/NullObject.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 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 new file mode 100644 index 00000000..13fb7c34 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/NumericString.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 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 new file mode 100644 index 00000000..1c5d3498 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/ObjectDescriptor.php @@ -0,0 +1,26 @@ + + * + * 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 new file mode 100644 index 00000000..150ce9c4 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/ObjectIdentifier.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 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 new file mode 100644 index 00000000..5d69ae7b --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/OctetString.php @@ -0,0 +1,91 @@ + + * + * 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 new file mode 100644 index 00000000..fe6d4bc0 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/PrintableString.php @@ -0,0 +1,53 @@ + + * + * 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 new file mode 100644 index 00000000..2aa9643a --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/RelativeObjectIdentifier.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 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 new file mode 100644 index 00000000..0397cf12 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Sequence.php @@ -0,0 +1,23 @@ + + * + * 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 new file mode 100644 index 00000000..6e6d346f --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Set.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 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 new file mode 100644 index 00000000..56418645 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/T61String.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 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 new file mode 100644 index 00000000..c4d303cb --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/UTCTime.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 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 new file mode 100644 index 00000000..cba568d3 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/UTF8String.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 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 new file mode 100644 index 00000000..0c3fe1d0 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/UniversalString.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 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 new file mode 100644 index 00000000..d9326d3f --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/VisibleString.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 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 new file mode 100644 index 00000000..b19a07a1 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/UnknownConstructedObject.php @@ -0,0 +1,59 @@ + + * + * 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 new file mode 100644 index 00000000..4ac536a9 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/UnknownObject.php @@ -0,0 +1,59 @@ + + * + * 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 new file mode 100644 index 00000000..77ab5575 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/Utility/BigInteger.php @@ -0,0 +1,197 @@ +_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 new file mode 100644 index 00000000..25ad8916 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/Utility/BigIntegerBcmath.php @@ -0,0 +1,133 @@ +_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 new file mode 100644 index 00000000..0791226a --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/Utility/BigIntegerGmp.php @@ -0,0 +1,133 @@ +_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 new file mode 100644 index 00000000..a06b56f7 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/AlgorithmIdentifier.php @@ -0,0 +1,22 @@ + + * + * 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 new file mode 100644 index 00000000..5a965e2f --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CSR/Attributes.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 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 new file mode 100644 index 00000000..69decdbb --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CSR/CSR.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 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, $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; + + $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); + + $this->addChild($certRequestInfo); + $this->addChild($signatureAlgorithm); + $this->addChild($signature); + } + + 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 new file mode 100644 index 00000000..6ed1c6a7 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CertificateExtensions.php @@ -0,0 +1,100 @@ + + * + * 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 new file mode 100644 index 00000000..0a04d574 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CertificateSubject.php @@ -0,0 +1,108 @@ + + * + * 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 new file mode 100644 index 00000000..d57ad865 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/PrivateKey.php @@ -0,0 +1,35 @@ + + * + * 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 new file mode 100644 index 00000000..ab8b4514 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/PublicKey.php @@ -0,0 +1,35 @@ + + * + * 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 new file mode 100644 index 00000000..502738b0 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/SAN/DNSName.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 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 new file mode 100644 index 00000000..f55be95b --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/SAN/IPAddress.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 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 new file mode 100644 index 00000000..271ddde7 --- /dev/null +++ b/lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/SAN/SubjectAlternativeNames.php @@ -0,0 +1,96 @@ + + * + * 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/nyholm/psr7/CHANGELOG.md b/lam/lib/3rdParty/composer/nyholm/psr7/CHANGELOG.md new file mode 100644 index 00000000..28f17afa --- /dev/null +++ b/lam/lib/3rdParty/composer/nyholm/psr7/CHANGELOG.md @@ -0,0 +1,85 @@ +# Changelog + +All notable changes to this project will be documented in this file, in reverse chronological order by release. + +## 1.2.1 + +### Changed + +- Added `.github` and `phpstan.neon.dist` to `.gitattributes`. + +## 1.2.0 + +### Changed + +- Change minimal port number to 0 (unix socket) +- Updated `Psr17Factory::createResponse` to respect the specification. If second + argument is not used, a standard reason phrase. If an empty string is passed, + then the reason phrase will be empty. + +### Fixed + +- Check for seekable on the stream resource. +- Fixed the `Response::$reason` should never be null. + +## 1.1.0 + +### Added + +- Improved performance +- More tests for `UploadedFile` and `HttplugFactory` + +### Removed + +- Dead code + +## 1.0.1 + +### Fixed + +- Handle `fopen` failing in createStreamFromFile according to PSR-7. +- Reduce execution path to speed up performance. +- Fixed typos. +- Code style. + +## 1.0.0 + +### Added + +- Support for final PSR-17 (HTTP factories). (`Psr17Factory`) +- Support for numeric header values. +- Support for empty header values. +- All classes are final +- `HttplugFactory` that implements factory interfaces from HTTPlug. + +### Changed + +- `ServerRequest` does not extend `Request`. + +### Removed + +- The HTTPlug discovery strategy was removed since it is included in php-http/discovery 1.4. +- `UploadedFileFactory()` was removed in favor for `Psr17Factory`. +- `ServerRequestFactory()` was removed in favor for `Psr17Factory`. +- `StreamFactory`, `UriFactory`, abd `MessageFactory`. Use `HttplugFactory` instead. +- `ServerRequestFactory::createServerRequestFromArray`, `ServerRequestFactory::createServerRequestFromArrays` and + `ServerRequestFactory::createServerRequestFromGlobals`. Please use the new `nyholm/psr7-server` instead. + +## 0.3.0 + +### Added + +- Return types. +- Many `InvalidArgumentException`s are thrown when you use invalid arguments. +- Integration tests for `UploadedFile` and `ServerRequest`. + +### Changed + +- We dropped PHP7.0 support. +- PSR-17 factories have been marked as internal. They do not fall under our BC promise until PSR-17 is accepted. +- `UploadedFileFactory::createUploadedFile` does not accept a string file path. + +## 0.2.3 + +No changelog before this release + diff --git a/lam/lib/3rdParty/composer/nyholm/psr7/LICENSE b/lam/lib/3rdParty/composer/nyholm/psr7/LICENSE new file mode 100644 index 00000000..d6c52312 --- /dev/null +++ b/lam/lib/3rdParty/composer/nyholm/psr7/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 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/nyholm/psr7/README.md b/lam/lib/3rdParty/composer/nyholm/psr7/README.md new file mode 100644 index 00000000..d626853b --- /dev/null +++ b/lam/lib/3rdParty/composer/nyholm/psr7/README.md @@ -0,0 +1,111 @@ +# PSR-7 implementation + +[![Latest Version](https://img.shields.io/github/release/Nyholm/psr7.svg?style=flat-square)](https://github.com/Nyholm/psr7/releases) +[![Build Status](https://img.shields.io/travis/Nyholm/psr7/master.svg?style=flat-square)](https://travis-ci.org/Nyholm/psr7) +[![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/Nyholm/psr7.svg?style=flat-square)](https://scrutinizer-ci.com/g/Nyholm/psr7) +[![Quality Score](https://img.shields.io/scrutinizer/g/Nyholm/psr7.svg?style=flat-square)](https://scrutinizer-ci.com/g/Nyholm/psr7) +[![Total Downloads](https://poser.pugx.org/nyholm/psr7/downloads)](https://packagist.org/packages/nyholm/psr7) +[![Monthly Downloads](https://poser.pugx.org/nyholm/psr7/d/monthly.png)](https://packagist.org/packages/nyholm/psr7) +[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE) + + +A super lightweight PSR-7 implementation. Very strict and very fast. + +| Description | Guzzle | Zend | Slim | Nyholm | +| ---- | ------ | ---- | ---- | ------ | +| Lines of code | 3 000 | 3 000 | 1 700 | 1 000 | +| PHP7 | No | Yes | No | Yes | +| PSR-7* | 66% | 100% | 75% | 100% | +| PSR-17 | No | Yes | Yes | Yes | +| HTTPlug | No | No | No | Yes | +| Performance** | 1.34x | 1x | 1.16x | 1.75x | + +\* Percent of completed tests in https://github.com/php-http/psr7-integration-tests + +\** See benchmark at https://github.com/Nyholm/http-client-benchmark (higher is better) + +## Installation + +```bash +composer require nyholm/psr7 +``` + +If you are using Symfony Flex then you get all message factories registered as services. + +## Usage + +The PSR-7 objects do not contain any other public methods than those defined in +the [PSR-7 specification](https://www.php-fig.org/psr/psr-7/). + +### Create objects + +Use the PSR-17 factory to create requests, streams, URIs etc. + +```php +$psr17Factory = new \Nyholm\Psr7\Factory\Psr17Factory(); +$request = $psr17Factory->createRequest('GET', 'http://tnyholm.se'); +$stream = $psr17Factory->createStream('foobar'); +``` + +### Sending a request + +With [HTTPlug](http://httplug.io/) or any other PSR-18 (HTTP client) you may send +requests like: + +```bash +composer require kriswallsmith/buzz +``` + +```php +$psr17Factory = new \Nyholm\Psr7\Factory\Psr17Factory(); +$psr18Client = new \Buzz\Client\Curl($psr17Factory); + +$request = $psr17Factory->createRequest('GET', 'http://tnyholm.se'); +$response = $psr18Client->sendRequest($request); +``` + +### Create server requests + +The [`nyholm/psr7-server`](https://github.com/Nyholm/psr7-server) package can be used +to create server requests from PHP superglobals. + +```bash +composer require nyholm/psr7-server +``` + +```php +$psr17Factory = new \Nyholm\Psr7\Factory\Psr17Factory(); + +$creator = new \Nyholm\Psr7Server\ServerRequestCreator( + $psr17Factory, // ServerRequestFactory + $psr17Factory, // UriFactory + $psr17Factory, // UploadedFileFactory + $psr17Factory // StreamFactory +); + +$serverRequest = $creator->fromGlobals(); +``` + +### Emitting a response + +```bash +composer require zendframework/zend-httphandlerrunner +``` + +```php +$psr17Factory = new \Nyholm\Psr7\Factory\Psr17Factory(); + +$responseBody = $psr17Factory->createStream('Hello world'); +$response = $psr17Factory->createResponse(200)->withBody($responseBody); +(new \Zend\HttpHandlerRunner\Emitter\SapiEmitter())->emit($response); +``` + +## Our goal + +This package is currently maintained by [Tobias Nyholm](http://nyholm.se) and +[Martijn van der Ven](https://vanderven.se/martijn/). They have decided that the +goal of this library should be to provide a super strict implementation of +[PSR-7](https://www.php-fig.org/psr/psr-7/) that is blazing fast. + +The package will never include any extra features nor helper methods. All our classes +and functions exist because they are required to fulfill the PSR-7 specification. diff --git a/lam/lib/3rdParty/composer/nyholm/psr7/composer.json b/lam/lib/3rdParty/composer/nyholm/psr7/composer.json new file mode 100644 index 00000000..569cf14f --- /dev/null +++ b/lam/lib/3rdParty/composer/nyholm/psr7/composer.json @@ -0,0 +1,51 @@ +{ + "name": "nyholm/psr7", + "description": "A fast PHP7 implementation of PSR-7", + "license": "MIT", + "keywords": ["psr-7", "psr-17"], + "homepage": "http://tnyholm.se", + "authors": [ + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com" + }, + { + "name": "Martijn van der Ven", + "email": "martijn@vanderven.se" + } + ], + "require": { + "php": "^7.1", + "psr/http-message": "^1.0", + "php-http/message-factory": "^1.0", + "psr/http-factory": "^1.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.5", + "php-http/psr7-integration-tests": "dev-master", + "http-interop/http-factory-tests": "dev-master" + }, + "provide": { + "psr/http-message-implementation": "1.0", + "psr/http-factory-implementation": "1.0" + }, + "autoload": { + "psr-4": { + "Nyholm\\Psr7\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\Nyholm\\Psr7\\": "tests/" + } + }, + "scripts": { + "test": "vendor/bin/phpunit", + "test-ci": "vendor/bin/phpunit --coverage-text --coverage-clover=build/coverage.xml" + }, + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + } +} diff --git a/lam/lib/3rdParty/composer/nyholm/psr7/src/Factory/HttplugFactory.php b/lam/lib/3rdParty/composer/nyholm/psr7/src/Factory/HttplugFactory.php new file mode 100644 index 00000000..a2965414 --- /dev/null +++ b/lam/lib/3rdParty/composer/nyholm/psr7/src/Factory/HttplugFactory.php @@ -0,0 +1,40 @@ + + * @author Martijn van der Ven + */ +final class HttplugFactory implements MessageFactory, StreamFactory, UriFactory +{ + public function createRequest($method, $uri, array $headers = [], $body = null, $protocolVersion = '1.1') + { + return new Request($method, $uri, $headers, $body, $protocolVersion); + } + + public function createResponse($statusCode = 200, $reasonPhrase = null, array $headers = [], $body = null, $version = '1.1') + { + return new Response((int) $statusCode, $headers, $body, $version, $reasonPhrase); + } + + public function createStream($body = null) + { + return Stream::create($body ?? ''); + } + + public function createUri($uri = ''): UriInterface + { + if ($uri instanceof UriInterface) { + return $uri; + } + + return new Uri($uri); + } +} diff --git a/lam/lib/3rdParty/composer/nyholm/psr7/src/Factory/Psr17Factory.php b/lam/lib/3rdParty/composer/nyholm/psr7/src/Factory/Psr17Factory.php new file mode 100644 index 00000000..08caf857 --- /dev/null +++ b/lam/lib/3rdParty/composer/nyholm/psr7/src/Factory/Psr17Factory.php @@ -0,0 +1,73 @@ + + * @author Martijn van der Ven + */ +final class Psr17Factory implements RequestFactoryInterface, ResponseFactoryInterface, ServerRequestFactoryInterface, StreamFactoryInterface, UploadedFileFactoryInterface, UriFactoryInterface +{ + public function createRequest(string $method, $uri): RequestInterface + { + return new Request($method, $uri); + } + + public function createResponse(int $code = 200, string $reasonPhrase = ''): ResponseInterface + { + if (2 > \func_num_args()) { + // This will make the Response class to use a custom reasonPhrase + $reasonPhrase = null; + } + + return new Response($code, [], null, '1.1', $reasonPhrase); + } + + public function createStream(string $content = ''): StreamInterface + { + return Stream::create($content); + } + + public function createStreamFromFile(string $filename, string $mode = 'r'): StreamInterface + { + $resource = @\fopen($filename, $mode); + if (false === $resource) { + if ('' === $mode || false === \in_array($mode[0], ['r', 'w', 'a', 'x', 'c'])) { + throw new \InvalidArgumentException('The mode ' . $mode . ' is invalid.'); + } + + throw new \RuntimeException('The file ' . $filename . ' cannot be opened.'); + } + + return Stream::create($resource); + } + + public function createStreamFromResource($resource): StreamInterface + { + return Stream::create($resource); + } + + public function createUploadedFile(StreamInterface $stream, int $size = null, int $error = \UPLOAD_ERR_OK, string $clientFilename = null, string $clientMediaType = null): UploadedFileInterface + { + if (null === $size) { + $size = $stream->getSize(); + } + + return new UploadedFile($stream, $size, $error, $clientFilename, $clientMediaType); + } + + public function createUri(string $uri = ''): UriInterface + { + return new Uri($uri); + } + + public function createServerRequest(string $method, $uri, array $serverParams = []): ServerRequestInterface + { + return new ServerRequest($method, $uri, [], null, '1.1', $serverParams); + } +} diff --git a/lam/lib/3rdParty/composer/nyholm/psr7/src/MessageTrait.php b/lam/lib/3rdParty/composer/nyholm/psr7/src/MessageTrait.php new file mode 100644 index 00000000..d1e93cc1 --- /dev/null +++ b/lam/lib/3rdParty/composer/nyholm/psr7/src/MessageTrait.php @@ -0,0 +1,202 @@ + + * @author Martijn van der Ven + * + * @internal should not be used outside of Nyholm/Psr7 as it does not fall under our BC promise + */ +trait MessageTrait +{ + /** @var array Map of all registered headers, as original name => array of values */ + private $headers = []; + + /** @var array Map of lowercase header name => original name at registration */ + private $headerNames = []; + + /** @var string */ + private $protocol = '1.1'; + + /** @var StreamInterface|null */ + private $stream; + + public function getProtocolVersion(): string + { + return $this->protocol; + } + + public function withProtocolVersion($version): self + { + if ($this->protocol === $version) { + return $this; + } + + $new = clone $this; + $new->protocol = $version; + + return $new; + } + + public function getHeaders(): array + { + return $this->headers; + } + + public function hasHeader($header): bool + { + return isset($this->headerNames[\strtolower($header)]); + } + + public function getHeader($header): array + { + $header = \strtolower($header); + if (!isset($this->headerNames[$header])) { + return []; + } + + $header = $this->headerNames[$header]; + + return $this->headers[$header]; + } + + public function getHeaderLine($header): string + { + return \implode(', ', $this->getHeader($header)); + } + + public function withHeader($header, $value): self + { + $value = $this->validateAndTrimHeader($header, $value); + $normalized = \strtolower($header); + + $new = clone $this; + if (isset($new->headerNames[$normalized])) { + unset($new->headers[$new->headerNames[$normalized]]); + } + $new->headerNames[$normalized] = $header; + $new->headers[$header] = $value; + + return $new; + } + + public function withAddedHeader($header, $value): self + { + if (!\is_string($header) || '' === $header) { + throw new \InvalidArgumentException('Header name must be an RFC 7230 compatible string.'); + } + + $new = clone $this; + $new->setHeaders([$header => $value]); + + return $new; + } + + public function withoutHeader($header): self + { + $normalized = \strtolower($header); + if (!isset($this->headerNames[$normalized])) { + return $this; + } + + $header = $this->headerNames[$normalized]; + $new = clone $this; + unset($new->headers[$header], $new->headerNames[$normalized]); + + return $new; + } + + public function getBody(): StreamInterface + { + if (null === $this->stream) { + $this->stream = Stream::create(''); + } + + return $this->stream; + } + + public function withBody(StreamInterface $body): self + { + if ($body === $this->stream) { + return $this; + } + + $new = clone $this; + $new->stream = $body; + + return $new; + } + + private function setHeaders(array $headers): void + { + foreach ($headers as $header => $value) { + $value = $this->validateAndTrimHeader($header, $value); + $normalized = \strtolower($header); + if (isset($this->headerNames[$normalized])) { + $header = $this->headerNames[$normalized]; + $this->headers[$header] = \array_merge($this->headers[$header], $value); + } else { + $this->headerNames[$normalized] = $header; + $this->headers[$header] = $value; + } + } + } + + /** + * Make sure the header complies with RFC 7230. + * + * Header names must be a non-empty string consisting of token characters. + * + * Header values must be strings consisting of visible characters with all optional + * leading and trailing whitespace stripped. This method will always strip such + * optional whitespace. Note that the method does not allow folding whitespace within + * the values as this was deprecated for almost all instances by the RFC. + * + * header-field = field-name ":" OWS field-value OWS + * field-name = 1*( "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / "^" + * / "_" / "`" / "|" / "~" / %x30-39 / ( %x41-5A / %x61-7A ) ) + * OWS = *( SP / HTAB ) + * field-value = *( ( %x21-7E / %x80-FF ) [ 1*( SP / HTAB ) ( %x21-7E / %x80-FF ) ] ) + * + * @see https://tools.ietf.org/html/rfc7230#section-3.2.4 + */ + private function validateAndTrimHeader($header, $values): array + { + if (!\is_string($header) || 1 !== \preg_match("@^[!#$%&'*+.^_`|~0-9A-Za-z-]+$@", $header)) { + throw new \InvalidArgumentException('Header name must be an RFC 7230 compatible string.'); + } + + if (!\is_array($values)) { + // This is simple, just one value. + if ((!\is_numeric($values) && !\is_string($values)) || 1 !== \preg_match("@^[ \t\x21-\x7E\x80-\xFF]*$@", (string) $values)) { + throw new \InvalidArgumentException('Header values must be RFC 7230 compatible strings.'); + } + + return [\trim((string) $values, " \t")]; + } + + if (empty($values)) { + throw new \InvalidArgumentException('Header values must be a string or an array of strings, empty array given.'); + } + + // Assert Non empty array + $returnValues = []; + foreach ($values as $v) { + if ((!\is_numeric($v) && !\is_string($v)) || 1 !== \preg_match("@^[ \t\x21-\x7E\x80-\xFF]*$@", (string) $v)) { + throw new \InvalidArgumentException('Header values must be RFC 7230 compatible strings.'); + } + + $returnValues[] = \trim((string) $v, " \t"); + } + + return $returnValues; + } +} diff --git a/lam/lib/3rdParty/composer/nyholm/psr7/src/Request.php b/lam/lib/3rdParty/composer/nyholm/psr7/src/Request.php new file mode 100644 index 00000000..84a9f2ab --- /dev/null +++ b/lam/lib/3rdParty/composer/nyholm/psr7/src/Request.php @@ -0,0 +1,45 @@ + + * @author Martijn van der Ven + */ +final class Request implements RequestInterface +{ + use MessageTrait; + use RequestTrait; + + /** + * @param string $method HTTP method + * @param string|UriInterface $uri URI + * @param array $headers Request headers + * @param string|resource|StreamInterface|null $body Request body + * @param string $version Protocol version + */ + public function __construct(string $method, $uri, array $headers = [], $body = null, string $version = '1.1') + { + if (!($uri instanceof UriInterface)) { + $uri = new Uri($uri); + } + + $this->method = $method; + $this->uri = $uri; + $this->setHeaders($headers); + $this->protocol = $version; + + if (!$this->hasHeader('Host')) { + $this->updateHostFromUri(); + } + + // If we got no body, defer initialization of the stream until Request::getBody() + if ('' !== $body && null !== $body) { + $this->stream = Stream::create($body); + } + } +} diff --git a/lam/lib/3rdParty/composer/nyholm/psr7/src/RequestTrait.php b/lam/lib/3rdParty/composer/nyholm/psr7/src/RequestTrait.php new file mode 100644 index 00000000..f39993a1 --- /dev/null +++ b/lam/lib/3rdParty/composer/nyholm/psr7/src/RequestTrait.php @@ -0,0 +1,113 @@ + + * @author Martijn van der Ven + * + * @internal should not be used outside of Nyholm/Psr7 as it does not fall under our BC promise + */ +trait RequestTrait +{ + /** @var string */ + private $method; + + /** @var string|null */ + private $requestTarget; + + /** @var UriInterface|null */ + private $uri; + + public function getRequestTarget(): string + { + if (null !== $this->requestTarget) { + return $this->requestTarget; + } + + if ('' === $target = $this->uri->getPath()) { + $target = '/'; + } + if ('' !== $this->uri->getQuery()) { + $target .= '?' . $this->uri->getQuery(); + } + + return $target; + } + + public function withRequestTarget($requestTarget): self + { + if (\preg_match('#\s#', $requestTarget)) { + throw new \InvalidArgumentException('Invalid request target provided; cannot contain whitespace'); + } + + $new = clone $this; + $new->requestTarget = $requestTarget; + + return $new; + } + + public function getMethod(): string + { + return $this->method; + } + + public function withMethod($method): self + { + if (!\is_string($method)) { + throw new \InvalidArgumentException('Method must be a string'); + } + + $new = clone $this; + $new->method = $method; + + return $new; + } + + public function getUri(): UriInterface + { + return $this->uri; + } + + public function withUri(UriInterface $uri, $preserveHost = false): self + { + if ($uri === $this->uri) { + return $this; + } + + $new = clone $this; + $new->uri = $uri; + + if (!$preserveHost || !$this->hasHeader('Host')) { + $new->updateHostFromUri(); + } + + return $new; + } + + private function updateHostFromUri(): void + { + if ('' === $host = $this->uri->getHost()) { + return; + } + + if (null !== ($port = $this->uri->getPort())) { + $host .= ':' . $port; + } + + if (isset($this->headerNames['host'])) { + $header = $this->headerNames['host']; + } else { + $this->headerNames['host'] = $header = 'Host'; + } + + // Ensure Host is the first header. + // See: http://tools.ietf.org/html/rfc7230#section-5.4 + $this->headers = [$header => [$host]] + $this->headers; + } +} diff --git a/lam/lib/3rdParty/composer/nyholm/psr7/src/Response.php b/lam/lib/3rdParty/composer/nyholm/psr7/src/Response.php new file mode 100644 index 00000000..a75e93c3 --- /dev/null +++ b/lam/lib/3rdParty/composer/nyholm/psr7/src/Response.php @@ -0,0 +1,88 @@ + + * @author Martijn van der Ven + */ +final class Response implements ResponseInterface +{ + use MessageTrait; + + /** @var array Map of standard HTTP status code/reason phrases */ + private const PHRASES = [ + 100 => 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', + 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 207 => 'Multi-status', 208 => 'Already Reported', + 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 306 => 'Switch Proxy', 307 => 'Temporary Redirect', + 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Time-out', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', 417 => 'Expectation Failed', 418 => 'I\'m a teapot', 422 => 'Unprocessable Entity', 423 => 'Locked', 424 => 'Failed Dependency', 425 => 'Unordered Collection', 426 => 'Upgrade Required', 428 => 'Precondition Required', 429 => 'Too Many Requests', 431 => 'Request Header Fields Too Large', 451 => 'Unavailable For Legal Reasons', + 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported', 506 => 'Variant Also Negotiates', 507 => 'Insufficient Storage', 508 => 'Loop Detected', 511 => 'Network Authentication Required', + ]; + + /** @var string */ + private $reasonPhrase = ''; + + /** @var int */ + private $statusCode; + + /** + * @param int $status Status code + * @param array $headers Response headers + * @param string|resource|StreamInterface|null $body Response body + * @param string $version Protocol version + * @param string|null $reason Reason phrase (when empty a default will be used based on the status code) + */ + public function __construct(int $status = 200, array $headers = [], $body = null, string $version = '1.1', string $reason = null) + { + // If we got no body, defer initialization of the stream until Response::getBody() + if ('' !== $body && null !== $body) { + $this->stream = Stream::create($body); + } + + $this->statusCode = $status; + $this->setHeaders($headers); + if (null === $reason && isset(self::PHRASES[$this->statusCode])) { + $this->reasonPhrase = self::PHRASES[$status]; + } else { + $this->reasonPhrase = $reason ?? ''; + } + + $this->protocol = $version; + } + + public function getStatusCode(): int + { + return $this->statusCode; + } + + public function getReasonPhrase(): string + { + return $this->reasonPhrase; + } + + public function withStatus($code, $reasonPhrase = ''): self + { + if (!\is_int($code) && !\is_string($code)) { + throw new \InvalidArgumentException('Status code has to be an integer'); + } + + $code = (int) $code; + if ($code < 100 || $code > 599) { + throw new \InvalidArgumentException('Status code has to be an integer between 100 and 599'); + } + + $new = clone $this; + $new->statusCode = $code; + if ((null === $reasonPhrase || '' === $reasonPhrase) && isset(self::PHRASES[$new->statusCode])) { + $reasonPhrase = self::PHRASES[$new->statusCode]; + } + $new->reasonPhrase = $reasonPhrase; + + return $new; + } +} diff --git a/lam/lib/3rdParty/composer/nyholm/psr7/src/ServerRequest.php b/lam/lib/3rdParty/composer/nyholm/psr7/src/ServerRequest.php new file mode 100644 index 00000000..aff8721d --- /dev/null +++ b/lam/lib/3rdParty/composer/nyholm/psr7/src/ServerRequest.php @@ -0,0 +1,162 @@ + + * @author Martijn van der Ven + */ +final class ServerRequest implements ServerRequestInterface +{ + use MessageTrait; + use RequestTrait; + + /** @var array */ + private $attributes = []; + + /** @var array */ + private $cookieParams = []; + + /** @var array|object|null */ + private $parsedBody; + + /** @var array */ + private $queryParams = []; + + /** @var array */ + private $serverParams; + + /** @var UploadedFileInterface[] */ + private $uploadedFiles = []; + + /** + * @param string $method HTTP method + * @param string|UriInterface $uri URI + * @param array $headers Request headers + * @param string|resource|StreamInterface|null $body Request body + * @param string $version Protocol version + * @param array $serverParams Typically the $_SERVER superglobal + */ + public function __construct(string $method, $uri, array $headers = [], $body = null, string $version = '1.1', array $serverParams = []) + { + $this->serverParams = $serverParams; + + if (!($uri instanceof UriInterface)) { + $uri = new Uri($uri); + } + + $this->method = $method; + $this->uri = $uri; + $this->setHeaders($headers); + $this->protocol = $version; + + if (!$this->hasHeader('Host')) { + $this->updateHostFromUri(); + } + + // If we got no body, defer initialization of the stream until ServerRequest::getBody() + if ('' !== $body && null !== $body) { + $this->stream = Stream::create($body); + } + } + + public function getServerParams(): array + { + return $this->serverParams; + } + + public function getUploadedFiles(): array + { + return $this->uploadedFiles; + } + + public function withUploadedFiles(array $uploadedFiles) + { + $new = clone $this; + $new->uploadedFiles = $uploadedFiles; + + return $new; + } + + public function getCookieParams(): array + { + return $this->cookieParams; + } + + public function withCookieParams(array $cookies) + { + $new = clone $this; + $new->cookieParams = $cookies; + + return $new; + } + + public function getQueryParams(): array + { + return $this->queryParams; + } + + public function withQueryParams(array $query) + { + $new = clone $this; + $new->queryParams = $query; + + return $new; + } + + public function getParsedBody() + { + return $this->parsedBody; + } + + public function withParsedBody($data) + { + if (!\is_array($data) && !\is_object($data) && null !== $data) { + throw new \InvalidArgumentException('First parameter to withParsedBody MUST be object, array or null'); + } + + $new = clone $this; + $new->parsedBody = $data; + + return $new; + } + + public function getAttributes(): array + { + return $this->attributes; + } + + public function getAttribute($attribute, $default = null) + { + if (false === \array_key_exists($attribute, $this->attributes)) { + return $default; + } + + return $this->attributes[$attribute]; + } + + public function withAttribute($attribute, $value): self + { + $new = clone $this; + $new->attributes[$attribute] = $value; + + return $new; + } + + public function withoutAttribute($attribute): self + { + if (false === \array_key_exists($attribute, $this->attributes)) { + return $this; + } + + $new = clone $this; + unset($new->attributes[$attribute]); + + return $new; + } +} diff --git a/lam/lib/3rdParty/composer/nyholm/psr7/src/Stream.php b/lam/lib/3rdParty/composer/nyholm/psr7/src/Stream.php new file mode 100644 index 00000000..a72ce0a6 --- /dev/null +++ b/lam/lib/3rdParty/composer/nyholm/psr7/src/Stream.php @@ -0,0 +1,257 @@ + + * @author Martijn van der Ven + */ +final class Stream implements StreamInterface +{ + /** @var resource|null A resource reference */ + private $stream; + + /** @var bool */ + private $seekable; + + /** @var bool */ + private $readable; + + /** @var bool */ + private $writable; + + /** @var array|mixed|void|null */ + private $uri; + + /** @var int|null */ + private $size; + + /** @var array Hash of readable and writable stream types */ + private const READ_WRITE_HASH = [ + 'read' => [ + 'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true, + 'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true, + 'c+b' => true, 'rt' => true, 'w+t' => true, 'r+t' => true, + 'x+t' => true, 'c+t' => true, 'a+' => true, + ], + 'write' => [ + 'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true, + 'c+' => true, 'wb' => true, 'w+b' => true, 'r+b' => true, + 'x+b' => true, 'c+b' => true, 'w+t' => true, 'r+t' => true, + 'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true, + ], + ]; + + private function __construct() + { + } + + /** + * Creates a new PSR-7 stream. + * + * @param string|resource|StreamInterface $body + * + * @return StreamInterface + * + * @throws \InvalidArgumentException + */ + public static function create($body = ''): StreamInterface + { + if ($body instanceof StreamInterface) { + return $body; + } + + if (\is_string($body)) { + $resource = \fopen('php://temp', 'rw+'); + \fwrite($resource, $body); + $body = $resource; + } + + if (\is_resource($body)) { + $new = new self(); + $new->stream = $body; + $meta = \stream_get_meta_data($new->stream); + $new->seekable = $meta['seekable'] && 0 === \fseek($new->stream, 0, \SEEK_CUR); + $new->readable = isset(self::READ_WRITE_HASH['read'][$meta['mode']]); + $new->writable = isset(self::READ_WRITE_HASH['write'][$meta['mode']]); + $new->uri = $new->getMetadata('uri'); + + return $new; + } + + throw new \InvalidArgumentException('First argument to Stream::create() must be a string, resource or StreamInterface.'); + } + + /** + * Closes the stream when the destructed. + */ + public function __destruct() + { + $this->close(); + } + + public function __toString(): string + { + try { + if ($this->isSeekable()) { + $this->seek(0); + } + + return $this->getContents(); + } catch (\Exception $e) { + return ''; + } + } + + public function close(): void + { + if (isset($this->stream)) { + if (\is_resource($this->stream)) { + \fclose($this->stream); + } + $this->detach(); + } + } + + public function detach() + { + if (!isset($this->stream)) { + return null; + } + + $result = $this->stream; + unset($this->stream); + $this->size = $this->uri = null; + $this->readable = $this->writable = $this->seekable = false; + + return $result; + } + + public function getSize(): ?int + { + if (null !== $this->size) { + return $this->size; + } + + if (!isset($this->stream)) { + return null; + } + + // Clear the stat cache if the stream has a URI + if ($this->uri) { + \clearstatcache(true, $this->uri); + } + + $stats = \fstat($this->stream); + if (isset($stats['size'])) { + $this->size = $stats['size']; + + return $this->size; + } + + return null; + } + + public function tell(): int + { + if (false === $result = \ftell($this->stream)) { + throw new \RuntimeException('Unable to determine stream position'); + } + + return $result; + } + + public function eof(): bool + { + return !$this->stream || \feof($this->stream); + } + + public function isSeekable(): bool + { + return $this->seekable; + } + + public function seek($offset, $whence = \SEEK_SET): void + { + if (!$this->seekable) { + throw new \RuntimeException('Stream is not seekable'); + } + + if (-1 === \fseek($this->stream, $offset, $whence)) { + throw new \RuntimeException('Unable to seek to stream position ' . $offset . ' with whence ' . \var_export($whence, true)); + } + } + + public function rewind(): void + { + $this->seek(0); + } + + public function isWritable(): bool + { + return $this->writable; + } + + public function write($string): int + { + if (!$this->writable) { + throw new \RuntimeException('Cannot write to a non-writable stream'); + } + + // We can't know the size after writing anything + $this->size = null; + + if (false === $result = \fwrite($this->stream, $string)) { + throw new \RuntimeException('Unable to write to stream'); + } + + return $result; + } + + public function isReadable(): bool + { + return $this->readable; + } + + public function read($length): string + { + if (!$this->readable) { + throw new \RuntimeException('Cannot read from non-readable stream'); + } + + return \fread($this->stream, $length); + } + + public function getContents(): string + { + if (!isset($this->stream)) { + throw new \RuntimeException('Unable to read stream contents'); + } + + if (false === $contents = \stream_get_contents($this->stream)) { + throw new \RuntimeException('Unable to read stream contents'); + } + + return $contents; + } + + public function getMetadata($key = null) + { + if (!isset($this->stream)) { + return $key ? null : []; + } + + $meta = \stream_get_meta_data($this->stream); + + if (null === $key) { + return $meta; + } + + return $meta[$key] ?? null; + } +} diff --git a/lam/lib/3rdParty/composer/nyholm/psr7/src/UploadedFile.php b/lam/lib/3rdParty/composer/nyholm/psr7/src/UploadedFile.php new file mode 100644 index 00000000..757e70e9 --- /dev/null +++ b/lam/lib/3rdParty/composer/nyholm/psr7/src/UploadedFile.php @@ -0,0 +1,171 @@ + + * @author Martijn van der Ven + */ +final class UploadedFile implements UploadedFileInterface +{ + /** @var array */ + private const ERRORS = [ + \UPLOAD_ERR_OK => 1, + \UPLOAD_ERR_INI_SIZE => 1, + \UPLOAD_ERR_FORM_SIZE => 1, + \UPLOAD_ERR_PARTIAL => 1, + \UPLOAD_ERR_NO_FILE => 1, + \UPLOAD_ERR_NO_TMP_DIR => 1, + \UPLOAD_ERR_CANT_WRITE => 1, + \UPLOAD_ERR_EXTENSION => 1, + ]; + + /** @var string */ + private $clientFilename; + + /** @var string */ + private $clientMediaType; + + /** @var int */ + private $error; + + /** @var string|null */ + private $file; + + /** @var bool */ + private $moved = false; + + /** @var int */ + private $size; + + /** @var StreamInterface|null */ + private $stream; + + /** + * @param StreamInterface|string|resource $streamOrFile + * @param int $size + * @param int $errorStatus + * @param string|null $clientFilename + * @param string|null $clientMediaType + */ + public function __construct($streamOrFile, $size, $errorStatus, $clientFilename = null, $clientMediaType = null) + { + if (false === \is_int($errorStatus) || !isset(self::ERRORS[$errorStatus])) { + throw new \InvalidArgumentException('Upload file error status must be an integer value and one of the "UPLOAD_ERR_*" constants.'); + } + + if (false === \is_int($size)) { + throw new \InvalidArgumentException('Upload file size must be an integer'); + } + + if (null !== $clientFilename && !\is_string($clientFilename)) { + throw new \InvalidArgumentException('Upload file client filename must be a string or null'); + } + + if (null !== $clientMediaType && !\is_string($clientMediaType)) { + throw new \InvalidArgumentException('Upload file client media type must be a string or null'); + } + + $this->error = $errorStatus; + $this->size = $size; + $this->clientFilename = $clientFilename; + $this->clientMediaType = $clientMediaType; + + if (\UPLOAD_ERR_OK === $this->error) { + // Depending on the value set file or stream variable. + if (\is_string($streamOrFile)) { + $this->file = $streamOrFile; + } elseif (\is_resource($streamOrFile)) { + $this->stream = Stream::create($streamOrFile); + } elseif ($streamOrFile instanceof StreamInterface) { + $this->stream = $streamOrFile; + } else { + throw new \InvalidArgumentException('Invalid stream or file provided for UploadedFile'); + } + } + } + + /** + * @throws \RuntimeException if is moved or not ok + */ + private function validateActive(): void + { + if (\UPLOAD_ERR_OK !== $this->error) { + throw new \RuntimeException('Cannot retrieve stream due to upload error'); + } + + if ($this->moved) { + throw new \RuntimeException('Cannot retrieve stream after it has already been moved'); + } + } + + public function getStream(): StreamInterface + { + $this->validateActive(); + + if ($this->stream instanceof StreamInterface) { + return $this->stream; + } + + $resource = \fopen($this->file, 'r'); + + return Stream::create($resource); + } + + public function moveTo($targetPath): void + { + $this->validateActive(); + + if (!\is_string($targetPath) || '' === $targetPath) { + throw new \InvalidArgumentException('Invalid path provided for move operation; must be a non-empty string'); + } + + if (null !== $this->file) { + $this->moved = 'cli' === \PHP_SAPI ? \rename($this->file, $targetPath) : \move_uploaded_file($this->file, $targetPath); + } else { + $stream = $this->getStream(); + if ($stream->isSeekable()) { + $stream->rewind(); + } + + // Copy the contents of a stream into another stream until end-of-file. + $dest = Stream::create(\fopen($targetPath, 'w')); + while (!$stream->eof()) { + if (!$dest->write($stream->read(1048576))) { + break; + } + } + + $this->moved = true; + } + + if (false === $this->moved) { + throw new \RuntimeException(\sprintf('Uploaded file could not be moved to %s', $targetPath)); + } + } + + public function getSize(): int + { + return $this->size; + } + + public function getError(): int + { + return $this->error; + } + + public function getClientFilename(): ?string + { + return $this->clientFilename; + } + + public function getClientMediaType(): ?string + { + return $this->clientMediaType; + } +} diff --git a/lam/lib/3rdParty/composer/nyholm/psr7/src/Uri.php b/lam/lib/3rdParty/composer/nyholm/psr7/src/Uri.php new file mode 100644 index 00000000..d67c0783 --- /dev/null +++ b/lam/lib/3rdParty/composer/nyholm/psr7/src/Uri.php @@ -0,0 +1,310 @@ + + * @author Martijn van der Ven + */ +final class Uri implements UriInterface +{ + private const SCHEMES = ['http' => 80, 'https' => 443]; + + private const CHAR_UNRESERVED = 'a-zA-Z0-9_\-\.~'; + + private const CHAR_SUB_DELIMS = '!\$&\'\(\)\*\+,;='; + + /** @var string Uri scheme. */ + private $scheme = ''; + + /** @var string Uri user info. */ + private $userInfo = ''; + + /** @var string Uri host. */ + private $host = ''; + + /** @var int|null Uri port. */ + private $port; + + /** @var string Uri path. */ + private $path = ''; + + /** @var string Uri query string. */ + private $query = ''; + + /** @var string Uri fragment. */ + private $fragment = ''; + + public function __construct(string $uri = '') + { + if ('' !== $uri) { + if (false === $parts = \parse_url($uri)) { + throw new \InvalidArgumentException("Unable to parse URI: $uri"); + } + + // Apply parse_url parts to a URI. + $this->scheme = isset($parts['scheme']) ? \strtolower($parts['scheme']) : ''; + $this->userInfo = $parts['user'] ?? ''; + $this->host = isset($parts['host']) ? \strtolower($parts['host']) : ''; + $this->port = isset($parts['port']) ? $this->filterPort($parts['port']) : null; + $this->path = isset($parts['path']) ? $this->filterPath($parts['path']) : ''; + $this->query = isset($parts['query']) ? $this->filterQueryAndFragment($parts['query']) : ''; + $this->fragment = isset($parts['fragment']) ? $this->filterQueryAndFragment($parts['fragment']) : ''; + if (isset($parts['pass'])) { + $this->userInfo .= ':' . $parts['pass']; + } + } + } + + public function __toString(): string + { + return self::createUriString($this->scheme, $this->getAuthority(), $this->path, $this->query, $this->fragment); + } + + public function getScheme(): string + { + return $this->scheme; + } + + public function getAuthority(): string + { + if ('' === $this->host) { + return ''; + } + + $authority = $this->host; + if ('' !== $this->userInfo) { + $authority = $this->userInfo . '@' . $authority; + } + + if (null !== $this->port) { + $authority .= ':' . $this->port; + } + + return $authority; + } + + public function getUserInfo(): string + { + return $this->userInfo; + } + + public function getHost(): string + { + return $this->host; + } + + public function getPort(): ?int + { + return $this->port; + } + + public function getPath(): string + { + return $this->path; + } + + public function getQuery(): string + { + return $this->query; + } + + public function getFragment(): string + { + return $this->fragment; + } + + public function withScheme($scheme): self + { + if (!\is_string($scheme)) { + throw new \InvalidArgumentException('Scheme must be a string'); + } + + if ($this->scheme === $scheme = \strtolower($scheme)) { + return $this; + } + + $new = clone $this; + $new->scheme = $scheme; + $new->port = $new->filterPort($new->port); + + return $new; + } + + public function withUserInfo($user, $password = null): self + { + $info = $user; + if (null !== $password && '' !== $password) { + $info .= ':' . $password; + } + + if ($this->userInfo === $info) { + return $this; + } + + $new = clone $this; + $new->userInfo = $info; + + return $new; + } + + public function withHost($host): self + { + if (!\is_string($host)) { + throw new \InvalidArgumentException('Host must be a string'); + } + + if ($this->host === $host = \strtolower($host)) { + return $this; + } + + $new = clone $this; + $new->host = $host; + + return $new; + } + + public function withPort($port): self + { + if ($this->port === $port = $this->filterPort($port)) { + return $this; + } + + $new = clone $this; + $new->port = $port; + + return $new; + } + + public function withPath($path): self + { + if ($this->path === $path = $this->filterPath($path)) { + return $this; + } + + $new = clone $this; + $new->path = $path; + + return $new; + } + + public function withQuery($query): self + { + if ($this->query === $query = $this->filterQueryAndFragment($query)) { + return $this; + } + + $new = clone $this; + $new->query = $query; + + return $new; + } + + public function withFragment($fragment): self + { + if ($this->fragment === $fragment = $this->filterQueryAndFragment($fragment)) { + return $this; + } + + $new = clone $this; + $new->fragment = $fragment; + + return $new; + } + + /** + * Create a URI string from its various parts. + */ + private static function createUriString(string $scheme, string $authority, string $path, string $query, string $fragment): string + { + $uri = ''; + if ('' !== $scheme) { + $uri .= $scheme . ':'; + } + + if ('' !== $authority) { + $uri .= '//' . $authority; + } + + if ('' !== $path) { + if ('/' !== $path[0]) { + if ('' !== $authority) { + // If the path is rootless and an authority is present, the path MUST be prefixed by "/" + $path = '/' . $path; + } + } elseif (isset($path[1]) && '/' === $path[1]) { + if ('' === $authority) { + // If the path is starting with more than one "/" and no authority is present, the + // starting slashes MUST be reduced to one. + $path = '/' . \ltrim($path, '/'); + } + } + + $uri .= $path; + } + + if ('' !== $query) { + $uri .= '?' . $query; + } + + if ('' !== $fragment) { + $uri .= '#' . $fragment; + } + + return $uri; + } + + /** + * Is a given port non-standard for the current scheme? + */ + private static function isNonStandardPort(string $scheme, int $port): bool + { + return !isset(self::SCHEMES[$scheme]) || $port !== self::SCHEMES[$scheme]; + } + + private function filterPort($port): ?int + { + if (null === $port) { + return null; + } + + $port = (int) $port; + if (0 > $port || 0xffff < $port) { + throw new \InvalidArgumentException(\sprintf('Invalid port: %d. Must be between 0 and 65535', $port)); + } + + return self::isNonStandardPort($this->scheme, $port) ? $port : null; + } + + private function filterPath($path): string + { + if (!\is_string($path)) { + throw new \InvalidArgumentException('Path must be a string'); + } + + return \preg_replace_callback('/(?:[^' . self::CHAR_UNRESERVED . self::CHAR_SUB_DELIMS . '%:@\/]++|%(?![A-Fa-f0-9]{2}))/', [__CLASS__, 'rawurlencodeMatchZero'], $path); + } + + private function filterQueryAndFragment($str): string + { + if (!\is_string($str)) { + throw new \InvalidArgumentException('Query and fragment must be a string'); + } + + return \preg_replace_callback('/(?:[^' . self::CHAR_UNRESERVED . self::CHAR_SUB_DELIMS . '%:@\/\?]++|%(?![A-Fa-f0-9]{2}))/', [__CLASS__, 'rawurlencodeMatchZero'], $str); + } + + private static function rawurlencodeMatchZero(array $match): string + { + return \rawurlencode($match[0]); + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/random_compat/LICENSE b/lam/lib/3rdParty/composer/paragonie/random_compat/LICENSE new file mode 100644 index 00000000..45c7017d --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/random_compat/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Paragon Initiative Enterprises + +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/paragonie/random_compat/build-phar.sh b/lam/lib/3rdParty/composer/paragonie/random_compat/build-phar.sh new file mode 100755 index 00000000..b4a5ba31 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/random_compat/build-phar.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +basedir=$( dirname $( readlink -f ${BASH_SOURCE[0]} ) ) + +php -dphar.readonly=0 "$basedir/other/build_phar.php" $* \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/paragonie/random_compat/composer.json b/lam/lib/3rdParty/composer/paragonie/random_compat/composer.json new file mode 100644 index 00000000..1fa8de9f --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/random_compat/composer.json @@ -0,0 +1,34 @@ +{ + "name": "paragonie/random_compat", + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "random", + "polyfill", + "pseudorandom" + ], + "license": "MIT", + "type": "library", + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "support": { + "issues": "https://github.com/paragonie/random_compat/issues", + "email": "info@paragonie.com", + "source": "https://github.com/paragonie/random_compat" + }, + "require": { + "php": "^7" + }, + "require-dev": { + "vimeo/psalm": "^1", + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/random_compat/dist/random_compat.phar.pubkey b/lam/lib/3rdParty/composer/paragonie/random_compat/dist/random_compat.phar.pubkey new file mode 100644 index 00000000..eb50ebfc --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/random_compat/dist/random_compat.phar.pubkey @@ -0,0 +1,5 @@ +-----BEGIN PUBLIC KEY----- +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEEd+wCqJDrx5B4OldM0dQE0ZMX+lx1ZWm +pui0SUqD4G29L3NGsz9UhJ/0HjBdbnkhIK5xviT0X5vtjacF6ajgcCArbTB+ds+p ++h7Q084NuSuIpNb6YPfoUFgC/CL9kAoc +-----END PUBLIC KEY----- diff --git a/lam/lib/3rdParty/composer/paragonie/random_compat/dist/random_compat.phar.pubkey.asc b/lam/lib/3rdParty/composer/paragonie/random_compat/dist/random_compat.phar.pubkey.asc new file mode 100644 index 00000000..6a1d7f30 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/random_compat/dist/random_compat.phar.pubkey.asc @@ -0,0 +1,11 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v2.0.22 (MingW32) + +iQEcBAABAgAGBQJWtW1hAAoJEGuXocKCZATaJf0H+wbZGgskK1dcRTsuVJl9IWip +QwGw/qIKI280SD6/ckoUMxKDCJiFuPR14zmqnS36k7N5UNPnpdTJTS8T11jttSpg +1LCmgpbEIpgaTah+cELDqFCav99fS+bEiAL5lWDAHBTE/XPjGVCqeehyPYref4IW +NDBIEsvnHPHPLsn6X5jq4+Yj5oUixgxaMPiR+bcO4Sh+RzOVB6i2D0upWfRXBFXA +NNnsg9/zjvoC7ZW73y9uSH+dPJTt/Vgfeiv52/v41XliyzbUyLalf02GNPY+9goV +JHG1ulEEBJOCiUD9cE1PUIJwHA/HqyhHIvV350YoEFiHl8iSwm7SiZu5kPjaq74= +=B6+8 +-----END PGP SIGNATURE----- diff --git a/lam/lib/3rdParty/composer/paragonie/random_compat/lib/random.php b/lam/lib/3rdParty/composer/paragonie/random_compat/lib/random.php new file mode 100644 index 00000000..c7731a56 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/random_compat/lib/random.php @@ -0,0 +1,32 @@ +buildFromDirectory(dirname(__DIR__).'/lib'); +rename( + dirname(__DIR__).'/lib/index.php', + dirname(__DIR__).'/lib/random.php' +); + +/** + * If we pass an (optional) path to a private key as a second argument, we will + * sign the Phar with OpenSSL. + * + * If you leave this out, it will produce an unsigned .phar! + */ +if ($argc > 1) { + if (!@is_readable($argv[1])) { + echo 'Could not read the private key file:', $argv[1], "\n"; + exit(255); + } + $pkeyFile = file_get_contents($argv[1]); + + $private = openssl_get_privatekey($pkeyFile); + if ($private !== false) { + $pkey = ''; + openssl_pkey_export($private, $pkey); + $phar->setSignatureAlgorithm(Phar::OPENSSL, $pkey); + + /** + * Save the corresponding public key to the file + */ + if (!@is_readable($dist.'/random_compat.phar.pubkey')) { + $details = openssl_pkey_get_details($private); + file_put_contents( + $dist.'/random_compat.phar.pubkey', + $details['key'] + ); + } + } else { + echo 'An error occurred reading the private key from OpenSSL.', "\n"; + exit(255); + } +} diff --git a/lam/lib/3rdParty/composer/paragonie/random_compat/psalm-autoload.php b/lam/lib/3rdParty/composer/paragonie/random_compat/psalm-autoload.php new file mode 100644 index 00000000..d71d1b81 --- /dev/null +++ b/lam/lib/3rdParty/composer/paragonie/random_compat/psalm-autoload.php @@ -0,0 +1,9 @@ + + + + + + + + + + + + + + + diff --git a/lam/lib/3rdParty/composer/php-http/message-factory/CHANGELOG.md b/lam/lib/3rdParty/composer/php-http/message-factory/CHANGELOG.md new file mode 100644 index 00000000..4711924c --- /dev/null +++ b/lam/lib/3rdParty/composer/php-http/message-factory/CHANGELOG.md @@ -0,0 +1,65 @@ +# Change Log + + +## 1.0.2 - 2015-12-19 + +### Added + +- Request and Response factory binding types to Puli + + +## 1.0.1 - 2015-12-17 + +### Added + +- Puli configuration and binding types + + +## 1.0.0 - 2015-12-15 + +### Added + +- Response Factory in order to be reused in Message and Server Message factories +- Request Factory + +### Changed + +- Message Factory extends Request and Response factories + + +## 1.0.0-RC1 - 2015-12-14 + +### Added + +- CS check + +### Changed + +- RuntimeException is thrown when the StreamFactory cannot write to the underlying stream + + +## 0.3.0 - 2015-11-16 + +### Removed + +- Client Context Factory +- Factory Awares and Templates + + +## 0.2.0 - 2015-11-16 + +### Changed + +- Reordered the parameters when creating a message to have the protocol last, +as its the least likely to need to be changed. + + +## 0.1.0 - 2015-06-01 + +### Added + +- Initial release + +### Changed + +- Helpers are renamed to templates diff --git a/lam/lib/3rdParty/composer/php-http/message-factory/LICENSE b/lam/lib/3rdParty/composer/php-http/message-factory/LICENSE new file mode 100644 index 00000000..8e2c4a0b --- /dev/null +++ b/lam/lib/3rdParty/composer/php-http/message-factory/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015 PHP HTTP Team + +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/php-http/message-factory/README.md b/lam/lib/3rdParty/composer/php-http/message-factory/README.md new file mode 100644 index 00000000..4654495a --- /dev/null +++ b/lam/lib/3rdParty/composer/php-http/message-factory/README.md @@ -0,0 +1,36 @@ +# PSR-7 Message Factory + +[![Latest Version](https://img.shields.io/github/release/php-http/message-factory.svg?style=flat-square)](https://github.com/php-http/message-factory/releases) +[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE) +[![Total Downloads](https://img.shields.io/packagist/dt/php-http/message-factory.svg?style=flat-square)](https://packagist.org/packages/php-http/message-factory) + +**Factory interfaces for PSR-7 HTTP Message.** + + +## Install + +Via Composer + +``` bash +$ composer require php-http/message-factory +``` + + +## Documentation + +Please see the [official documentation](http://php-http.readthedocs.org/en/latest/message-factory/). + + +## Contributing + +Please see [CONTRIBUTING](CONTRIBUTING.md) and [CONDUCT](CONDUCT.md) for details. + + +## Security + +If you discover any security related issues, please contact us at [security@php-http.org](mailto:security@php-http.org). + + +## License + +The MIT License (MIT). Please see [License File](LICENSE) for more information. diff --git a/lam/lib/3rdParty/composer/php-http/message-factory/composer.json b/lam/lib/3rdParty/composer/php-http/message-factory/composer.json new file mode 100644 index 00000000..7c72febe --- /dev/null +++ b/lam/lib/3rdParty/composer/php-http/message-factory/composer.json @@ -0,0 +1,27 @@ +{ + "name": "php-http/message-factory", + "description": "Factory interfaces for PSR-7 HTTP Message", + "license": "MIT", + "keywords": ["http", "factory", "message", "stream", "uri"], + "homepage": "http://php-http.org", + "authors": [ + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + } + ], + "require": { + "php": ">=5.4", + "psr/http-message": "^1.0" + }, + "autoload": { + "psr-4": { + "Http\\Message\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + } +} diff --git a/lam/lib/3rdParty/composer/php-http/message-factory/puli.json b/lam/lib/3rdParty/composer/php-http/message-factory/puli.json new file mode 100644 index 00000000..08d37627 --- /dev/null +++ b/lam/lib/3rdParty/composer/php-http/message-factory/puli.json @@ -0,0 +1,43 @@ +{ + "version": "1.0", + "binding-types": { + "Http\\Message\\MessageFactory": { + "description": "PSR-7 Message Factory", + "parameters": { + "depends": { + "description": "Optional class dependency which can be checked by consumers" + } + } + }, + "Http\\Message\\RequestFactory": { + "parameters": { + "depends": { + "description": "Optional class dependency which can be checked by consumers" + } + } + }, + "Http\\Message\\ResponseFactory": { + "parameters": { + "depends": { + "description": "Optional class dependency which can be checked by consumers" + } + } + }, + "Http\\Message\\StreamFactory": { + "description": "PSR-7 Stream Factory", + "parameters": { + "depends": { + "description": "Optional class dependency which can be checked by consumers" + } + } + }, + "Http\\Message\\UriFactory": { + "description": "PSR-7 URI Factory", + "parameters": { + "depends": { + "description": "Optional class dependency which can be checked by consumers" + } + } + } + } +} diff --git a/lam/lib/3rdParty/composer/php-http/message-factory/src/MessageFactory.php b/lam/lib/3rdParty/composer/php-http/message-factory/src/MessageFactory.php new file mode 100644 index 00000000..965aaa80 --- /dev/null +++ b/lam/lib/3rdParty/composer/php-http/message-factory/src/MessageFactory.php @@ -0,0 +1,12 @@ + + */ +interface MessageFactory extends RequestFactory, ResponseFactory +{ +} diff --git a/lam/lib/3rdParty/composer/php-http/message-factory/src/RequestFactory.php b/lam/lib/3rdParty/composer/php-http/message-factory/src/RequestFactory.php new file mode 100644 index 00000000..624e82f3 --- /dev/null +++ b/lam/lib/3rdParty/composer/php-http/message-factory/src/RequestFactory.php @@ -0,0 +1,34 @@ + + */ +interface RequestFactory +{ + /** + * Creates a new PSR-7 request. + * + * @param string $method + * @param string|UriInterface $uri + * @param array $headers + * @param resource|string|StreamInterface|null $body + * @param string $protocolVersion + * + * @return RequestInterface + */ + public function createRequest( + $method, + $uri, + array $headers = [], + $body = null, + $protocolVersion = '1.1' + ); +} diff --git a/lam/lib/3rdParty/composer/php-http/message-factory/src/ResponseFactory.php b/lam/lib/3rdParty/composer/php-http/message-factory/src/ResponseFactory.php new file mode 100644 index 00000000..2411ed3a --- /dev/null +++ b/lam/lib/3rdParty/composer/php-http/message-factory/src/ResponseFactory.php @@ -0,0 +1,35 @@ + + */ +interface ResponseFactory +{ + /** + * Creates a new PSR-7 response. + * + * @param int $statusCode + * @param string|null $reasonPhrase + * @param array $headers + * @param resource|string|StreamInterface|null $body + * @param string $protocolVersion + * + * @return ResponseInterface + */ + public function createResponse( + $statusCode = 200, + $reasonPhrase = null, + array $headers = [], + $body = null, + $protocolVersion = '1.1' + ); +} diff --git a/lam/lib/3rdParty/composer/php-http/message-factory/src/StreamFactory.php b/lam/lib/3rdParty/composer/php-http/message-factory/src/StreamFactory.php new file mode 100644 index 00000000..327a902f --- /dev/null +++ b/lam/lib/3rdParty/composer/php-http/message-factory/src/StreamFactory.php @@ -0,0 +1,25 @@ + + */ +interface StreamFactory +{ + /** + * Creates a new PSR-7 stream. + * + * @param string|resource|StreamInterface|null $body + * + * @return StreamInterface + * + * @throws \InvalidArgumentException If the stream body is invalid. + * @throws \RuntimeException If creating the stream from $body fails. + */ + public function createStream($body = null); +} diff --git a/lam/lib/3rdParty/composer/php-http/message-factory/src/UriFactory.php b/lam/lib/3rdParty/composer/php-http/message-factory/src/UriFactory.php new file mode 100644 index 00000000..f05e6252 --- /dev/null +++ b/lam/lib/3rdParty/composer/php-http/message-factory/src/UriFactory.php @@ -0,0 +1,24 @@ + + */ +interface UriFactory +{ + /** + * Creates an PSR-7 URI. + * + * @param string|UriInterface $uri + * + * @return UriInterface + * + * @throws \InvalidArgumentException If the $uri argument can not be converted into a valid URI. + */ + public function createUri($uri); +} diff --git a/lam/lib/3rdParty/composer/psr/http-client/CHANGELOG.md b/lam/lib/3rdParty/composer/psr/http-client/CHANGELOG.md new file mode 100644 index 00000000..171ac649 --- /dev/null +++ b/lam/lib/3rdParty/composer/psr/http-client/CHANGELOG.md @@ -0,0 +1,19 @@ +# Changelog + +All notable changes to this project will be documented in this file, in reverse chronological order by release. + +## 1.0.0 + +First stable release. No changes since 0.3.0. + +## 0.3.0 + +Added Interface suffix on exceptions + +## 0.2.0 + +All exceptions are in `Psr\Http\Client` namespace + +## 0.1.0 + +First release \ No newline at end of file diff --git a/lam/lib/3rdParty/composer/psr/http-client/LICENSE b/lam/lib/3rdParty/composer/psr/http-client/LICENSE new file mode 100644 index 00000000..cd5e0020 --- /dev/null +++ b/lam/lib/3rdParty/composer/psr/http-client/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2017 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 +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/psr/http-client/README.md b/lam/lib/3rdParty/composer/psr/http-client/README.md new file mode 100644 index 00000000..e600b559 --- /dev/null +++ b/lam/lib/3rdParty/composer/psr/http-client/README.md @@ -0,0 +1,14 @@ +PSR Http Client +=============== + +This repository holds all interfaces/classes/traits related to +[PSR-18](http://www.php-fig.org/psr/psr-18/). + +Note that this is not an HTTP client implementation of its own. It is merely an +interface that describes an HTTP client. See +[the specification](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-18-http-client.md) +for more details. + +You can find implementations of the specification by looking for packages providing +the [psr/http-client-implementation](https://packagist.org/providers/psr/http-client-implementation) +virtual package. diff --git a/lam/lib/3rdParty/composer/psr/http-client/composer.json b/lam/lib/3rdParty/composer/psr/http-client/composer.json new file mode 100644 index 00000000..78cb39b6 --- /dev/null +++ b/lam/lib/3rdParty/composer/psr/http-client/composer.json @@ -0,0 +1,27 @@ +{ + "name": "psr/http-client", + "description": "Common interface for HTTP clients", + "keywords": ["psr", "psr-18", "http", "http-client"], + "homepage": "https://github.com/php-fig/http-client", + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "require": { + "php": "^7.0", + "psr/http-message": "^1.0" + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/lam/lib/3rdParty/composer/psr/http-client/src/ClientExceptionInterface.php b/lam/lib/3rdParty/composer/psr/http-client/src/ClientExceptionInterface.php new file mode 100644 index 00000000..aa0b9cf1 --- /dev/null +++ b/lam/lib/3rdParty/composer/psr/http-client/src/ClientExceptionInterface.php @@ -0,0 +1,10 @@ +=7.0.0", + "psr/http-message": "^1.0" + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/lam/lib/3rdParty/composer/psr/http-factory/src/RequestFactoryInterface.php b/lam/lib/3rdParty/composer/psr/http-factory/src/RequestFactoryInterface.php new file mode 100644 index 00000000..cb39a08b --- /dev/null +++ b/lam/lib/3rdParty/composer/psr/http-factory/src/RequestFactoryInterface.php @@ -0,0 +1,18 @@ +=5.3.0" + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/lam/lib/3rdParty/composer/psr/http-message/src/MessageInterface.php b/lam/lib/3rdParty/composer/psr/http-message/src/MessageInterface.php new file mode 100644 index 00000000..dd46e5ec --- /dev/null +++ b/lam/lib/3rdParty/composer/psr/http-message/src/MessageInterface.php @@ -0,0 +1,187 @@ +getHeaders() as $name => $values) { + * echo $name . ": " . implode(", ", $values); + * } + * + * // Emit headers iteratively: + * foreach ($message->getHeaders() as $name => $values) { + * foreach ($values as $value) { + * header(sprintf('%s: %s', $name, $value), false); + * } + * } + * + * While header names are not case-sensitive, getHeaders() will preserve the + * exact case in which headers were originally specified. + * + * @return string[][] Returns an associative array of the message's headers. Each + * key MUST be a header name, and each value MUST be an array of strings + * for that header. + */ + public function getHeaders(); + + /** + * Checks if a header exists by the given case-insensitive name. + * + * @param string $name Case-insensitive header field name. + * @return bool Returns true if any header names match the given header + * name using a case-insensitive string comparison. Returns false if + * no matching header name is found in the message. + */ + public function hasHeader($name); + + /** + * Retrieves a message header value by the given case-insensitive name. + * + * This method returns an array of all the header values of the given + * case-insensitive header name. + * + * If the header does not appear in the message, this method MUST return an + * empty array. + * + * @param string $name Case-insensitive header field name. + * @return string[] An array of string values as provided for the given + * header. If the header does not appear in the message, this method MUST + * return an empty array. + */ + public function getHeader($name); + + /** + * Retrieves a comma-separated string of the values for a single header. + * + * This method returns all of the header values of the given + * case-insensitive header name as a string concatenated together using + * a comma. + * + * NOTE: Not all header values may be appropriately represented using + * comma concatenation. For such headers, use getHeader() instead + * and supply your own delimiter when concatenating. + * + * If the header does not appear in the message, this method MUST return + * an empty string. + * + * @param string $name Case-insensitive header field name. + * @return string A string of values as provided for the given header + * concatenated together using a comma. If the header does not appear in + * the message, this method MUST return an empty string. + */ + public function getHeaderLine($name); + + /** + * Return an instance with the provided value replacing the specified header. + * + * While header names are case-insensitive, the casing of the header will + * be preserved by this function, and returned from getHeaders(). + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * new and/or updated header and value. + * + * @param string $name Case-insensitive header field name. + * @param string|string[] $value Header value(s). + * @return static + * @throws \InvalidArgumentException for invalid header names or values. + */ + public function withHeader($name, $value); + + /** + * Return an instance with the specified header appended with the given value. + * + * Existing values for the specified header will be maintained. The new + * value(s) will be appended to the existing list. If the header did not + * exist previously, it will be added. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * new header and/or value. + * + * @param string $name Case-insensitive header field name to add. + * @param string|string[] $value Header value(s). + * @return static + * @throws \InvalidArgumentException for invalid header names or values. + */ + public function withAddedHeader($name, $value); + + /** + * Return an instance without the specified header. + * + * Header resolution MUST be done without case-sensitivity. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that removes + * the named header. + * + * @param string $name Case-insensitive header field name to remove. + * @return static + */ + public function withoutHeader($name); + + /** + * Gets the body of the message. + * + * @return StreamInterface Returns the body as a stream. + */ + public function getBody(); + + /** + * Return an instance with the specified message body. + * + * The body MUST be a StreamInterface object. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return a new instance that has the + * new body stream. + * + * @param StreamInterface $body Body. + * @return static + * @throws \InvalidArgumentException When the body is not valid. + */ + public function withBody(StreamInterface $body); +} diff --git a/lam/lib/3rdParty/composer/psr/http-message/src/RequestInterface.php b/lam/lib/3rdParty/composer/psr/http-message/src/RequestInterface.php new file mode 100644 index 00000000..a96d4fd6 --- /dev/null +++ b/lam/lib/3rdParty/composer/psr/http-message/src/RequestInterface.php @@ -0,0 +1,129 @@ +getQuery()` + * or from the `QUERY_STRING` server param. + * + * @return array + */ + public function getQueryParams(); + + /** + * Return an instance with the specified query string arguments. + * + * These values SHOULD remain immutable over the course of the incoming + * request. They MAY be injected during instantiation, such as from PHP's + * $_GET superglobal, or MAY be derived from some other value such as the + * URI. In cases where the arguments are parsed from the URI, the data + * MUST be compatible with what PHP's parse_str() would return for + * purposes of how duplicate query parameters are handled, and how nested + * sets are handled. + * + * Setting query string arguments MUST NOT change the URI stored by the + * request, nor the values in the server params. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * updated query string arguments. + * + * @param array $query Array of query string arguments, typically from + * $_GET. + * @return static + */ + public function withQueryParams(array $query); + + /** + * Retrieve normalized file upload data. + * + * This method returns upload metadata in a normalized tree, with each leaf + * an instance of Psr\Http\Message\UploadedFileInterface. + * + * These values MAY be prepared from $_FILES or the message body during + * instantiation, or MAY be injected via withUploadedFiles(). + * + * @return array An array tree of UploadedFileInterface instances; an empty + * array MUST be returned if no data is present. + */ + public function getUploadedFiles(); + + /** + * Create a new instance with the specified uploaded files. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * updated body parameters. + * + * @param array $uploadedFiles An array tree of UploadedFileInterface instances. + * @return static + * @throws \InvalidArgumentException if an invalid structure is provided. + */ + public function withUploadedFiles(array $uploadedFiles); + + /** + * Retrieve any parameters provided in the request body. + * + * If the request Content-Type is either application/x-www-form-urlencoded + * or multipart/form-data, and the request method is POST, this method MUST + * return the contents of $_POST. + * + * Otherwise, this method may return any results of deserializing + * the request body content; as parsing returns structured content, the + * potential types MUST be arrays or objects only. A null value indicates + * the absence of body content. + * + * @return null|array|object The deserialized body parameters, if any. + * These will typically be an array or object. + */ + public function getParsedBody(); + + /** + * Return an instance with the specified body parameters. + * + * These MAY be injected during instantiation. + * + * If the request Content-Type is either application/x-www-form-urlencoded + * or multipart/form-data, and the request method is POST, use this method + * ONLY to inject the contents of $_POST. + * + * The data IS NOT REQUIRED to come from $_POST, but MUST be the results of + * deserializing the request body content. Deserialization/parsing returns + * structured data, and, as such, this method ONLY accepts arrays or objects, + * or a null value if nothing was available to parse. + * + * As an example, if content negotiation determines that the request data + * is a JSON payload, this method could be used to create a request + * instance with the deserialized parameters. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * updated body parameters. + * + * @param null|array|object $data The deserialized body data. This will + * typically be in an array or object. + * @return static + * @throws \InvalidArgumentException if an unsupported argument type is + * provided. + */ + public function withParsedBody($data); + + /** + * Retrieve attributes derived from the request. + * + * The request "attributes" may be used to allow injection of any + * parameters derived from the request: e.g., the results of path + * match operations; the results of decrypting cookies; the results of + * deserializing non-form-encoded message bodies; etc. Attributes + * will be application and request specific, and CAN be mutable. + * + * @return array Attributes derived from the request. + */ + public function getAttributes(); + + /** + * Retrieve a single derived request attribute. + * + * Retrieves a single derived request attribute as described in + * getAttributes(). If the attribute has not been previously set, returns + * the default value as provided. + * + * This method obviates the need for a hasAttribute() method, as it allows + * specifying a default value to return if the attribute is not found. + * + * @see getAttributes() + * @param string $name The attribute name. + * @param mixed $default Default value to return if the attribute does not exist. + * @return mixed + */ + public function getAttribute($name, $default = null); + + /** + * Return an instance with the specified derived request attribute. + * + * This method allows setting a single derived request attribute as + * described in getAttributes(). + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * updated attribute. + * + * @see getAttributes() + * @param string $name The attribute name. + * @param mixed $value The value of the attribute. + * @return static + */ + public function withAttribute($name, $value); + + /** + * Return an instance that removes the specified derived request attribute. + * + * This method allows removing a single derived request attribute as + * described in getAttributes(). + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that removes + * the attribute. + * + * @see getAttributes() + * @param string $name The attribute name. + * @return static + */ + public function withoutAttribute($name); +} diff --git a/lam/lib/3rdParty/composer/psr/http-message/src/StreamInterface.php b/lam/lib/3rdParty/composer/psr/http-message/src/StreamInterface.php new file mode 100644 index 00000000..f68f3912 --- /dev/null +++ b/lam/lib/3rdParty/composer/psr/http-message/src/StreamInterface.php @@ -0,0 +1,158 @@ + + * [user-info@]host[:port] + * + * + * If the port component is not set or is the standard port for the current + * scheme, it SHOULD NOT be included. + * + * @see https://tools.ietf.org/html/rfc3986#section-3.2 + * @return string The URI authority, in "[user-info@]host[:port]" format. + */ + public function getAuthority(); + + /** + * Retrieve the user information component of the URI. + * + * If no user information is present, this method MUST return an empty + * string. + * + * If a user is present in the URI, this will return that value; + * additionally, if the password is also present, it will be appended to the + * user value, with a colon (":") separating the values. + * + * The trailing "@" character is not part of the user information and MUST + * NOT be added. + * + * @return string The URI user information, in "username[:password]" format. + */ + public function getUserInfo(); + + /** + * Retrieve the host component of the URI. + * + * If no host is present, this method MUST return an empty string. + * + * The value returned MUST be normalized to lowercase, per RFC 3986 + * Section 3.2.2. + * + * @see http://tools.ietf.org/html/rfc3986#section-3.2.2 + * @return string The URI host. + */ + public function getHost(); + + /** + * Retrieve the port component of the URI. + * + * If a port is present, and it is non-standard for the current scheme, + * this method MUST return it as an integer. If the port is the standard port + * used with the current scheme, this method SHOULD return null. + * + * If no port is present, and no scheme is present, this method MUST return + * a null value. + * + * If no port is present, but a scheme is present, this method MAY return + * the standard port for that scheme, but SHOULD return null. + * + * @return null|int The URI port. + */ + public function getPort(); + + /** + * Retrieve the path component of the URI. + * + * The path can either be empty or absolute (starting with a slash) or + * rootless (not starting with a slash). Implementations MUST support all + * three syntaxes. + * + * Normally, the empty path "" and absolute path "/" are considered equal as + * defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically + * do this normalization because in contexts with a trimmed base path, e.g. + * the front controller, this difference becomes significant. It's the task + * of the user to handle both "" and "/". + * + * The value returned MUST be percent-encoded, but MUST NOT double-encode + * any characters. To determine what characters to encode, please refer to + * RFC 3986, Sections 2 and 3.3. + * + * As an example, if the value should include a slash ("/") not intended as + * delimiter between path segments, that value MUST be passed in encoded + * form (e.g., "%2F") to the instance. + * + * @see https://tools.ietf.org/html/rfc3986#section-2 + * @see https://tools.ietf.org/html/rfc3986#section-3.3 + * @return string The URI path. + */ + public function getPath(); + + /** + * Retrieve the query string of the URI. + * + * If no query string is present, this method MUST return an empty string. + * + * The leading "?" character is not part of the query and MUST NOT be + * added. + * + * The value returned MUST be percent-encoded, but MUST NOT double-encode + * any characters. To determine what characters to encode, please refer to + * RFC 3986, Sections 2 and 3.4. + * + * As an example, if a value in a key/value pair of the query string should + * include an ampersand ("&") not intended as a delimiter between values, + * that value MUST be passed in encoded form (e.g., "%26") to the instance. + * + * @see https://tools.ietf.org/html/rfc3986#section-2 + * @see https://tools.ietf.org/html/rfc3986#section-3.4 + * @return string The URI query string. + */ + public function getQuery(); + + /** + * Retrieve the fragment component of the URI. + * + * If no fragment is present, this method MUST return an empty string. + * + * The leading "#" character is not part of the fragment and MUST NOT be + * added. + * + * The value returned MUST be percent-encoded, but MUST NOT double-encode + * any characters. To determine what characters to encode, please refer to + * RFC 3986, Sections 2 and 3.5. + * + * @see https://tools.ietf.org/html/rfc3986#section-2 + * @see https://tools.ietf.org/html/rfc3986#section-3.5 + * @return string The URI fragment. + */ + public function getFragment(); + + /** + * Return an instance with the specified scheme. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified scheme. + * + * Implementations MUST support the schemes "http" and "https" case + * insensitively, and MAY accommodate other schemes if required. + * + * An empty scheme is equivalent to removing the scheme. + * + * @param string $scheme The scheme to use with the new instance. + * @return static A new instance with the specified scheme. + * @throws \InvalidArgumentException for invalid or unsupported schemes. + */ + public function withScheme($scheme); + + /** + * Return an instance with the specified user information. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified user information. + * + * Password is optional, but the user information MUST include the + * user; an empty string for the user is equivalent to removing user + * information. + * + * @param string $user The user name to use for authority. + * @param null|string $password The password associated with $user. + * @return static A new instance with the specified user information. + */ + public function withUserInfo($user, $password = null); + + /** + * Return an instance with the specified host. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified host. + * + * An empty host value is equivalent to removing the host. + * + * @param string $host The hostname to use with the new instance. + * @return static A new instance with the specified host. + * @throws \InvalidArgumentException for invalid hostnames. + */ + public function withHost($host); + + /** + * Return an instance with the specified port. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified port. + * + * Implementations MUST raise an exception for ports outside the + * established TCP and UDP port ranges. + * + * A null value provided for the port is equivalent to removing the port + * information. + * + * @param null|int $port The port to use with the new instance; a null value + * removes the port information. + * @return static A new instance with the specified port. + * @throws \InvalidArgumentException for invalid ports. + */ + public function withPort($port); + + /** + * Return an instance with the specified path. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified path. + * + * The path can either be empty or absolute (starting with a slash) or + * rootless (not starting with a slash). Implementations MUST support all + * three syntaxes. + * + * If the path is intended to be domain-relative rather than path relative then + * it must begin with a slash ("/"). Paths not starting with a slash ("/") + * are assumed to be relative to some base path known to the application or + * consumer. + * + * Users can provide both encoded and decoded path characters. + * Implementations ensure the correct encoding as outlined in getPath(). + * + * @param string $path The path to use with the new instance. + * @return static A new instance with the specified path. + * @throws \InvalidArgumentException for invalid paths. + */ + public function withPath($path); + + /** + * Return an instance with the specified query string. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified query string. + * + * Users can provide both encoded and decoded query characters. + * Implementations ensure the correct encoding as outlined in getQuery(). + * + * An empty query string value is equivalent to removing the query string. + * + * @param string $query The query string to use with the new instance. + * @return static A new instance with the specified query string. + * @throws \InvalidArgumentException for invalid query strings. + */ + public function withQuery($query); + + /** + * Return an instance with the specified URI fragment. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified URI fragment. + * + * Users can provide both encoded and decoded fragment characters. + * Implementations ensure the correct encoding as outlined in getFragment(). + * + * An empty fragment value is equivalent to removing the fragment. + * + * @param string $fragment The fragment to use with the new instance. + * @return static A new instance with the specified fragment. + */ + public function withFragment($fragment); + + /** + * Return the string representation as a URI reference. + * + * Depending on which components of the URI are present, the resulting + * string is either a full URI or relative reference according to RFC 3986, + * Section 4.1. The method concatenates the various components of the URI, + * using the appropriate delimiters: + * + * - If a scheme is present, it MUST be suffixed by ":". + * - If an authority is present, it MUST be prefixed by "//". + * - The path can be concatenated without delimiters. But there are two + * cases where the path has to be adjusted to make the URI reference + * valid as PHP does not allow to throw an exception in __toString(): + * - If the path is rootless and an authority is present, the path MUST + * be prefixed by "/". + * - If the path is starting with more than one "/" and no authority is + * present, the starting slashes MUST be reduced to one. + * - If a query is present, it MUST be prefixed by "?". + * - If a fragment is present, it MUST be prefixed by "#". + * + * @see http://tools.ietf.org/html/rfc3986#section-4.1 + * @return string + */ + public function __toString(); +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/CHANGELOG.md b/lam/lib/3rdParty/composer/ramsey/uuid/CHANGELOG.md new file mode 100644 index 00000000..3965fff2 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/CHANGELOG.md @@ -0,0 +1,376 @@ +# ramsey/uuid Changelog + +## 3.8.0 + +_Released: 2018-07-19_ + + * Add support for determining MAC address on FreeBSD systems ([#212](https://github.com/ramsey/uuid/pull/212)) + * Add a polyfill for PHP ctype functions to support systems where the ctype functions are not part of the PHP build ([#223](https://github.com/ramsey/uuid/pull/223)) + * Improve validation to disallow UUIDs with a trailing newline character ([#225](https://github.com/ramsey/uuid/pull/225)) + * Add annotations for thrown exceptions for improved IDE hinting ([#232](https://github.com/ramsey/uuid/pull/232)) + * Improve documentation, testing, and project metadata (i.e. `.gitattributes`, etc.) + +## 3.7.3 + +_Released: 2018-01-19_ + + * In rare cases, when using `glob()` to find `/sys/class/net/*/address` files on Linux, `glob()` encountered errors, returning `false` instead of an empty array, causing `array_map()` to emit warnings since its second parameter was not an array; this release gracefully handles cases where `glob()` returns `false` [#203](https://github.com/ramsey/uuid/issues/203) + * Fixed an off-by-one error in `DefaultTimeGenerator` and switching to `random_int()` from `mt_rand()` for better random numbers [#206](https://github.com/ramsey/uuid/pull/206) + +## 3.7.2 + +_Released: 2018-01-13_ + + * On Linux, first check sysfs to determine node identifier; this provides a reliable way to identify the node on Docker images, etc. [#185](https://github.com/ramsey/uuid/pull/185) + +## 3.7.1 + +_Released: 2017-09-22_ + + * Use `random_bytes()` when generating random nodes + * Set the multicast bit for random nodes, according to RFC 4122, §4.5, [#170](https://github.com/ramsey/uuid/pull/170), [#171](https://github.com/ramsey/uuid/pull/171), [#182](https://github.com/ramsey/uuid/pull/182) + +## 3.7.0 + +_Released: 2017-08-04_ + + * Add UUID version constants [#173](https://github.com/ramsey/uuid/issues/173), [#177](https://github.com/ramsey/uuid/pull/177) + * `Uuid::UUID_TYPE_TIME` + * `Uuid::UUID_TYPE_IDENTIFIER` + * `Uuid::UUID_TYPE_HASH_MD5` + * `Uuid::UUID_TYPE_RANDOM` + * `Uuid::UUID_TYPE_HASH_SHA1` + +## 3.6.1 + +_Released: 2017-03-26_ + + * Optimize UUID string decoding [#164](https://github.com/ramsey/uuid/pull/164) + +## 3.6.0 + +_Released: 2017-03-18_ + + * Add `InvalidUuidStringException`, thrown when attempting to decode an invalid string UUID; this does not introduce any BC issues, since the new exception inherits from the previously used `InvalidArgumentException` [#162](https://github.com/ramsey/uuid/pull/162) + * Improve memory usage when generating large quantities of UUIDs (use `str_pad()` and `dechex()` instead of `sprintf()`) [#160](https://github.com/ramsey/uuid/pull/160) + * Minor test and documentation updates + +## 3.5.2 + +_Released: 2016-11-22_ + + * Improved test coverage. + +## 3.5.1 + +_Released: 2016-10-02_ + + * Fixed issue where same UUIDs were not treated as equal with mixed case ([#131](https://github.com/ramsey/uuid/issues/131), [#137](https://github.com/ramsey/uuid/pull/137)). + * Test cleanup. + +## 3.5.0 + +_Released: 2016-08-02_ + + * Add `OrderedTimeCodec` to store UUID in an optimized way for InnoDB ([#117](https://github.com/ramsey/uuid/issues/117), [#118](https://github.com/ramsey/uuid/pull/118)). + * Fixed `RandomNodeProvider` to prevent invalid node generation ([#129](https://github.com/ramsey/uuid/pull/129)). + * Cache failed attempt to retrieve system node to avoid multiple system calls ([#107](https://github.com/ramsey/uuid/issues/107), [#121](https://github.com/ramsey/uuid/pull/121)). + * Various test improvements. + +## 3.4.1 + +_Released: 2016-04-23_ + + * Fixed test that violated a PHP CodeSniffer rule, breaking the build. + +## 3.4.0 + +_Released: 2016-04-23_ + + * Add `TimestampFirstCombCodec` and `TimestampLastCombCodec` codecs. + * Improve logic of `CombGenerator` for COMB sequential UUIDs. + * Significantly improved test coverage. + +## 3.3.0 + +_Released: 2016-03-22_ + + * Drop the use of OpenSSL as a fallback and use [paragonie/random_compat][] to support RandomBytesGenerator in versions of PHP earlier than 7.0. This addresses and fixes the [collision issue][]. + * Improved test coverage. + * Update code to conduct to version 1.4 of the Contributor Covenant. + +## 3.2.0 + +_Released: 2016-02-17_ + + * Add random generator option for use for the PECL libsodium extension. + * Updates to test infrastructure. + +## 3.1.0 + +_Released: 2015-12-17_ + + * Uuid objects now may be properly serialized/unserialized. + * Update build environments for testing on Travis CI. + +## 3.0.1 + +_Released: 2015-10-21_ + + * Add project [Contributor Code of Conduct](https://github.com/ramsey/uuid/blob/master/CONDUCT.md) + * Modify Travis CI builds to run tests on multiple CPU architectures + * Clean up code, tests, and documentation + +## 3.0.0 + +_Released: 2015-09-28_ + +The 3.0.0 release represents a significant step for the ramsey/uuid library. While the simple and familiar API used in previous versions remains intact, this release provides greater flexibility to integrators, including the ability to inject your own number generators, UUID codecs, node and time providers, and more. + + * BREAK: The root namespace for this package has changed from "Rhumsaa" to "Ramsey." In most cases, simply making this change in your applications is the only upgrade path you will need. Everything else should work as expected. + * BREAK: The UUID [Doctrine field type](http://doctrine-dbal.readthedocs.org/en/latest/reference/types.html) has been moved to [ramsey/uuid-doctrine](https://github.com/ramsey/uuid-doctrine). + * BREAK: The `uuid` console application has been moved to [ramsey/uuid-console](https://github.com/ramsey/uuid-console). + * BREAK: The `Uuid::VERSION` package version constant has been removed. + * See also the release notes for [3.0.0-alpha1][300-alpha1], [3.0.0-alpha2][300-alpha2], [3.0.0-alpha3][300-alpha3], and [3.0.0-beta1][300-beta1]. + +[300-alpha1]: https://github.com/ramsey/uuid/blob/master/CHANGELOG.md#300-alpha1 +[300-alpha2]: https://github.com/ramsey/uuid/blob/master/CHANGELOG.md#300-alpha2 +[300-alpha3]: https://github.com/ramsey/uuid/blob/master/CHANGELOG.md#300-alpha3 +[300-beta1]: https://github.com/ramsey/uuid/blob/master/CHANGELOG.md#300-beta1 + +## 3.0.0-beta1 + +_Released: 2015-08-31_ + + * Improve GUID support to ensure that: + * On little endian (LE) architectures, the byte order of the first three fields is LE. + * On big endian (BE) architectures, it is the same as a GUID. + * String representation is always the same. + * Fix exception message for `DegradedNumberConverter::fromHex()`. + * Add Scrutinizer configuration to run code-quality builds through Scrutinizer. + * Auto-fix Scrutinizer issues. + * Fix support URLs in composer.json to point to the correct GitHub repository. + +## 3.0.0-alpha3 + +_Released: 2015-07-28_ + + * Time generator improvements: + * Enabled use of custom TimeGenerator implementations. + * BREAK: Removed now unnecessary `timeConverter` and `timeProvider` properties, setters, and getters in both `FeatureSet` and `UuidFactory` as those are now exclusively used by the default `TimeGenerator`. + * Added a `setTimeGenerator` method on `UuidFactory` to override the default time generator. + * Add option to enable `PeclUuidTimeGenerator` via `FeatureSet`. + +## 3.0.0-alpha2 + +_Released: 2015-07-28_ + + * BREAK: Removed `PeclUuidFactory` in favor of using pecl-uuid with generators. + * NEW: Refactored time-based (version 1) UUIDs into a `TimeGeneratorInterface` to allow for other sources to generate version 1 UUIDs in this library. + * NEW: Added `PeclUuidTimeGenerator` and `PeclUuidRandomGenerator` for creating version 1 or version 4 UUIDs using the pecl-uuid extension. + * NEW: Add `RandomBytesGenerator` for use with PHP 7. ramsey/uuid will default to use this generator when running on PHP 7. + * `RandomLibAdapter` now defaults to a medium-strength generator with [ircmaxell/random-lib](https://github.com/ircmaxell/RandomLib). This is configurable, so other generator strengths may be used. + * Migrated to the Travis CI container-based infrastructure for builds. + * Documentation updates and corrections. + +## 3.0.0-alpha1 + +_Released: 2015-07-16_ + + * BREAK: The root namespace for this package has changed from "Rhumsaa" to "Ramsey." In most cases, simply making this change in your applications is the only upgrade path you will need. Everything else should work as expected. + * BREAK: The UUID [Doctrine field type](http://doctrine-dbal.readthedocs.org/en/latest/reference/types.html) has been moved to [ramsey/uuid-doctrine](https://github.com/ramsey/uuid-doctrine). + * BREAK: The `uuid` console application has been moved to [ramsey/uuid-console](https://github.com/ramsey/uuid-console). + * BREAK: The `Uuid::VERSION` package version constant has been removed. + * NEW: The `Uuid` class is no longer marked as `final`. Everything is now based around interfaces and factories, allowing you to use this package as a base to implement other kinds of UUIDs with different dependencies. + * NEW: Through setting dependencies on `UuidFactory` and/or extending `FeatureSet`, you may override any package defaults, injecting your own dependencies. + * NEW: For random number generation, in addition to `OpenSslGenerator` (used if `openssl_random_pseudo_bytes()` is present) and the fallback `MtRandGenerator`, you may use the bundled `CombGenerator` for sequential UUIDs or the `RandomLibAdapter` if using [ircmaxell/random-lib](https://github.com/ircmaxell/RandomLib). + * NEW: In addition to the default UUID generation, this library also supports GUID generation by configuring a `FeatureSet` to use GUIDs. + * NEW: While the interface to create UUIDs hasn't changed, if using this package on a 32-bit system, you will now receive an object of type `DegradedUuid` (which extends `Uuid`, which implements `UuidInterface`). + * NEW: All UUIDs are now [JsonSerializable](http://php.net/JsonSerializable). + +## 2.9.0 + +_Released: 2016-03-22_ + + * Drop support for OpenSSL in favor of [paragonie/random_compat][]. This addresses and fixes the [collision issue][]. + +## 2.8.4 + +_Released: 2015-12-17_ + + * Add support for symfony/console v3. + * Update build matrix to run Travis CI tests on PHP 7 & with lowest package versions. + +## 2.8.3 + +_Released: 2015-08-31_ + + * Fix exception message in `Uuid::calculateUuidTime()`. + * Update composer.json to reflect new repository and package name. + +## 2.8.2 + +_Released: 2015-07-23_ + + * Ensure the release tag makes it into the rhumsaa/uuid package. + * Minor documentation changes. + +## 2.8.1 + +_Released: 2015-06-16_ + + * Use `passthru()` and output buffering in `getIfconfig()`. + * Cache the system node in a static variable so that we process it only once per runtime. + * Set ramsey/uuid as a replacement for rhumsaa/uuid in composer.json. + * Documentation updates and corrections. + +## 2.8.0 + +_Released: 2014-11-09_ + + * Added static `fromInteger()` method to create UUIDs from string integer or `\Moontoast\Math\BigNumber`. + * Friendlier Doctrine conversion to Uuid or string. + * Documentation fixes. + +## 2.7.4 + +_Released: 2014-10-29_ + + * Changed loop in `generateBytes()` from `foreach` to `for`; see #33 + * Use `toString()` in README examples to avoid confusion + * Exclude build/development tools from releases using .gitattributes + * Set timezone properly for tests + +## 2.7.3 + +_Released: 2014-08-27_ + + * Fixed upper range for `mt_rand` used in version 4 UUIDs + +## 2.7.2 + +_Released: 2014-07-28_ + + * Upgraded to PSR-4 autoloading + * Testing upgrades: + * Testing against PHP 5.6 + * Testing with PHPUnit 4 + * Using Coveralls.io to generate code coverage reports + * Documentation fixes + +## 2.7.1 + +_Released: 2014-02-19_ + + * Moved moontoast/math and symfony/console to require-dev; fixes #20 + * Now supporting symfony/console for 2.3 (LTS version); fixes #21 + * Updated tests to run even when dev packages are not installed (skips tests if requirements are not met) + +## 2.7.0 + +_Released: 2014-01-31_ + + * Moved UUID validation regex pattern into constant for external use (`Uuid::VALID_PATTERN`) + +## 2.6.1 + +_Released: 2014-01-27_ + + * Fixed bug where `uuid` console application could not find the Composer autoloader when installed in another project + +## 2.6.0 + +_Released: 2014-01-17_ + + * Introduced `uuid` console application for generating and decoding UUIDs from CLI (run `./bin/uuid` for details) + * Added `Uuid::getInteger()` to retrieve a Moontoast\Math\BigNumber representation of the 128-bit integer representing the UUID + * Added `Uuid::getHex()` to retrieve the hexadecimal representation of the UUID + * Now using netstat on Linux to capture the node for a version 1 UUID + * Now requiring Moontoast\Math as part of the regular package requirements, not just the dev requirements + +## 2.5.0 + +_Released: 2013-10-30_ + + * Using `openssl_random_pseudo_bytes()`, if available, to generate random bytes, by merging in PR #15 from @dfreudenberger + * Fixed test for Rhumsaa\Uuid\Doctrine\UuidType, by merging in PR #17 from @dfreudenberger + * Documentation fixes + +## 2.4.0 + +_Released: 2013-07-29_ + + * `Uuid::getVersion()` now returns null if the UUID isn't an RFC 4122 variant + * `Uuid::fromString()` now supports a 128-bit integer formatted as a hexadecimal string (UUID without dashes) + * Tests have been greatly enhanced, borrowing from the Python UUID library + +## 2.3.0 + +_Released: 2013-07-16_ + + * Added `Uuid::fromBytes()` by merging in PR #14 from @asm89 + +## 2.2.0 + +_Released: 2013-07-04_ + + * Added `Doctrine\UuidType::requiresSQLCommentHint()` method by merging in PR #13 from @zerrvox + * Removed `"minimum-stability": "dev"` from composer.json + +## 2.1.2 + +_Released: 2013-07-03_ + + * @ericthelin found cases where the system node was coming back with uppercase hexadecimal digits; this ensures that case in the node is converted to lowercase + +## 2.1.1 + +_Released: 2013-04-29_ + + * Fixed NIL bug in `Uuid::isValid()` method, reported by @ocubom in PR #11 + +## 2.1.0 + +_Released: 2013-04-15_ + + * Added static `Uuid::isValid()` method for checking whether a string is a valid UUID + +## 2.0.0 + +_Released: 2013-02-11_ + + * Break: `Uuid` class is now marked as "final" + * Break: `Uuid::getLeastSignificantBits()` no longer returns an integer on 64-bit platforms; it requires `moontoast/math` + * Break: `Uuid::getMostSignificantBits()` no longer returns an integer on 64-bit platforms; it requires `moontoast/math` + * Break: Moved `UnsupportedOperationException` to the `Exception` subnamespace + * Added support for 32-bit platforms + * Added generated API documentation to the repository + +## 1.1.2 + +_Released: 2012-11-29_ + + * Relaxed Doctrine type conversion rules + +## 1.1.1 + +_Released: 2012-08-27_ + + * Removed `final` keyword from `Uuid` class + +## 1.1.0 + +_Released: 2012-08-06_ + + * Added `Doctrine\UuidType` as a field mapping type for the Doctrine Database Abstraction Layer (DBAL) + * Improved tests and code coverage + +## 1.0.0 + +_Released: 2012-07-19_ + + * Initial release + + +[paragonie/random_compat]: https://github.com/paragonie/random_compat +[collision issue]: https://github.com/ramsey/uuid/issues/80 diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/CODE_OF_CONDUCT.md b/lam/lib/3rdParty/composer/ramsey/uuid/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..9c207259 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project maintainer at . All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/CONTRIBUTING.md b/lam/lib/3rdParty/composer/ramsey/uuid/CONTRIBUTING.md new file mode 100644 index 00000000..4cde9b84 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/CONTRIBUTING.md @@ -0,0 +1,75 @@ +# Contributing + +Contributions are welcome. We accept pull requests on [GitHub](https://github.com/ramsey/uuid). + +This project adheres to a [Contributor Code of Conduct](https://github.com/ramsey/uuid/blob/master/CODE_OF_CONDUCT.md). By participating in this project and its community, you are expected to uphold this code. + +## Team members + +* [Ben Ramsey](https://github.com/ramsey) - original author and maintainer +* [Marijn Huizendveld](https://github.com/marijn) - contributor, author of UUID type definition for Doctrine DBAL +* [Thibaud Fabre](https://github.com/aztech-dev) - contributor, lead developer for version 3.0.0 re-architecture + +## Communication Channels + +You can find help and discussion in the following places: + +* GitHub Issues: +* Wiki: + +## Reporting Bugs + +Bugs are tracked in our project's [issue tracker](https://github.com/ramsey/uuid/issues). + +When submitting a bug report, please include enough information for us to reproduce the bug. A good bug report includes the following sections: + +* Expected outcome +* Actual outcome +* Steps to reproduce, including sample code +* Any other information that will help us debug and reproduce the issue, including stack traces, system/environment information, and screenshots + +**Please do not include passwords or any personally identifiable information in your bug report and sample code.** + +## Fixing Bugs + +We welcome pull requests to fix bugs! + +If you see a bug report that you'd like to fix, please feel free to do so. Following the directions and guidelines described in the "Adding New Features" section below, you may create bugfix branches and send us pull requests. + +## Adding New Features + +If you have an idea for a new feature, it's a good idea to check out our [issues](https://github.com/ramsey/uuid/issues) or active [pull requests](https://github.com/ramsey/uuid/pulls) first to see if the feature is already being worked on. If not, feel free to submit an issue first, asking whether the feature is beneficial to the project. This will save you from doing a lot of development work only to have your feature rejected. We don't enjoy rejecting your hard work, but some features just don't fit with the goals of the project. + +When you do begin working on your feature, here are some guidelines to consider: + +* Your pull request description should clearly detail the changes you have made. We will use this description to add to our CHANGELOG. If there is no description or it does not adequately describe your feature, we will ask you to update the description. +* We following the **[PSR-2 coding standard](http://www.php-fig.org/psr/psr-2/)**. Please ensure your code does, too. +* Please **write tests** for any new features you add. +* Please **ensure that tests pass** before submitting your pull request. We have Travis CI automatically running tests for pull requests. However, running the tests locally will help save time. +* **Use topic/feature branches.** Please do not ask us to pull from your master branch. +* **Submit one feature per pull request.** If you have multiple features you wish to submit, please break them up into separate pull requests. +* **Send coherent history**. Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before submitting. + +## Running Tests + +The following tests must pass before we will accept a pull request. If any of these do not pass, it will result in a complete build failure. Before you can run these, be sure to `composer install`. + +``` +composer test +``` + +### Locally Test With Emulated MIPS Architecture + +The following commands use [Vagrant](https://www.vagrantup.com/) to start an Ubuntu VM, install necessary dependencies, and then run the `tools/run-tests.sh` script that will download a Docker image emulating the MIPS architecture. This is especially helpful for testing UUID generation in a big-endian environment. + +``` +vagrant init ubuntu/trusty64 +vagrant up +vagrant ssh +sudo apt-get install docker.io qemu-user-static php5-cli php5-curl +cd /vagrant +curl -sS https://getcomposer.org/installer | php +php composer.phar install --no-interaction --prefer-dist +mkdir -p build/logs +ARCH=mips PHP_VERSION=5.6.14 TRAVIS_BUILD_DIR=/vagrant ./tools/run-tests.sh +``` diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/LICENSE b/lam/lib/3rdParty/composer/ramsey/uuid/LICENSE new file mode 100644 index 00000000..753a4c9c --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2012-2018 Ben Ramsey + +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/ramsey/uuid/README.md b/lam/lib/3rdParty/composer/ramsey/uuid/README.md new file mode 100644 index 00000000..b6557abb --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/README.md @@ -0,0 +1,159 @@ +# ramsey/uuid + +_NOTICE: Formerly known as `rhumsaa/uuid`, The package and namespace names have changed to `ramsey/uuid` and `Ramsey\Uuid`, respectively._ + +[![Source Code][badge-source]][source] +[![Latest Version][badge-release]][release] +[![Software License][badge-license]][license] +[![Build Status][badge-build]][build] +[![Coverage Status][badge-coverage]][coverage] +[![Total Downloads][badge-downloads]][downloads] + +ramsey/uuid is a PHP 5.4+ library for generating and working with [RFC 4122][rfc4122] version 1, 3, 4, and 5 universally unique identifiers (UUID). + +This project adheres to a [Contributor Code of Conduct][conduct]. By participating in this project and its community, you are expected to uphold this code. + + +## About + +From [Wikipedia](http://en.wikipedia.org/wiki/Universally_unique_identifier): + +> The intent of UUIDs is to enable distributed systems to uniquely identify information without significant central coordination. In this context the word unique should be taken to mean "practically unique" rather than "guaranteed unique". Since the identifiers have a finite size, it is possible for two differing items to share the same identifier. The identifier size and generation process need to be selected so as to make this sufficiently improbable in practice. Anyone can create a UUID and use it to identify something with reasonable confidence that the same identifier will never be unintentionally created by anyone to identify something else. Information labeled with UUIDs can therefore be later combined into a single database without needing to resolve identifier (ID) conflicts. + +Much inspiration for this library came from the [Java][javauuid] and [Python][pyuuid] UUID libraries. + + +## Installation + +The preferred method of installation is via [Packagist][] and [Composer][]. Run the following command to install the package and add it as a requirement to your project's `composer.json`: + +```bash +composer require ramsey/uuid +``` + + +## Upgrading from 2.x to 3.x + +While we have made significant internal changes to the library, we have made every effort to ensure a seamless upgrade path from the 2.x series of this library to 3.x. + +One major breaking change is the transition from the `Rhumsaa` root namespace to `Ramsey`. In most cases, all you will need is to change the namespace to `Ramsey` in your code, and everything will "just work." + +Here are full details on the breaking changes to the public API of this library: + +1. All namespace references of `Rhumsaa` have changed to `Ramsey`. Simply change the namespace to `Ramsey` in your code and everything should work. +2. The console application has moved to [ramsey/uuid-console](https://packagist.org/packages/ramsey/uuid-console). If using the console functionality, use Composer to require `ramsey/uuid-console`. +3. The Doctrine field type mapping has moved to [ramsey/uuid-doctrine](https://packagist.org/packages/ramsey/uuid-doctrine). If using the Doctrine functionality, use Composer to require `ramsey/uuid-doctrine`. + + +## What to do if you see a "rhumsaa/uuid is abandoned" message + +When installing your project's dependencies using Composer, you might see the following message: + +``` +Package rhumsaa/uuid is abandoned, you should avoid using it. Use ramsey/uuid instead. +``` + +Don't panic. Simply execute the following commands with Composer: + +``` bash +composer remove rhumsaa/uuid +composer require ramsey/uuid=^2.9 +``` + +After doing so, you will have the latest ramsey/uuid package in the 2.x series, and there will be no need to modify any code; the namespace in the 2.x series is still `Rhumsaa`. + + +## Requirements + +Some methods in this library have requirements due to integer size restrictions on 32-bit and 64-bit builds of PHP. A 64-bit build of PHP and the [Moontoast\Math][] library are recommended. However, this library is designed to work on 32-bit builds of PHP without Moontoast\Math, with some degraded functionality. Please check the API documentation for more information. + +If a particular requirement is not present, then an `UnsatisfiedDependencyException` is thrown, allowing one to catch a bad call in an environment where the call is not supported and gracefully degrade. + + +## API documentation + +The [latest class API documentation][apidocs] is available online. + +This project uses [ApiGen](http://apigen.org/) to generate this documentation. To generate the documentation on your own, install dev dependencies and run the following command from the root of the project: + +``` +composer build-docs +``` + +This will generate documentation in the `build/apidocs/` folder. + + +## Examples + +See the [cookbook on the wiki][wiki-cookbook] for more examples and approaches to specific use-cases. + +```php +toString() . "\n"; // i.e. e4eaaaf2-d142-11e1-b3e4-080027620cdd + + // Generate a version 3 (name-based and hashed with MD5) UUID object + $uuid3 = Uuid::uuid3(Uuid::NAMESPACE_DNS, 'php.net'); + echo $uuid3->toString() . "\n"; // i.e. 11a38b9a-b3da-360f-9353-a5a725514269 + + // Generate a version 4 (random) UUID object + $uuid4 = Uuid::uuid4(); + echo $uuid4->toString() . "\n"; // i.e. 25769c6c-d34d-4bfe-ba98-e0ee856f3e7a + + // Generate a version 5 (name-based and hashed with SHA1) UUID object + $uuid5 = Uuid::uuid5(Uuid::NAMESPACE_DNS, 'php.net'); + echo $uuid5->toString() . "\n"; // i.e. c4a760a8-dbcf-5254-a0d9-6a4474bd1b62 + +} catch (UnsatisfiedDependencyException $e) { + + // Some dependency was not met. Either the method cannot be called on a + // 32-bit system, or it can, but it relies on Moontoast\Math to be present. + echo 'Caught exception: ' . $e->getMessage() . "\n"; + +} +``` + + +## Contributing + +Contributions are welcome! Please read [CONTRIBUTING][] for details. + + +## Copyright and license + +The ramsey/uuid library is copyright © [Ben Ramsey](https://benramsey.com/) and licensed for use under the MIT License (MIT). Please see [LICENSE][] for more information. + + + +[rfc4122]: http://tools.ietf.org/html/rfc4122 +[conduct]: https://github.com/ramsey/uuid/blob/master/CODE_OF_CONDUCT.md +[javauuid]: http://docs.oracle.com/javase/6/docs/api/java/util/UUID.html +[pyuuid]: http://docs.python.org/3/library/uuid.html +[packagist]: https://packagist.org/packages/ramsey/uuid +[composer]: http://getcomposer.org/ +[moontoast\math]: https://packagist.org/packages/moontoast/math +[apidocs]: http://docs.benramsey.com/ramsey-uuid/latest/ +[wiki-cookbook]: https://github.com/ramsey/uuid/wiki/Ramsey%5CUuid-Cookbook +[contributing]: https://github.com/ramsey/uuid/blob/master/CONTRIBUTING.md + +[badge-source]: https://img.shields.io/badge/source-ramsey/uuid-blue.svg?style=flat-square +[badge-release]: https://img.shields.io/packagist/v/ramsey/uuid.svg?style=flat-square +[badge-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square +[badge-build]: https://img.shields.io/travis/ramsey/uuid/master.svg?style=flat-square +[badge-coverage]: https://img.shields.io/coveralls/ramsey/uuid/master.svg?style=flat-square +[badge-downloads]: https://img.shields.io/packagist/dt/ramsey/uuid.svg?style=flat-square + +[source]: https://github.com/ramsey/uuid +[release]: https://packagist.org/packages/ramsey/uuid +[license]: https://github.com/ramsey/uuid/blob/master/LICENSE +[build]: https://travis-ci.org/ramsey/uuid +[coverage]: https://coveralls.io/r/ramsey/uuid?branch=master +[downloads]: https://packagist.org/packages/ramsey/uuid diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/composer.json b/lam/lib/3rdParty/composer/ramsey/uuid/composer.json new file mode 100644 index 00000000..952120cd --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/composer.json @@ -0,0 +1,80 @@ +{ + "name": "ramsey/uuid", + "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).", + "type": "library", + "keywords": ["uuid", "identifier", "guid"], + "homepage": "https://github.com/ramsey/uuid", + "license": "MIT", + "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + }, + { + "name": "Marijn Huizendveld", + "email": "marijn.huizendveld@gmail.com" + }, + { + "name": "Thibaud Fabre", + "email": "thibaud@aztech.io" + } + ], + "support": { + "issues": "https://github.com/ramsey/uuid/issues", + "source": "https://github.com/ramsey/uuid" + }, + "require": { + "php": "^5.4 || ^7.0", + "paragonie/random_compat": "^1.0|^2.0|9.99.99", + "symfony/polyfill-ctype": "^1.8" + }, + "require-dev": { + "codeception/aspect-mock": "^1.0 | ~2.0.0", + "doctrine/annotations": "~1.2.0", + "goaop/framework": "1.0.0-alpha.2 | ^1.0 | ~2.1.0", + "ircmaxell/random-lib": "^1.1", + "jakub-onderka/php-parallel-lint": "^0.9.0", + "mockery/mockery": "^0.9.9", + "moontoast/math": "^1.1", + "php-mock/php-mock-phpunit": "^0.3|^1.1", + "phpunit/phpunit": "^4.7|^5.0|^6.5", + "squizlabs/php_codesniffer": "^2.3" + }, + "suggest": { + "ext-ctype": "Provides support for PHP Ctype functions", + "ircmaxell/random-lib": "Provides RandomLib for use with the RandomLibAdapter", + "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator", + "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator", + "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).", + "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type.", + "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid" + }, + "autoload": { + "psr-4": {"Ramsey\\Uuid\\": "src/"} + }, + "autoload-dev": { + "psr-4": {"Ramsey\\Uuid\\Test\\": "tests/"} + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "scripts": { + "lint": "parallel-lint src tests", + "phpunit": "phpunit --verbose --colors=always", + "phpcs": "phpcs src tests --standard=psr2 -sp --colors", + "test": [ + "@lint", + "@phpunit", + "@phpcs" + ] + }, + "config": { + "sort-packages": true + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/BinaryUtils.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/BinaryUtils.php new file mode 100644 index 00000000..f04a9d9c --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/BinaryUtils.php @@ -0,0 +1,43 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Builder; + +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Uuid; + +/** + * DefaultUuidBuilder is the default UUID builder for ramsey/uuid; it builds + * instances of Uuid objects + */ +class DefaultUuidBuilder implements UuidBuilderInterface +{ + /** + * @var NumberConverterInterface + */ + private $converter; + + /** + * Constructs the DefaultUuidBuilder + * + * @param NumberConverterInterface $converter The number converter to use when constructing the Uuid + */ + public function __construct(NumberConverterInterface $converter) + { + $this->converter = $converter; + } + + /** + * Builds a Uuid + * + * @param CodecInterface $codec The codec to use for building this Uuid + * @param array $fields An array of fields from which to construct the Uuid; + * see {@see \Ramsey\Uuid\UuidInterface::getFieldsHex()} for array structure. + * @return Uuid + */ + public function build(CodecInterface $codec, array $fields) + { + return new Uuid($fields, $this->converter, $codec); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Builder/DegradedUuidBuilder.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Builder/DegradedUuidBuilder.php new file mode 100644 index 00000000..7edb6deb --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Builder/DegradedUuidBuilder.php @@ -0,0 +1,53 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Builder; + +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\DegradedUuid; + +/** + * DegradedUuidBuilder builds instances of DegradedUuid + */ +class DegradedUuidBuilder implements UuidBuilderInterface +{ + /** + * @var NumberConverterInterface + */ + private $converter; + + /** + * Constructs the DegradedUuidBuilder + * + * @param NumberConverterInterface $converter The number converter to use when constructing the DegradedUuid + */ + public function __construct(NumberConverterInterface $converter) + { + $this->converter = $converter; + } + + /** + * Builds a DegradedUuid + * + * @param CodecInterface $codec The codec to use for building this DegradedUuid + * @param array $fields An array of fields from which to construct the DegradedUuid; + * see {@see \Ramsey\Uuid\UuidInterface::getFieldsHex()} for array structure. + * @return DegradedUuid + */ + public function build(CodecInterface $codec, array $fields) + { + return new DegradedUuid($fields, $this->converter, $codec); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Builder/UuidBuilderInterface.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Builder/UuidBuilderInterface.php new file mode 100644 index 00000000..e4e99010 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Builder/UuidBuilderInterface.php @@ -0,0 +1,34 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Builder; + +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\UuidInterface; + +/** + * UuidBuilderInterface builds instances UuidInterface + */ +interface UuidBuilderInterface +{ + /** + * Builds an instance of a UuidInterface + * + * @param CodecInterface $codec The codec to use for building this UuidInterface instance + * @param array $fields An array of fields from which to construct a UuidInterface instance; + * see {@see \Ramsey\Uuid\UuidInterface::getFieldsHex()} for array structure. + * @return UuidInterface + */ + public function build(CodecInterface $codec, array $fields); +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/CodecInterface.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/CodecInterface.php new file mode 100644 index 00000000..6ea20544 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/CodecInterface.php @@ -0,0 +1,58 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Codec; + +use Ramsey\Uuid\UuidInterface; + +/** + * CodecInterface represents a UUID coder-decoder + */ +interface CodecInterface +{ + /** + * Encodes a UuidInterface as a string representation of a UUID + * + * @param UuidInterface $uuid + * @return string Hexadecimal string representation of a UUID + */ + public function encode(UuidInterface $uuid); + + /** + * Encodes a UuidInterface as a binary representation of a UUID + * + * @param UuidInterface $uuid + * @return string Binary string representation of a UUID + */ + public function encodeBinary(UuidInterface $uuid); + + /** + * Decodes a string representation of a UUID into a UuidInterface object instance + * + * @param string $encodedUuid + * @return UuidInterface + * @throws \Ramsey\Uuid\Exception\InvalidUuidStringException + */ + public function decode($encodedUuid); + + /** + * Decodes a binary representation of a UUID into a UuidInterface object instance + * + * @param string $bytes + * @return UuidInterface + * @throws \Ramsey\Uuid\Exception\InvalidUuidStringException + * @throws \InvalidArgumentException if string has not 16 characters + */ + public function decodeBytes($bytes); +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/GuidStringCodec.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/GuidStringCodec.php new file mode 100644 index 00000000..864980b3 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/GuidStringCodec.php @@ -0,0 +1,102 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Codec; + +use Ramsey\Uuid\UuidInterface; + +/** + * GuidStringCodec encodes and decodes globally unique identifiers (GUID) + * + * @link https://en.wikipedia.org/wiki/Globally_unique_identifier + */ +class GuidStringCodec extends StringCodec +{ + /** + * Encodes a UuidInterface as a string representation of a GUID + * + * @param UuidInterface $uuid + * @return string Hexadecimal string representation of a GUID + */ + public function encode(UuidInterface $uuid) + { + $components = array_values($uuid->getFieldsHex()); + + // Swap byte-order on the first three fields + $this->swapFields($components); + + return vsprintf( + '%08s-%04s-%04s-%02s%02s-%012s', + $components + ); + } + + /** + * Encodes a UuidInterface as a binary representation of a GUID + * + * @param UuidInterface $uuid + * @return string Binary string representation of a GUID + */ + public function encodeBinary(UuidInterface $uuid) + { + $components = array_values($uuid->getFieldsHex()); + + return hex2bin(implode('', $components)); + } + + /** + * Decodes a string representation of a GUID into a UuidInterface object instance + * + * @param string $encodedUuid + * @return UuidInterface + * @throws \Ramsey\Uuid\Exception\InvalidUuidStringException + */ + public function decode($encodedUuid) + { + $components = $this->extractComponents($encodedUuid); + + $this->swapFields($components); + + return $this->getBuilder()->build($this, $this->getFields($components)); + } + + /** + * Decodes a binary representation of a GUID into a UuidInterface object instance + * + * @param string $bytes + * @return UuidInterface + * @throws \Ramsey\Uuid\Exception\InvalidUuidStringException + */ + public function decodeBytes($bytes) + { + // Specifically call parent::decode to preserve correct byte order + return parent::decode(bin2hex($bytes)); + } + + /** + * Swaps fields to support GUID byte order + * + * @param array $components An array of UUID components (the UUID exploded on its dashes) + * @return void + */ + protected function swapFields(array &$components) + { + $hex = unpack('H*', pack('L', hexdec($components[0]))); + $components[0] = $hex[1]; + $hex = unpack('H*', pack('S', hexdec($components[1]))); + $components[1] = $hex[1]; + $hex = unpack('H*', pack('S', hexdec($components[2]))); + $components[2] = $hex[1]; + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/OrderedTimeCodec.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/OrderedTimeCodec.php new file mode 100644 index 00000000..3257759c --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/OrderedTimeCodec.php @@ -0,0 +1,68 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ +namespace Ramsey\Uuid\Codec; + +use InvalidArgumentException; +use Ramsey\Uuid\UuidInterface; + +/** + * OrderedTimeCodec optimizes the bytes to increment UUIDs when time goes by, to improve database INSERTs. + * The string value will be unchanged from StringCodec. Only works for UUID type 1. + */ +class OrderedTimeCodec extends StringCodec +{ + + /** + * Encodes a UuidInterface as an optimized binary representation of a UUID + * + * @param UuidInterface $uuid + * @return string Binary string representation of a UUID + */ + public function encodeBinary(UuidInterface $uuid) + { + $fields = $uuid->getFieldsHex(); + + $optimized = [ + $fields['time_hi_and_version'], + $fields['time_mid'], + $fields['time_low'], + $fields['clock_seq_hi_and_reserved'], + $fields['clock_seq_low'], + $fields['node'], + ]; + + return hex2bin(implode('', $optimized)); + } + + /** + * Decodes an optimized binary representation of a UUID into a UuidInterface object instance + * + * @param string $bytes + * @return UuidInterface + * @throws \InvalidArgumentException if string has not 16 characters + */ + public function decodeBytes($bytes) + { + if (strlen($bytes) !== 16) { + throw new InvalidArgumentException('$bytes string should contain 16 characters.'); + } + + $hex = unpack('H*', $bytes)[1]; + + // Rearrange the fields to their original order + $hex = substr($hex, 8, 4) . substr($hex, 12, 4) . substr($hex, 4, 4) . substr($hex, 0, 4) . substr($hex, 16); + + return $this->decode($hex); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/StringCodec.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/StringCodec.php new file mode 100644 index 00000000..7f352065 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/StringCodec.php @@ -0,0 +1,170 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Codec; + +use InvalidArgumentException; +use Ramsey\Uuid\Builder\UuidBuilderInterface; +use Ramsey\Uuid\Exception\InvalidUuidStringException; +use Ramsey\Uuid\Uuid; +use Ramsey\Uuid\UuidInterface; + +/** + * StringCodec encodes and decodes RFC 4122 UUIDs + * + * @link http://tools.ietf.org/html/rfc4122 + */ +class StringCodec implements CodecInterface +{ + /** + * @var UuidBuilderInterface + */ + private $builder; + + /** + * Constructs a StringCodec for use encoding and decoding UUIDs + * + * @param UuidBuilderInterface $builder The UUID builder to use when encoding UUIDs + */ + public function __construct(UuidBuilderInterface $builder) + { + $this->builder = $builder; + } + + /** + * Encodes a UuidInterface as a string representation of a UUID + * + * @param UuidInterface $uuid + * @return string Hexadecimal string representation of a UUID + */ + public function encode(UuidInterface $uuid) + { + $fields = array_values($uuid->getFieldsHex()); + + return vsprintf( + '%08s-%04s-%04s-%02s%02s-%012s', + $fields + ); + } + + /** + * Encodes a UuidInterface as a binary representation of a UUID + * + * @param UuidInterface $uuid + * @return string Binary string representation of a UUID + */ + public function encodeBinary(UuidInterface $uuid) + { + return hex2bin($uuid->getHex()); + } + + /** + * Decodes a string representation of a UUID into a UuidInterface object instance + * + * @param string $encodedUuid + * @return UuidInterface + * @throws \Ramsey\Uuid\Exception\InvalidUuidStringException + */ + public function decode($encodedUuid) + { + $components = $this->extractComponents($encodedUuid); + $fields = $this->getFields($components); + + return $this->builder->build($this, $fields); + } + + /** + * Decodes a binary representation of a UUID into a UuidInterface object instance + * + * @param string $bytes + * @return UuidInterface + * @throws \InvalidArgumentException if string has not 16 characters + */ + public function decodeBytes($bytes) + { + if (strlen($bytes) !== 16) { + throw new InvalidArgumentException('$bytes string should contain 16 characters.'); + } + + $hexUuid = unpack('H*', $bytes); + + return $this->decode($hexUuid[1]); + } + + /** + * Returns the UUID builder + * + * @return UuidBuilderInterface + */ + protected function getBuilder() + { + return $this->builder; + } + + /** + * Returns an array of UUID components (the UUID exploded on its dashes) + * + * @param string $encodedUuid + * @return array + * @throws \Ramsey\Uuid\Exception\InvalidUuidStringException + */ + protected function extractComponents($encodedUuid) + { + $nameParsed = str_replace(array( + 'urn:', + 'uuid:', + '{', + '}', + '-' + ), '', $encodedUuid); + + // We have stripped out the dashes and are breaking up the string using + // substr(). In this way, we can accept a full hex value that doesn't + // contain dashes. + $components = array( + substr($nameParsed, 0, 8), + substr($nameParsed, 8, 4), + substr($nameParsed, 12, 4), + substr($nameParsed, 16, 4), + substr($nameParsed, 20) + ); + + $nameParsed = implode('-', $components); + + if (!Uuid::isValid($nameParsed)) { + throw new InvalidUuidStringException('Invalid UUID string: ' . $encodedUuid); + } + + return $components; + } + + /** + * Returns the fields that make up this UUID + * + * @see \Ramsey\Uuid\UuidInterface::getFieldsHex() + * @param array $components + * @return array + */ + protected function getFields(array $components) + { + return array( + 'time_low' => str_pad($components[0], 8, '0', STR_PAD_LEFT), + 'time_mid' => str_pad($components[1], 4, '0', STR_PAD_LEFT), + 'time_hi_and_version' => str_pad($components[2], 4, '0', STR_PAD_LEFT), + 'clock_seq_hi_and_reserved' => str_pad(substr($components[3], 0, 2), 2, '0', STR_PAD_LEFT), + 'clock_seq_low' => str_pad(substr($components[3], 2), 2, '0', STR_PAD_LEFT), + 'node' => str_pad($components[4], 12, '0', STR_PAD_LEFT) + ); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/TimestampFirstCombCodec.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/TimestampFirstCombCodec.php new file mode 100644 index 00000000..2c4ded89 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/TimestampFirstCombCodec.php @@ -0,0 +1,107 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ +namespace Ramsey\Uuid\Codec; + +use Ramsey\Uuid\UuidInterface; + +/** + * TimestampLastCombCodec encodes and decodes COMB UUIDs which have the timestamp as the first 48 bits. + * To be used with MySQL, PostgreSQL, Oracle. + */ +class TimestampFirstCombCodec extends StringCodec +{ + /** + * Encodes a UuidInterface as a string representation of a timestamp first COMB UUID + * + * @param UuidInterface $uuid + * + * @return string Hexadecimal string representation of a GUID + */ + public function encode(UuidInterface $uuid) + { + $sixPieceComponents = array_values($uuid->getFieldsHex()); + + $this->swapTimestampAndRandomBits($sixPieceComponents); + + return vsprintf( + '%08s-%04s-%04s-%02s%02s-%012s', + $sixPieceComponents + ); + } + + /** + * Encodes a UuidInterface as a binary representation of timestamp first COMB UUID + * + * @param UuidInterface $uuid + * + * @return string Binary string representation of timestamp first COMB UUID + */ + public function encodeBinary(UuidInterface $uuid) + { + $stringEncoding = $this->encode($uuid); + + return hex2bin(str_replace('-', '', $stringEncoding)); + } + + /** + * Decodes a string representation of timestamp first COMB UUID into a UuidInterface object instance + * + * @param string $encodedUuid + * + * @return UuidInterface + * @throws \Ramsey\Uuid\Exception\InvalidUuidStringException + */ + public function decode($encodedUuid) + { + $fivePieceComponents = $this->extractComponents($encodedUuid); + + $this->swapTimestampAndRandomBits($fivePieceComponents); + + return $this->getBuilder()->build($this, $this->getFields($fivePieceComponents)); + } + + /** + * Decodes a binary representation of timestamp first COMB UUID into a UuidInterface object instance + * + * @param string $bytes + * + * @return UuidInterface + * @throws \Ramsey\Uuid\Exception\InvalidUuidStringException + */ + public function decodeBytes($bytes) + { + return $this->decode(bin2hex($bytes)); + } + + /** + * Swaps the first 48 bits with the last 48 bits + * + * @param array $components An array of UUID components (the UUID exploded on its dashes) + * + * @return void + */ + protected function swapTimestampAndRandomBits(array &$components) + { + $last48Bits = $components[4]; + if (count($components) == 6) { + $last48Bits = $components[5]; + $components[5] = $components[0] . $components[1]; + } else { + $components[4] = $components[0] . $components[1]; + } + + $components[0] = substr($last48Bits, 0, 8); + $components[1] = substr($last48Bits, 8, 4); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/TimestampLastCombCodec.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/TimestampLastCombCodec.php new file mode 100644 index 00000000..0cdd009a --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Codec/TimestampLastCombCodec.php @@ -0,0 +1,23 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ +namespace Ramsey\Uuid\Codec; + +/** + * TimestampLastCombCodec encodes and decodes COMB UUIDs which have the timestamp as the last 48 bits. + * To be used with MSSQL. + */ +class TimestampLastCombCodec extends StringCodec +{ + +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/Number/BigNumberConverter.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/Number/BigNumberConverter.php new file mode 100644 index 00000000..d2351225 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/Number/BigNumberConverter.php @@ -0,0 +1,54 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Converter\Number; + +use Moontoast\Math\BigNumber; +use Ramsey\Uuid\Converter\NumberConverterInterface; + +/** + * BigNumberConverter converts UUIDs from hexadecimal characters into + * moontoast/math `BigNumber` representations of integers and vice versa + */ +class BigNumberConverter implements NumberConverterInterface +{ + /** + * Converts a hexadecimal number into a `Moontoast\Math\BigNumber` representation + * + * @param string $hex The hexadecimal string representation to convert + * @return BigNumber + */ + public function fromHex($hex) + { + $number = BigNumber::convertToBase10($hex, 16); + + return new BigNumber($number); + } + + /** + * Converts an integer or `Moontoast\Math\BigNumber` integer representation + * into a hexadecimal string representation + * + * @param int|string|BigNumber $integer An integer or `Moontoast\Math\BigNumber` + * @return string Hexadecimal string + */ + public function toHex($integer) + { + if (!$integer instanceof BigNumber) { + $integer = new BigNumber($integer); + } + + return BigNumber::convertFromBase10($integer, 16); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/Number/DegradedNumberConverter.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/Number/DegradedNumberConverter.php new file mode 100644 index 00000000..96a011c6 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/Number/DegradedNumberConverter.php @@ -0,0 +1,58 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Converter\Number; + +use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; +use Ramsey\Uuid\Converter\NumberConverterInterface; + +/** + * DegradedNumberConverter throws `UnsatisfiedDependencyException` exceptions + * if attempting to use number conversion functionality in an environment that + * does not support large integers (i.e. when moontoast/math is not available) + */ +class DegradedNumberConverter implements NumberConverterInterface +{ + /** + * Throws an `UnsatisfiedDependencyException` + * + * @param string $hex The hexadecimal string representation to convert + * @return void + * @throws UnsatisfiedDependencyException + */ + public function fromHex($hex) + { + throw new UnsatisfiedDependencyException( + 'Cannot call ' . __METHOD__ . ' without support for large ' + . 'integers, since integer is an unsigned ' + . '128-bit integer; Moontoast\Math\BigNumber is required.' + ); + } + + /** + * Throws an `UnsatisfiedDependencyException` + * + * @param mixed $integer An integer representation to convert + * @return void + * @throws UnsatisfiedDependencyException + */ + public function toHex($integer) + { + throw new UnsatisfiedDependencyException( + 'Cannot call ' . __METHOD__ . ' without support for large ' + . 'integers, since integer is an unsigned ' + . '128-bit integer; Moontoast\Math\BigNumber is required. ' + ); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/NumberConverterInterface.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/NumberConverterInterface.php new file mode 100644 index 00000000..9505e8c6 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/NumberConverterInterface.php @@ -0,0 +1,46 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Converter; + +/** + * NumberConverterInterface converts UUIDs from hexadecimal characters into + * representations of integers and vice versa + */ +interface NumberConverterInterface +{ + /** + * Converts a hexadecimal number into an integer representation of the number + * + * The integer representation returned may be an object or a string + * representation of the integer, depending on the implementation. + * + * @param string $hex The hexadecimal string representation to convert + * @return mixed + * @throws \Ramsey\Uuid\Exception\UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present + */ + public function fromHex($hex); + + /** + * Converts an integer representation into a hexadecimal string representation + * of the number + * + * @param mixed $integer An integer representation to convert; this may be + * a true integer, a string integer, or a object representation that + * this converter can understand + * @return string Hexadecimal string + * @throws \Ramsey\Uuid\Exception\UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present + */ + public function toHex($integer); +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/Time/BigNumberTimeConverter.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/Time/BigNumberTimeConverter.php new file mode 100644 index 00000000..d47c8019 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/Time/BigNumberTimeConverter.php @@ -0,0 +1,58 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Converter\Time; + +use Moontoast\Math\BigNumber; +use Ramsey\Uuid\Converter\TimeConverterInterface; + +/** + * BigNumberTimeConverter uses the moontoast/math library's `BigNumber` to + * provide facilities for converting parts of time into representations that may + * be used in UUIDs + */ +class BigNumberTimeConverter implements TimeConverterInterface +{ + /** + * Uses the provided seconds and micro-seconds to calculate the time_low, + * time_mid, and time_high fields used by RFC 4122 version 1 UUIDs + * + * @param string $seconds + * @param string $microSeconds + * @return string[] An array containing `low`, `mid`, and `high` keys + * @link http://tools.ietf.org/html/rfc4122#section-4.2.2 + */ + public function calculateTime($seconds, $microSeconds) + { + $uuidTime = new BigNumber('0'); + + $sec = new BigNumber($seconds); + $sec->multiply('10000000'); + + $usec = new BigNumber($microSeconds); + $usec->multiply('10'); + + $uuidTime->add($sec) + ->add($usec) + ->add('122192928000000000'); + + $uuidTimeHex = sprintf('%016s', $uuidTime->convertToBase(16)); + + return array( + 'low' => substr($uuidTimeHex, 8), + 'mid' => substr($uuidTimeHex, 4, 4), + 'hi' => substr($uuidTimeHex, 0, 4), + ); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/Time/DegradedTimeConverter.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/Time/DegradedTimeConverter.php new file mode 100644 index 00000000..b94589cd --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/Time/DegradedTimeConverter.php @@ -0,0 +1,42 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Converter\Time; + +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; + +/** + * DegradedTimeConverter throws `UnsatisfiedDependencyException` exceptions + * if attempting to use time conversion functionality in an environment that + * does not support large integers (i.e. when moontoast/math is not available) + */ +class DegradedTimeConverter implements TimeConverterInterface +{ + /** + * Throws an `UnsatisfiedDependencyException` + * + * @param string $seconds + * @param string $microSeconds + * @return void + * @throws UnsatisfiedDependencyException if called on a 32-bit system and `Moontoast\Math\BigNumber` is not present + */ + public function calculateTime($seconds, $microSeconds) + { + throw new UnsatisfiedDependencyException( + 'When calling ' . __METHOD__ . ' on a 32-bit system, ' + . 'Moontoast\Math\BigNumber must be present.' + ); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/Time/PhpTimeConverter.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/Time/PhpTimeConverter.php new file mode 100644 index 00000000..6a9da74b --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/Time/PhpTimeConverter.php @@ -0,0 +1,47 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Converter\Time; + +use Ramsey\Uuid\Converter\TimeConverterInterface; + +/** + * PhpTimeConverter uses built-in PHP functions and standard math operations + * available to the PHP programming language to provide facilities for + * converting parts of time into representations that may be used in UUIDs + */ +class PhpTimeConverter implements TimeConverterInterface +{ + /** + * Uses the provided seconds and micro-seconds to calculate the time_low, + * time_mid, and time_high fields used by RFC 4122 version 1 UUIDs + * + * @param string $seconds + * @param string $microSeconds + * @return string[] An array containing `low`, `mid`, and `high` keys + * @link http://tools.ietf.org/html/rfc4122#section-4.2.2 + */ + public function calculateTime($seconds, $microSeconds) + { + // 0x01b21dd213814000 is the number of 100-ns intervals between the + // UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00. + $uuidTime = ($seconds * 10000000) + ($microSeconds * 10) + 0x01b21dd213814000; + + return array( + 'low' => sprintf('%08x', $uuidTime & 0xffffffff), + 'mid' => sprintf('%04x', ($uuidTime >> 32) & 0xffff), + 'hi' => sprintf('%04x', ($uuidTime >> 48) & 0x0fff), + ); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/TimeConverterInterface.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/TimeConverterInterface.php new file mode 100644 index 00000000..382008ac --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Converter/TimeConverterInterface.php @@ -0,0 +1,35 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Converter; + +/** + * TimeConverterInterface provides facilities for converting parts of time into + * representations that may be used in UUIDs + */ +interface TimeConverterInterface +{ + /** + * Uses the provided seconds and micro-seconds to calculate the time_low, + * time_mid, and time_high fields used by RFC 4122 version 1 UUIDs + * + * @param string $seconds + * @param string $microSeconds + * @return string[] An array guaranteed to contain `low`, `mid`, and `high` keys + * @throws \Ramsey\Uuid\Exception\UnsatisfiedDependencyException if called on a 32-bit system and + * `Moontoast\Math\BigNumber` is not present + * @link http://tools.ietf.org/html/rfc4122#section-4.2.2 + */ + public function calculateTime($seconds, $microSeconds); +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/DegradedUuid.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/DegradedUuid.php new file mode 100644 index 00000000..bcf0be80 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/DegradedUuid.php @@ -0,0 +1,114 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid; + +use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; +use Ramsey\Uuid\Exception\UnsupportedOperationException; + +/** + * DegradedUuid represents an RFC 4122 UUID on 32-bit systems + * + * @see Uuid + */ +class DegradedUuid extends Uuid +{ + /** + * @inheritdoc + */ + public function getDateTime() + { + if ($this->getVersion() != 1) { + throw new UnsupportedOperationException('Not a time-based UUID'); + } + + $time = $this->converter->fromHex($this->getTimestampHex()); + + $ts = new \Moontoast\Math\BigNumber($time, 20); + $ts->subtract('122192928000000000'); + $ts->divide('10000000.0'); + $ts->round(); + $unixTime = $ts->getValue(); + + return new \DateTime("@{$unixTime}"); + } + + /** + * For degraded UUIDs, throws an `UnsatisfiedDependencyException` when + * called on a 32-bit system + * + * @throws UnsatisfiedDependencyException if called on a 32-bit system + */ + public function getFields() + { + throw new UnsatisfiedDependencyException( + 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since some ' + . 'values overflow the system max integer value' + . '; consider calling getFieldsHex instead' + ); + } + + /** + * For degraded UUIDs, throws an `UnsatisfiedDependencyException` when + * called on a 32-bit system + * + * @throws UnsatisfiedDependencyException if called on a 32-bit system + */ + public function getNode() + { + throw new UnsatisfiedDependencyException( + 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since node ' + . 'is an unsigned 48-bit integer and can overflow the system ' + . 'max integer value' + . '; consider calling getNodeHex instead' + ); + } + + /** + * For degraded UUIDs, throws an `UnsatisfiedDependencyException` when + * called on a 32-bit system + * + * @throws UnsatisfiedDependencyException if called on a 32-bit system + */ + public function getTimeLow() + { + throw new UnsatisfiedDependencyException( + 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since time_low ' + . 'is an unsigned 32-bit integer and can overflow the system ' + . 'max integer value' + . '; consider calling getTimeLowHex instead' + ); + } + + /** + * For degraded UUIDs, throws an `UnsatisfiedDependencyException` when + * called on a 32-bit system + * + * @throws UnsatisfiedDependencyException if called on a 32-bit system + * @throws UnsupportedOperationException If this UUID is not a version 1 UUID + */ + public function getTimestamp() + { + if ($this->getVersion() != 1) { + throw new UnsupportedOperationException('Not a time-based UUID'); + } + + throw new UnsatisfiedDependencyException( + 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since timestamp ' + . 'is an unsigned 60-bit integer and can overflow the system ' + . 'max integer value' + . '; consider calling getTimestampHex instead' + ); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Exception/InvalidUuidStringException.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Exception/InvalidUuidStringException.php new file mode 100644 index 00000000..0e480649 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Exception/InvalidUuidStringException.php @@ -0,0 +1,22 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Exception; + +/** + * Thrown to indicate that the parsed UUID string is invalid. + */ +class InvalidUuidStringException extends \InvalidArgumentException +{ +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Exception/UnsatisfiedDependencyException.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Exception/UnsatisfiedDependencyException.php new file mode 100644 index 00000000..8b5d5d08 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Exception/UnsatisfiedDependencyException.php @@ -0,0 +1,23 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Exception; + +/** + * Thrown to indicate that the requested operation has dependencies that have not + * been satisfied. + */ +class UnsatisfiedDependencyException extends \RuntimeException +{ +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Exception/UnsupportedOperationException.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Exception/UnsupportedOperationException.php new file mode 100644 index 00000000..b371b682 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Exception/UnsupportedOperationException.php @@ -0,0 +1,22 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Exception; + +/** + * Thrown to indicate that the requested operation is not supported. + */ +class UnsupportedOperationException extends \RuntimeException +{ +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/FeatureSet.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/FeatureSet.php new file mode 100644 index 00000000..56a774ea --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/FeatureSet.php @@ -0,0 +1,333 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid; + +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Generator\PeclUuidTimeGenerator; +use Ramsey\Uuid\Provider\Node\FallbackNodeProvider; +use Ramsey\Uuid\Provider\Node\RandomNodeProvider; +use Ramsey\Uuid\Provider\Node\SystemNodeProvider; +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Converter\Number\BigNumberConverter; +use Ramsey\Uuid\Converter\Number\DegradedNumberConverter; +use Ramsey\Uuid\Converter\Time\BigNumberTimeConverter; +use Ramsey\Uuid\Converter\Time\DegradedTimeConverter; +use Ramsey\Uuid\Converter\Time\PhpTimeConverter; +use Ramsey\Uuid\Provider\Time\SystemTimeProvider; +use Ramsey\Uuid\Builder\UuidBuilderInterface; +use Ramsey\Uuid\Builder\DefaultUuidBuilder; +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Codec\StringCodec; +use Ramsey\Uuid\Codec\GuidStringCodec; +use Ramsey\Uuid\Builder\DegradedUuidBuilder; +use Ramsey\Uuid\Generator\RandomGeneratorFactory; +use Ramsey\Uuid\Generator\RandomGeneratorInterface; +use Ramsey\Uuid\Generator\TimeGeneratorFactory; +use Ramsey\Uuid\Generator\TimeGeneratorInterface; +use Ramsey\Uuid\Provider\TimeProviderInterface; +use Ramsey\Uuid\Provider\NodeProviderInterface; + +/** + * FeatureSet detects and exposes available features in the current environment + * (32- or 64-bit, available dependencies, etc.) + */ +class FeatureSet +{ + /** + * @var bool + */ + private $disableBigNumber = false; + + /** + * @var bool + */ + private $disable64Bit = false; + + /** + * @var bool + */ + private $ignoreSystemNode = false; + + /** + * @var bool + */ + private $enablePecl = false; + + /** + * @var UuidBuilderInterface + */ + private $builder; + + /** + * @var CodecInterface + */ + private $codec; + + /** + * @var NodeProviderInterface + */ + private $nodeProvider; + + /** + * @var NumberConverterInterface + */ + private $numberConverter; + + /** + * @var RandomGeneratorInterface + */ + private $randomGenerator; + + /** + * @var TimeGeneratorInterface + */ + private $timeGenerator; + + /** + * Constructs a `FeatureSet` for use by a `UuidFactory` to determine or set + * features available to the environment + * + * @param bool $useGuids Whether to build UUIDs using the `GuidStringCodec` + * @param bool $force32Bit Whether to force the use of 32-bit functionality + * (primarily for testing purposes) + * @param bool $forceNoBigNumber Whether to disable the use of moontoast/math + * `BigNumber` (primarily for testing purposes) + * @param bool $ignoreSystemNode Whether to disable attempts to check for + * the system host ID (primarily for testing purposes) + * @param bool $enablePecl Whether to enable the use of the `PeclUuidTimeGenerator` + * to generate version 1 UUIDs + */ + public function __construct( + $useGuids = false, + $force32Bit = false, + $forceNoBigNumber = false, + $ignoreSystemNode = false, + $enablePecl = false + ) { + $this->disableBigNumber = $forceNoBigNumber; + $this->disable64Bit = $force32Bit; + $this->ignoreSystemNode = $ignoreSystemNode; + $this->enablePecl = $enablePecl; + + $this->numberConverter = $this->buildNumberConverter(); + $this->builder = $this->buildUuidBuilder(); + $this->codec = $this->buildCodec($useGuids); + $this->nodeProvider = $this->buildNodeProvider(); + $this->randomGenerator = $this->buildRandomGenerator(); + $this->setTimeProvider(new SystemTimeProvider()); + } + + /** + * Returns the builder configured for this environment + * + * @return UuidBuilderInterface + */ + public function getBuilder() + { + return $this->builder; + } + + /** + * Returns the UUID UUID coder-decoder configured for this environment + * + * @return CodecInterface + */ + public function getCodec() + { + return $this->codec; + } + + /** + * Returns the system node ID provider configured for this environment + * + * @return NodeProviderInterface + */ + public function getNodeProvider() + { + return $this->nodeProvider; + } + + /** + * Returns the number converter configured for this environment + * + * @return NumberConverterInterface + */ + public function getNumberConverter() + { + return $this->numberConverter; + } + + /** + * Returns the random UUID generator configured for this environment + * + * @return RandomGeneratorInterface + */ + public function getRandomGenerator() + { + return $this->randomGenerator; + } + + /** + * Returns the time-based UUID generator configured for this environment + * + * @return TimeGeneratorInterface + */ + public function getTimeGenerator() + { + return $this->timeGenerator; + } + + /** + * Sets the time provider for use in this environment + * + * @param TimeProviderInterface $timeProvider + */ + public function setTimeProvider(TimeProviderInterface $timeProvider) + { + $this->timeGenerator = $this->buildTimeGenerator($timeProvider); + } + + /** + * Determines which UUID coder-decoder to use and returns the configured + * codec for this environment + * + * @param bool $useGuids Whether to build UUIDs using the `GuidStringCodec` + * @return CodecInterface + */ + protected function buildCodec($useGuids = false) + { + if ($useGuids) { + return new GuidStringCodec($this->builder); + } + + return new StringCodec($this->builder); + } + + /** + * Determines which system node ID provider to use and returns the configured + * system node ID provider for this environment + * + * @return NodeProviderInterface + */ + protected function buildNodeProvider() + { + if ($this->ignoreSystemNode) { + return new RandomNodeProvider(); + } + + return new FallbackNodeProvider([ + new SystemNodeProvider(), + new RandomNodeProvider() + ]); + } + + /** + * Determines which number converter to use and returns the configured + * number converter for this environment + * + * @return NumberConverterInterface + */ + protected function buildNumberConverter() + { + if ($this->hasBigNumber()) { + return new BigNumberConverter(); + } + + return new DegradedNumberConverter(); + } + + /** + * Determines which random UUID generator to use and returns the configured + * random UUID generator for this environment + * + * @return RandomGeneratorInterface + */ + protected function buildRandomGenerator() + { + return (new RandomGeneratorFactory())->getGenerator(); + } + + /** + * Determines which time-based UUID generator to use and returns the configured + * time-based UUID generator for this environment + * + * @param TimeProviderInterface $timeProvider + * @return TimeGeneratorInterface + */ + protected function buildTimeGenerator(TimeProviderInterface $timeProvider) + { + if ($this->enablePecl) { + return new PeclUuidTimeGenerator(); + } + + return (new TimeGeneratorFactory( + $this->nodeProvider, + $this->buildTimeConverter(), + $timeProvider + ))->getGenerator(); + } + + /** + * Determines which time converter to use and returns the configured + * time converter for this environment + * + * @return TimeConverterInterface + */ + protected function buildTimeConverter() + { + if ($this->is64BitSystem()) { + return new PhpTimeConverter(); + } elseif ($this->hasBigNumber()) { + return new BigNumberTimeConverter(); + } + + return new DegradedTimeConverter(); + } + + /** + * Determines which UUID builder to use and returns the configured UUID + * builder for this environment + * + * @return UuidBuilderInterface + */ + protected function buildUuidBuilder() + { + if ($this->is64BitSystem()) { + return new DefaultUuidBuilder($this->numberConverter); + } + + return new DegradedUuidBuilder($this->numberConverter); + } + + /** + * Returns true if the system has `Moontoast\Math\BigNumber` + * + * @return bool + */ + protected function hasBigNumber() + { + return class_exists('Moontoast\Math\BigNumber') && !$this->disableBigNumber; + } + + /** + * Returns true if the system is 64-bit, false otherwise + * + * @return bool + */ + protected function is64BitSystem() + { + return PHP_INT_SIZE == 8 && !$this->disable64Bit; + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/CombGenerator.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/CombGenerator.php new file mode 100644 index 00000000..7a948231 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/CombGenerator.php @@ -0,0 +1,88 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Generator; + +use Ramsey\Uuid\Converter\NumberConverterInterface; + +/** + * CombGenerator provides functionality to generate COMB (combined GUID/timestamp) + * sequential UUIDs + * + * @link https://en.wikipedia.org/wiki/Globally_unique_identifier#Sequential_algorithms + */ +class CombGenerator implements RandomGeneratorInterface +{ + const TIMESTAMP_BYTES = 6; + + /** + * @var RandomGeneratorInterface + */ + private $randomGenerator; + + /** + * @var NumberConverterInterface + */ + private $converter; + + /** + * Constructs a `CombGenerator` using a random-number generator and a number converter + * + * @param RandomGeneratorInterface $generator Random-number generator for the non-time part. + * @param NumberConverterInterface $numberConverter Instance of number converter. + */ + public function __construct(RandomGeneratorInterface $generator, NumberConverterInterface $numberConverter) + { + $this->converter = $numberConverter; + $this->randomGenerator = $generator; + } + + /** + * Generates a string of binary data of the specified length + * + * @param integer $length The number of bytes of random binary data to generate + * @return string A binary string + * @throws \Ramsey\Uuid\Exception\UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present + * @throws \InvalidArgumentException if length is not a positive integer + * @throws \Exception + */ + public function generate($length) + { + if ($length < self::TIMESTAMP_BYTES || $length < 0) { + throw new \InvalidArgumentException('Length must be a positive integer.'); + } + + $hash = ''; + + if (self::TIMESTAMP_BYTES > 0 && $length > self::TIMESTAMP_BYTES) { + $hash = $this->randomGenerator->generate($length - self::TIMESTAMP_BYTES); + } + + $lsbTime = str_pad($this->converter->toHex($this->timestamp()), self::TIMESTAMP_BYTES * 2, '0', STR_PAD_LEFT); + + return hex2bin(str_pad(bin2hex($hash), $length - self::TIMESTAMP_BYTES, '0') . $lsbTime); + } + + /** + * Returns current timestamp as integer, precise to 0.00001 seconds + * + * @return string + */ + private function timestamp() + { + $time = explode(' ', microtime(false)); + + return $time[1] . substr($time[0], 2, 5); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/DefaultTimeGenerator.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/DefaultTimeGenerator.php new file mode 100644 index 00000000..c9969b3a --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/DefaultTimeGenerator.php @@ -0,0 +1,138 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Generator; + +use Ramsey\Uuid\BinaryUtils; +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Provider\NodeProviderInterface; +use Ramsey\Uuid\Provider\TimeProviderInterface; + +/** + * DefaultTimeGenerator provides functionality to generate strings of binary + * data for version 1 UUIDs based on a host ID, sequence number, and the current + * time + */ +class DefaultTimeGenerator implements TimeGeneratorInterface +{ + /** + * @var NodeProviderInterface + */ + private $nodeProvider; + + /** + * @var TimeConverterInterface + */ + private $timeConverter; + + /** + * @var TimeProviderInterface + */ + private $timeProvider; + + /** + * Constructs a `DefaultTimeGenerator` using a node provider, time converter, + * and time provider + * + * @param NodeProviderInterface $nodeProvider + * @param TimeConverterInterface $timeConverter + * @param TimeProviderInterface $timeProvider + */ + public function __construct( + NodeProviderInterface $nodeProvider, + TimeConverterInterface $timeConverter, + TimeProviderInterface $timeProvider + ) { + $this->nodeProvider = $nodeProvider; + $this->timeConverter = $timeConverter; + $this->timeProvider = $timeProvider; + } + + /** + * Generate a version 1 UUID from a host ID, sequence number, and the current time + * + * If $node is not given, we will attempt to obtain the local hardware + * address. If $clockSeq is given, it is used as the sequence number; + * otherwise a random 14-bit sequence number is chosen. + * + * @param int|string $node A 48-bit number representing the hardware address + * This number may be represented as an integer or a hexadecimal string. + * @param int $clockSeq A 14-bit number used to help avoid duplicates that + * could arise when the clock is set backwards in time or if the node ID + * changes. + * @return string A binary string + * @throws \Ramsey\Uuid\Exception\UnsatisfiedDependencyException if called on a 32-bit system and + * `Moontoast\Math\BigNumber` is not present + * @throws \InvalidArgumentException + * @throws \Exception if it was not possible to gather sufficient entropy + */ + public function generate($node = null, $clockSeq = null) + { + $node = $this->getValidNode($node); + + if ($clockSeq === null) { + // Not using "stable storage"; see RFC 4122, Section 4.2.1.1 + $clockSeq = random_int(0, 0x3fff); + } + + // Create a 60-bit time value as a count of 100-nanosecond intervals + // since 00:00:00.00, 15 October 1582 + $timeOfDay = $this->timeProvider->currentTime(); + $uuidTime = $this->timeConverter->calculateTime($timeOfDay['sec'], $timeOfDay['usec']); + + $timeHi = BinaryUtils::applyVersion($uuidTime['hi'], 1); + $clockSeqHi = BinaryUtils::applyVariant($clockSeq >> 8); + + $hex = vsprintf( + '%08s%04s%04s%02s%02s%012s', + array( + $uuidTime['low'], + $uuidTime['mid'], + sprintf('%04x', $timeHi), + sprintf('%02x', $clockSeqHi), + sprintf('%02x', $clockSeq & 0xff), + $node, + ) + ); + + return hex2bin($hex); + } + + /** + * Uses the node provider given when constructing this instance to get + * the node ID (usually a MAC address) + * + * @param string|int $node A node value that may be used to override the node provider + * @return string Hexadecimal representation of the node ID + * @throws \InvalidArgumentException + * @throws \Exception + */ + protected function getValidNode($node) + { + if ($node === null) { + $node = $this->nodeProvider->getNode(); + } + + // Convert the node to hex, if it is still an integer + if (is_int($node)) { + $node = sprintf('%012x', $node); + } + + if (!ctype_xdigit($node) || strlen($node) > 12) { + throw new \InvalidArgumentException('Invalid node value'); + } + + return strtolower(sprintf('%012s', $node)); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/MtRandGenerator.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/MtRandGenerator.php new file mode 100644 index 00000000..f58b7835 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/MtRandGenerator.php @@ -0,0 +1,41 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Generator; + +/** + * MtRandRandomGenerator provides functionality to generate strings of random + * binary data using the `mt_rand()` PHP function + * + * @link http://php.net/mt_rand + */ +class MtRandGenerator implements RandomGeneratorInterface +{ + /** + * Generates a string of random binary data of the specified length + * + * @param integer $length The number of bytes of random binary data to generate + * @return string A binary string + */ + public function generate($length) + { + $bytes = ''; + + for ($i = 1; $i <= $length; $i++) { + $bytes = chr(mt_rand(0, 255)) . $bytes; + } + + return $bytes; + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/OpenSslGenerator.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/OpenSslGenerator.php new file mode 100644 index 00000000..e8ec6a4d --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/OpenSslGenerator.php @@ -0,0 +1,38 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Generator; + +/** + * OpenSslRandomGenerator provides functionality to generate strings of random + * binary data using the `openssl_random_pseudo_bytes()` PHP function + * + * The use of this generator requires PHP to be compiled using the + * `--with-openssl` option. + * + * @link http://php.net/openssl_random_pseudo_bytes + */ +class OpenSslGenerator implements RandomGeneratorInterface +{ + /** + * Generates a string of random binary data of the specified length + * + * @param integer $length The number of bytes of random binary data to generate + * @return string A binary string + */ + public function generate($length) + { + return openssl_random_pseudo_bytes($length); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/PeclUuidRandomGenerator.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/PeclUuidRandomGenerator.php new file mode 100644 index 00000000..fc2ef7e4 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/PeclUuidRandomGenerator.php @@ -0,0 +1,37 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Generator; + +/** + * PeclUuidRandomGenerator provides functionality to generate strings of random + * binary data using the PECL UUID PHP extension + * + * @link https://pecl.php.net/package/uuid + */ +class PeclUuidRandomGenerator implements RandomGeneratorInterface +{ + /** + * Generates a string of random binary data of the specified length + * + * @param integer $length The number of bytes of random binary data to generate + * @return string A binary string + */ + public function generate($length) + { + $uuid = uuid_create(UUID_TYPE_RANDOM); + + return uuid_parse($uuid); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/PeclUuidTimeGenerator.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/PeclUuidTimeGenerator.php new file mode 100644 index 00000000..7ccf16fd --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/PeclUuidTimeGenerator.php @@ -0,0 +1,38 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Generator; + +/** + * PeclUuidTimeGenerator provides functionality to generate strings of binary + * data for version 1 UUIDs using the PECL UUID PHP extension + * + * @link https://pecl.php.net/package/uuid + */ +class PeclUuidTimeGenerator implements TimeGeneratorInterface +{ + /** + * Generate a version 1 UUID using the PECL UUID extension + * + * @param int|string $node Not used in this context + * @param int $clockSeq Not used in this context + * @return string A binary string + */ + public function generate($node = null, $clockSeq = null) + { + $uuid = uuid_create(UUID_TYPE_TIME); + + return uuid_parse($uuid); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/RandomBytesGenerator.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/RandomBytesGenerator.php new file mode 100644 index 00000000..aaa285df --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/RandomBytesGenerator.php @@ -0,0 +1,37 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Generator; + +/** + * RandomBytesGenerator provides functionality to generate strings of random + * binary data using `random_bytes()` function in PHP 7+ or paragonie/random_compat + * + * @link http://php.net/random_bytes + * @link https://github.com/paragonie/random_compat + */ +class RandomBytesGenerator implements RandomGeneratorInterface +{ + /** + * Generates a string of random binary data of the specified length + * + * @param integer $length The number of bytes of random binary data to generate + * @return string A binary string + * @throws \Exception if it was not possible to gather sufficient entropy + */ + public function generate($length) + { + return random_bytes($length); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/RandomGeneratorFactory.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/RandomGeneratorFactory.php new file mode 100644 index 00000000..39110622 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/RandomGeneratorFactory.php @@ -0,0 +1,31 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Generator; + +/** + * A factory for retrieving a random generator, based on the environment + */ +class RandomGeneratorFactory +{ + /** + * Returns a default random generator, based on the current environment + * + * @return RandomGeneratorInterface + */ + public static function getGenerator() + { + return new RandomBytesGenerator(); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/RandomGeneratorInterface.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/RandomGeneratorInterface.php new file mode 100644 index 00000000..3a1bcae7 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/RandomGeneratorInterface.php @@ -0,0 +1,33 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Generator; + +/** + * RandomGeneratorInterface provides functionality to generate strings of random + * binary data + */ +interface RandomGeneratorInterface +{ + /** + * Generates a string of random binary data of the specified length + * + * @param integer $length The number of bytes of random binary data to generate + * @return string A binary string + * @throws \Ramsey\Uuid\Exception\UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present + * @throws \InvalidArgumentException + * @throws \Exception if it was not possible to gather sufficient entropy + */ + public function generate($length); +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/RandomLibAdapter.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/RandomLibAdapter.php new file mode 100644 index 00000000..25b54a83 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/RandomLibAdapter.php @@ -0,0 +1,62 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Generator; + +use RandomLib\Generator; +use RandomLib\Factory; + +/** + * RandomLibAdapter provides functionality to generate strings of random + * binary data using the ircmaxell/random-lib library + * + * @link https://packagist.org/packages/ircmaxell/random-lib + */ +class RandomLibAdapter implements RandomGeneratorInterface +{ + /** + * @var Generator + */ + private $generator; + + /** + * Constructs a `RandomLibAdapter` using a `RandomLib\Generator` + * + * By default, if no `Generator` is passed in, this creates a medium-strength + * generator to use when generating random binary data. + * + * @param Generator $generator An ircmaxell/random-lib `Generator` + */ + public function __construct(Generator $generator = null) + { + $this->generator = $generator; + + if ($this->generator === null) { + $factory = new Factory(); + + $this->generator = $factory->getMediumStrengthGenerator(); + } + } + + /** + * Generates a string of random binary data of the specified length + * + * @param integer $length The number of bytes of random binary data to generate + * @return string A binary string + */ + public function generate($length) + { + return $this->generator->generate($length); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/SodiumRandomGenerator.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/SodiumRandomGenerator.php new file mode 100644 index 00000000..6b08f540 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/SodiumRandomGenerator.php @@ -0,0 +1,36 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Generator; + +/** + * SodiumRandomGenerator provides functionality to generate strings of random + * binary data using the PECL libsodium extension + * + * @link http://pecl.php.net/package/libsodium + * @link https://paragonie.com/book/pecl-libsodium + */ +class SodiumRandomGenerator implements RandomGeneratorInterface +{ + /** + * Generates a string of random binary data of the specified length + * + * @param integer $length The number of bytes of random binary data to generate + * @return string A binary string + */ + public function generate($length) + { + return \Sodium\randombytes_buf($length); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/TimeGeneratorFactory.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/TimeGeneratorFactory.php new file mode 100644 index 00000000..24d501bb --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/TimeGeneratorFactory.php @@ -0,0 +1,72 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Generator; + +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Provider\NodeProviderInterface; +use Ramsey\Uuid\Provider\TimeProviderInterface; + +/** + * A factory for retrieving a time generator, based on the environment + */ +class TimeGeneratorFactory +{ + /** + * @var NodeProviderInterface + */ + private $nodeProvider; + + /** + * @var TimeConverterInterface + */ + private $timeConverter; + + /** + * @var TimeProviderInterface + */ + private $timeProvider; + + /** + * Constructs a `TimeGeneratorFactory` using a node provider, time converter, + * and time provider + * + * @param NodeProviderInterface $nodeProvider + * @param TimeConverterInterface $timeConverter + * @param TimeProviderInterface $timeProvider + */ + public function __construct( + NodeProviderInterface $nodeProvider, + TimeConverterInterface $timeConverter, + TimeProviderInterface $timeProvider + ) { + $this->nodeProvider = $nodeProvider; + $this->timeConverter = $timeConverter; + $this->timeProvider = $timeProvider; + } + + /** + * Returns a default time generator, based on the current environment + * + * @return TimeGeneratorInterface + */ + public function getGenerator() + { + return new DefaultTimeGenerator( + $this->nodeProvider, + $this->timeConverter, + $this->timeProvider + ); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/TimeGeneratorInterface.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/TimeGeneratorInterface.php new file mode 100644 index 00000000..cb182ea0 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Generator/TimeGeneratorInterface.php @@ -0,0 +1,39 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Generator; + +/** + * TimeGeneratorInterface provides functionality to generate strings of binary + * data for version 1 UUIDs based on a host ID, sequence number, and the current + * time + */ +interface TimeGeneratorInterface +{ + /** + * Generate a version 1 UUID from a host ID, sequence number, and the current time + * + * @param int|string $node A 48-bit number representing the hardware address + * This number may be represented as an integer or a hexadecimal string. + * @param int $clockSeq A 14-bit number used to help avoid duplicates that + * could arise when the clock is set backwards in time or if the node ID + * changes. + * @return string A binary string + * @throws \Ramsey\Uuid\Exception\UnsatisfiedDependencyException if called on a 32-bit system and + * `Moontoast\Math\BigNumber` is not present + * @throws \InvalidArgumentException + * @throws \Exception if it was not possible to gather sufficient entropy + */ + public function generate($node = null, $clockSeq = null); +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/Node/FallbackNodeProvider.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/Node/FallbackNodeProvider.php new file mode 100644 index 00000000..289fddea --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/Node/FallbackNodeProvider.php @@ -0,0 +1,58 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Provider\Node; + +use Ramsey\Uuid\Provider\NodeProviderInterface; + +/** + * FallbackNodeProvider attempts to gain the system host ID from an array of + * providers, falling back to the next in line in the event a host ID can not be + * obtained + */ +class FallbackNodeProvider implements NodeProviderInterface +{ + /** + * @var NodeProviderInterface[] + */ + private $nodeProviders; + + /** + * Constructs a `FallbackNodeProvider` using an array of node providers + * + * @param NodeProviderInterface[] $providers Array of node providers + */ + public function __construct(array $providers) + { + $this->nodeProviders = $providers; + } + + /** + * Returns the system node ID by iterating over an array of node providers + * and returning the first non-empty value found + * + * @return string System node ID as a hexadecimal string + * @throws \Exception + */ + public function getNode() + { + foreach ($this->nodeProviders as $provider) { + if ($node = $provider->getNode()) { + return $node; + } + } + + return null; + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/Node/RandomNodeProvider.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/Node/RandomNodeProvider.php new file mode 100644 index 00000000..76c570d7 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/Node/RandomNodeProvider.php @@ -0,0 +1,42 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Provider\Node; + +use Ramsey\Uuid\Provider\NodeProviderInterface; + +/** + * RandomNodeProvider provides functionality to generate a random node ID, in + * the event that the node ID could not be obtained from the host system + * + * @link http://tools.ietf.org/html/rfc4122#section-4.5 + */ +class RandomNodeProvider implements NodeProviderInterface +{ + /** + * Returns the system node ID + * + * @return string System node ID as a hexadecimal string + * @throws \Exception if it was not possible to gather sufficient entropy + */ + public function getNode() + { + $node = hexdec(bin2hex(random_bytes(6))); + + // Set the multicast bit; see RFC 4122, section 4.5. + $node = $node | 0x010000000000; + + return str_pad(dechex($node), 12, '0', STR_PAD_LEFT); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/Node/SystemNodeProvider.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/Node/SystemNodeProvider.php new file mode 100644 index 00000000..ae6a09ea --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/Node/SystemNodeProvider.php @@ -0,0 +1,125 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Provider\Node; + +use Ramsey\Uuid\Provider\NodeProviderInterface; + +/** + * SystemNodeProvider provides functionality to get the system node ID (MAC + * address) using external system calls + */ +class SystemNodeProvider implements NodeProviderInterface +{ + /** + * Returns the system node ID + * + * @return string|false System node ID as a hexadecimal string, or false if it is not found + */ + public function getNode() + { + static $node = null; + + if ($node !== null) { + return $node; + } + + $pattern = '/[^:]([0-9A-Fa-f]{2}([:-])[0-9A-Fa-f]{2}(\2[0-9A-Fa-f]{2}){4})[^:]/'; + $matches = array(); + + // first try a linux specific way + $node = $this->getSysfs(); + + // Search the ifconfig output for all MAC addresses and return + // the first one found + if ($node === false) { + if (preg_match_all($pattern, $this->getIfconfig(), $matches, PREG_PATTERN_ORDER)) { + $node = $matches[1][0]; + } + } + if ($node !== false) { + $node = str_replace([':', '-'], '', $node); + } + return $node; + } + + /** + * Returns the network interface configuration for the system + * + * @codeCoverageIgnore + * @return string + */ + protected function getIfconfig() + { + if (strpos(strtolower(ini_get('disable_functions')), 'passthru') !== false) { + return ''; + } + + ob_start(); + switch (strtoupper(substr(php_uname('a'), 0, 3))) { + case 'WIN': + passthru('ipconfig /all 2>&1'); + break; + case 'DAR': + passthru('ifconfig 2>&1'); + break; + case 'FRE': + passthru('netstat -i -f link 2>&1'); + break; + case 'LIN': + default: + passthru('netstat -ie 2>&1'); + break; + } + + return ob_get_clean(); + } + + /** + * Returns mac address from the first system interface via the sysfs interface + * + * @return string|bool + */ + protected function getSysfs() + { + $mac = false; + + if (strtoupper(php_uname('s')) === 'LINUX') { + $addressPaths = glob('/sys/class/net/*/address', GLOB_NOSORT); + + if (empty($addressPaths)) { + return false; + } + + array_walk($addressPaths, function ($addressPath) use (&$macs) { + $macs[] = file_get_contents($addressPath); + }); + + $macs = array_map('trim', $macs); + + // remove invalid entries + $macs = array_filter($macs, function ($mac) { + return + // localhost adapter + $mac !== '00:00:00:00:00:00' && + // must match mac adress + preg_match('/^([0-9a-f]{2}:){5}[0-9a-f]{2}$/i', $mac); + }); + + $mac = reset($macs); + } + + return $mac; + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/NodeProviderInterface.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/NodeProviderInterface.php new file mode 100644 index 00000000..14f747be --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/NodeProviderInterface.php @@ -0,0 +1,30 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Provider; + +/** + * NodeProviderInterface provides functionality to get the node ID (or host ID + * in the form of the system's MAC address) from a specific type of node provider + */ +interface NodeProviderInterface +{ + /** + * Returns the system node ID + * + * @return string System node ID as a hexadecimal string + * @throws \Exception if it was not possible to gather sufficient entropy + */ + public function getNode(); +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/Time/FixedTimeProvider.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/Time/FixedTimeProvider.php new file mode 100644 index 00000000..a62d39c6 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/Time/FixedTimeProvider.php @@ -0,0 +1,76 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Provider\Time; + +use Ramsey\Uuid\Provider\TimeProviderInterface; + +/** + * FixedTimeProvider uses an previously-generated timestamp to provide the time + * + * This provider allows the use of a previously-generated timestamp, such as one + * stored in a database, when creating version 1 UUIDs. + */ +class FixedTimeProvider implements TimeProviderInterface +{ + /** + * @var int[] Array containing `sec` and `usec` components of a timestamp + */ + private $fixedTime; + + /** + * Constructs a `FixedTimeProvider` using the provided `$timestamp` + * + * @param int[] Array containing `sec` and `usec` components of a timestamp + * @throws \InvalidArgumentException if the `$timestamp` does not contain `sec` or `usec` components + */ + public function __construct(array $timestamp) + { + if (!array_key_exists('sec', $timestamp) || !array_key_exists('usec', $timestamp)) { + throw new \InvalidArgumentException('Array must contain sec and usec keys.'); + } + + $this->fixedTime = $timestamp; + } + + /** + * Sets the `usec` component of the timestamp + * + * @param int $value The `usec` value to set + */ + public function setUsec($value) + { + $this->fixedTime['usec'] = $value; + } + + /** + * Sets the `sec` component of the timestamp + * + * @param int $value The `sec` value to set + */ + public function setSec($value) + { + $this->fixedTime['sec'] = $value; + } + + /** + * Returns a timestamp array + * + * @return int[] Array containing `sec` and `usec` components of a timestamp + */ + public function currentTime() + { + return $this->fixedTime; + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/Time/SystemTimeProvider.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/Time/SystemTimeProvider.php new file mode 100644 index 00000000..6442985f --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/Time/SystemTimeProvider.php @@ -0,0 +1,33 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Provider\Time; + +use Ramsey\Uuid\Provider\TimeProviderInterface; + +/** + * SystemTimeProvider uses built-in PHP functions to provide the time + */ +class SystemTimeProvider implements TimeProviderInterface +{ + /** + * Returns a timestamp array + * + * @return int[] Array containing `sec` and `usec` components of a timestamp + */ + public function currentTime() + { + return gettimeofday(); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/TimeProviderInterface.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/TimeProviderInterface.php new file mode 100644 index 00000000..ef8099dd --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Provider/TimeProviderInterface.php @@ -0,0 +1,29 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Provider; + +/** + * TimeProviderInterface provides functionality to get the time from a specific + * type of time provider + */ +interface TimeProviderInterface +{ + /** + * Returns a timestamp array + * + * @return int[] Array guaranteed to contain `sec` and `usec` components of a timestamp + */ + public function currentTime(); +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/Uuid.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/Uuid.php new file mode 100644 index 00000000..45f9fa44 --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/Uuid.php @@ -0,0 +1,740 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid; + +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Exception\UnsupportedOperationException; + +/** + * Represents a universally unique identifier (UUID), according to RFC 4122. + * + * This class provides immutable UUID objects (the Uuid class) and the static + * methods `uuid1()`, `uuid3()`, `uuid4()`, and `uuid5()` for generating version + * 1, 3, 4, and 5 UUIDs as specified in RFC 4122. + * + * If all you want is a unique ID, you should probably call `uuid1()` or `uuid4()`. + * Note that `uuid1()` may compromise privacy since it creates a UUID containing + * the computer’s network address. `uuid4()` creates a random UUID. + * + * @link http://tools.ietf.org/html/rfc4122 + * @link http://en.wikipedia.org/wiki/Universally_unique_identifier + * @link http://docs.python.org/3/library/uuid.html + * @link http://docs.oracle.com/javase/6/docs/api/java/util/UUID.html + */ +class Uuid implements UuidInterface +{ + /** + * When this namespace is specified, the name string is a fully-qualified domain name. + * @link http://tools.ietf.org/html/rfc4122#appendix-C + */ + const NAMESPACE_DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'; + + /** + * When this namespace is specified, the name string is a URL. + * @link http://tools.ietf.org/html/rfc4122#appendix-C + */ + const NAMESPACE_URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; + + /** + * When this namespace is specified, the name string is an ISO OID. + * @link http://tools.ietf.org/html/rfc4122#appendix-C + */ + const NAMESPACE_OID = '6ba7b812-9dad-11d1-80b4-00c04fd430c8'; + + /** + * When this namespace is specified, the name string is an X.500 DN in DER or a text output format. + * @link http://tools.ietf.org/html/rfc4122#appendix-C + */ + const NAMESPACE_X500 = '6ba7b814-9dad-11d1-80b4-00c04fd430c8'; + + /** + * The nil UUID is special form of UUID that is specified to have all 128 bits set to zero. + * @link http://tools.ietf.org/html/rfc4122#section-4.1.7 + */ + const NIL = '00000000-0000-0000-0000-000000000000'; + + /** + * Reserved for NCS compatibility. + * @link http://tools.ietf.org/html/rfc4122#section-4.1.1 + */ + const RESERVED_NCS = 0; + + /** + * Specifies the UUID layout given in RFC 4122. + * @link http://tools.ietf.org/html/rfc4122#section-4.1.1 + */ + const RFC_4122 = 2; + + /** + * Reserved for Microsoft compatibility. + * @link http://tools.ietf.org/html/rfc4122#section-4.1.1 + */ + const RESERVED_MICROSOFT = 6; + + /** + * Reserved for future definition. + * @link http://tools.ietf.org/html/rfc4122#section-4.1.1 + */ + const RESERVED_FUTURE = 7; + + /** + * Regular expression pattern for matching a valid UUID of any variant. + */ + const VALID_PATTERN = '^[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}$'; + + /** + * Version 1 (time-based) UUID object constant identifier + */ + const UUID_TYPE_TIME = 1; + + /** + * Version 2 (identifier-based) UUID object constant identifier + */ + const UUID_TYPE_IDENTIFIER = 2; + + /** + * Version 3 (name-based and hashed with MD5) UUID object constant identifier + */ + const UUID_TYPE_HASH_MD5 = 3; + + /** + * Version 4 (random) UUID object constant identifier + */ + const UUID_TYPE_RANDOM = 4; + + /** + * Version 5 (name-based and hashed with SHA1) UUID object constant identifier + */ + const UUID_TYPE_HASH_SHA1 = 5; + + /** + * The factory to use when creating UUIDs. + * @var UuidFactoryInterface + */ + private static $factory = null; + + /** + * The codec to use when encoding or decoding UUID strings. + * @var CodecInterface + */ + protected $codec; + + /** + * The fields that make up this UUID. + * + * This is initialized to the nil value. + * + * @var array + * @see UuidInterface::getFieldsHex() + */ + protected $fields = array( + 'time_low' => '00000000', + 'time_mid' => '0000', + 'time_hi_and_version' => '0000', + 'clock_seq_hi_and_reserved' => '00', + 'clock_seq_low' => '00', + 'node' => '000000000000', + ); + + /** + * The number converter to use for converting hex values to/from integers. + * @var NumberConverterInterface + */ + protected $converter; + + /** + * Creates a universally unique identifier (UUID) from an array of fields. + * + * Unless you're making advanced use of this library to generate identifiers + * that deviate from RFC 4122, you probably do not want to instantiate a + * UUID directly. Use the static methods, instead: + * + * ``` + * use Ramsey\Uuid\Uuid; + * + * $timeBasedUuid = Uuid::uuid1(); + * $namespaceMd5Uuid = Uuid::uuid3(Uuid::NAMESPACE_URL, 'http://php.net/'); + * $randomUuid = Uuid::uuid4(); + * $namespaceSha1Uuid = Uuid::uuid5(Uuid::NAMESPACE_URL, 'http://php.net/'); + * ``` + * + * @param array $fields An array of fields from which to construct a UUID; + * see {@see \Ramsey\Uuid\UuidInterface::getFieldsHex()} for array structure. + * @param NumberConverterInterface $converter The number converter to use + * for converting hex values to/from integers. + * @param CodecInterface $codec The codec to use when encoding or decoding + * UUID strings. + */ + public function __construct( + array $fields, + NumberConverterInterface $converter, + CodecInterface $codec + ) { + $this->fields = $fields; + $this->codec = $codec; + $this->converter = $converter; + } + + /** + * Converts this UUID object to a string when the object is used in any + * string context. + * + * @return string + * @link http://www.php.net/manual/en/language.oop5.magic.php#object.tostring + */ + public function __toString() + { + return $this->toString(); + } + + /** + * Converts this UUID object to a string when the object is serialized + * with `json_encode()` + * + * @return string + * @link http://php.net/manual/en/class.jsonserializable.php + */ + public function jsonSerialize() + { + return $this->toString(); + } + + /** + * Converts this UUID object to a string when the object is serialized + * with `serialize()` + * + * @return string + * @link http://php.net/manual/en/class.serializable.php + */ + public function serialize() + { + return $this->toString(); + } + + /** + * Re-constructs the object from its serialized form. + * + * @param string $serialized + * @link http://php.net/manual/en/class.serializable.php + * @throws \Ramsey\Uuid\Exception\InvalidUuidStringException + */ + public function unserialize($serialized) + { + $uuid = self::fromString($serialized); + $this->codec = $uuid->codec; + $this->converter = $uuid->converter; + $this->fields = $uuid->fields; + } + + public function compareTo(UuidInterface $other) + { + $comparison = 0; + + if ($this->getMostSignificantBitsHex() < $other->getMostSignificantBitsHex()) { + $comparison = -1; + } elseif ($this->getMostSignificantBitsHex() > $other->getMostSignificantBitsHex()) { + $comparison = 1; + } elseif ($this->getLeastSignificantBitsHex() < $other->getLeastSignificantBitsHex()) { + $comparison = -1; + } elseif ($this->getLeastSignificantBitsHex() > $other->getLeastSignificantBitsHex()) { + $comparison = 1; + } + + return $comparison; + } + + public function equals($other) + { + if (!($other instanceof UuidInterface)) { + return false; + } + + return ($this->compareTo($other) == 0); + } + + public function getBytes() + { + return $this->codec->encodeBinary($this); + } + + /** + * Returns the high field of the clock sequence multiplexed with the variant + * (bits 65-72 of the UUID). + * + * @return int Unsigned 8-bit integer value of clock_seq_hi_and_reserved + */ + public function getClockSeqHiAndReserved() + { + return hexdec($this->getClockSeqHiAndReservedHex()); + } + + public function getClockSeqHiAndReservedHex() + { + return $this->fields['clock_seq_hi_and_reserved']; + } + + /** + * Returns the low field of the clock sequence (bits 73-80 of the UUID). + * + * @return int Unsigned 8-bit integer value of clock_seq_low + */ + public function getClockSeqLow() + { + return hexdec($this->getClockSeqLowHex()); + } + + public function getClockSeqLowHex() + { + return $this->fields['clock_seq_low']; + } + + /** + * Returns the clock sequence value associated with this UUID. + * + * For UUID version 1, the clock sequence is used to help avoid + * duplicates that could arise when the clock is set backwards in time + * or if the node ID changes. + * + * For UUID version 3 or 5, the clock sequence is a 14-bit value + * constructed from a name as described in RFC 4122, Section 4.3. + * + * For UUID version 4, clock sequence is a randomly or pseudo-randomly + * generated 14-bit value as described in RFC 4122, Section 4.4. + * + * @return int Unsigned 14-bit integer value of clock sequence + * @link http://tools.ietf.org/html/rfc4122#section-4.1.5 + */ + public function getClockSequence() + { + return (($this->getClockSeqHiAndReserved() & 0x3f) << 8) + | $this->getClockSeqLow(); + } + + public function getClockSequenceHex() + { + return sprintf('%04x', $this->getClockSequence()); + } + + public function getNumberConverter() + { + return $this->converter; + } + + /** + * @inheritdoc + */ + public function getDateTime() + { + if ($this->getVersion() != 1) { + throw new UnsupportedOperationException('Not a time-based UUID'); + } + + $unixTime = ($this->getTimestamp() - 0x01b21dd213814000) / 1e7; + $unixTime = number_format($unixTime, 0, '', ''); + + return new \DateTime("@{$unixTime}"); + } + + /** + * Returns an array of the fields of this UUID, with keys named according + * to the RFC 4122 names for the fields. + * + * * **time_low**: The low field of the timestamp, an unsigned 32-bit integer + * * **time_mid**: The middle field of the timestamp, an unsigned 16-bit integer + * * **time_hi_and_version**: The high field of the timestamp multiplexed with + * the version number, an unsigned 16-bit integer + * * **clock_seq_hi_and_reserved**: The high field of the clock sequence + * multiplexed with the variant, an unsigned 8-bit integer + * * **clock_seq_low**: The low field of the clock sequence, an unsigned + * 8-bit integer + * * **node**: The spatially unique node identifier, an unsigned 48-bit + * integer + * + * @return array The UUID fields represented as integer values + * @link http://tools.ietf.org/html/rfc4122#section-4.1.2 + */ + public function getFields() + { + return array( + 'time_low' => $this->getTimeLow(), + 'time_mid' => $this->getTimeMid(), + 'time_hi_and_version' => $this->getTimeHiAndVersion(), + 'clock_seq_hi_and_reserved' => $this->getClockSeqHiAndReserved(), + 'clock_seq_low' => $this->getClockSeqLow(), + 'node' => $this->getNode(), + ); + } + + public function getFieldsHex() + { + return $this->fields; + } + + public function getHex() + { + return str_replace('-', '', $this->toString()); + } + + /** + * @inheritdoc + */ + public function getInteger() + { + return $this->converter->fromHex($this->getHex()); + } + + /** + * Returns the least significant 64 bits of this UUID's 128 bit value. + * + * @return mixed Converted representation of the unsigned 64-bit integer value + * @throws \Ramsey\Uuid\Exception\UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present + */ + public function getLeastSignificantBits() + { + return $this->converter->fromHex($this->getLeastSignificantBitsHex()); + } + + public function getLeastSignificantBitsHex() + { + return sprintf( + '%02s%02s%012s', + $this->fields['clock_seq_hi_and_reserved'], + $this->fields['clock_seq_low'], + $this->fields['node'] + ); + } + + /** + * Returns the most significant 64 bits of this UUID's 128 bit value. + * + * @return mixed Converted representation of the unsigned 64-bit integer value + * @throws \Ramsey\Uuid\Exception\UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present + */ + public function getMostSignificantBits() + { + return $this->converter->fromHex($this->getMostSignificantBitsHex()); + } + + public function getMostSignificantBitsHex() + { + return sprintf( + '%08s%04s%04s', + $this->fields['time_low'], + $this->fields['time_mid'], + $this->fields['time_hi_and_version'] + ); + } + + /** + * Returns the node value associated with this UUID + * + * For UUID version 1, the node field consists of an IEEE 802 MAC + * address, usually the host address. For systems with multiple IEEE + * 802 addresses, any available one can be used. The lowest addressed + * octet (octet number 10) contains the global/local bit and the + * unicast/multicast bit, and is the first octet of the address + * transmitted on an 802.3 LAN. + * + * For systems with no IEEE address, a randomly or pseudo-randomly + * generated value may be used; see RFC 4122, Section 4.5. The + * multicast bit must be set in such addresses, in order that they + * will never conflict with addresses obtained from network cards. + * + * For UUID version 3 or 5, the node field is a 48-bit value constructed + * from a name as described in RFC 4122, Section 4.3. + * + * For UUID version 4, the node field is a randomly or pseudo-randomly + * generated 48-bit value as described in RFC 4122, Section 4.4. + * + * @return int Unsigned 48-bit integer value of node + * @link http://tools.ietf.org/html/rfc4122#section-4.1.6 + */ + public function getNode() + { + return hexdec($this->getNodeHex()); + } + + public function getNodeHex() + { + return $this->fields['node']; + } + + /** + * Returns the high field of the timestamp multiplexed with the version + * number (bits 49-64 of the UUID). + * + * @return int Unsigned 16-bit integer value of time_hi_and_version + */ + public function getTimeHiAndVersion() + { + return hexdec($this->getTimeHiAndVersionHex()); + } + + public function getTimeHiAndVersionHex() + { + return $this->fields['time_hi_and_version']; + } + + /** + * Returns the low field of the timestamp (the first 32 bits of the UUID). + * + * @return int Unsigned 32-bit integer value of time_low + */ + public function getTimeLow() + { + return hexdec($this->getTimeLowHex()); + } + + public function getTimeLowHex() + { + return $this->fields['time_low']; + } + + /** + * Returns the middle field of the timestamp (bits 33-48 of the UUID). + * + * @return int Unsigned 16-bit integer value of time_mid + */ + public function getTimeMid() + { + return hexdec($this->getTimeMidHex()); + } + + public function getTimeMidHex() + { + return $this->fields['time_mid']; + } + + /** + * Returns the timestamp value associated with this UUID. + * + * The 60 bit timestamp value is constructed from the time_low, + * time_mid, and time_hi fields of this UUID. The resulting + * timestamp is measured in 100-nanosecond units since midnight, + * October 15, 1582 UTC. + * + * The timestamp value is only meaningful in a time-based UUID, which + * has version type 1. If this UUID is not a time-based UUID then + * this method throws UnsupportedOperationException. + * + * @return int Unsigned 60-bit integer value of the timestamp + * @throws UnsupportedOperationException If this UUID is not a version 1 UUID + * @link http://tools.ietf.org/html/rfc4122#section-4.1.4 + */ + public function getTimestamp() + { + if ($this->getVersion() != 1) { + throw new UnsupportedOperationException('Not a time-based UUID'); + } + + return hexdec($this->getTimestampHex()); + } + + /** + * @inheritdoc + */ + public function getTimestampHex() + { + if ($this->getVersion() != 1) { + throw new UnsupportedOperationException('Not a time-based UUID'); + } + + return sprintf( + '%03x%04s%08s', + ($this->getTimeHiAndVersion() & 0x0fff), + $this->fields['time_mid'], + $this->fields['time_low'] + ); + } + + public function getUrn() + { + return 'urn:uuid:' . $this->toString(); + } + + public function getVariant() + { + $clockSeq = $this->getClockSeqHiAndReserved(); + if (0 === ($clockSeq & 0x80)) { + $variant = self::RESERVED_NCS; + } elseif (0 === ($clockSeq & 0x40)) { + $variant = self::RFC_4122; + } elseif (0 === ($clockSeq & 0x20)) { + $variant = self::RESERVED_MICROSOFT; + } else { + $variant = self::RESERVED_FUTURE; + } + + return $variant; + } + + public function getVersion() + { + if ($this->getVariant() == self::RFC_4122) { + return (int) (($this->getTimeHiAndVersion() >> 12) & 0x0f); + } + + return null; + } + + public function toString() + { + return $this->codec->encode($this); + } + + /** + * Returns the currently set factory used to create UUIDs. + * + * @return UuidFactoryInterface + */ + public static function getFactory() + { + if (!self::$factory) { + self::$factory = new UuidFactory(); + } + + return self::$factory; + } + + /** + * Sets the factory used to create UUIDs. + * + * @param UuidFactoryInterface $factory + */ + public static function setFactory(UuidFactoryInterface $factory) + { + self::$factory = $factory; + } + + /** + * Creates a UUID from a byte string. + * + * @param string $bytes + * @return UuidInterface + * @throws \Ramsey\Uuid\Exception\InvalidUuidStringException + * @throws \InvalidArgumentException + */ + public static function fromBytes($bytes) + { + return self::getFactory()->fromBytes($bytes); + } + + /** + * Creates a UUID from the string standard representation. + * + * @param string $name A string that specifies a UUID + * @return UuidInterface + * @throws \Ramsey\Uuid\Exception\InvalidUuidStringException + */ + public static function fromString($name) + { + return self::getFactory()->fromString($name); + } + + /** + * Creates a UUID from a 128-bit integer string. + * + * @param string $integer String representation of 128-bit integer + * @return UuidInterface + * @throws \Ramsey\Uuid\Exception\UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present + * @throws \Ramsey\Uuid\Exception\InvalidUuidStringException + */ + public static function fromInteger($integer) + { + return self::getFactory()->fromInteger($integer); + } + + /** + * Check if a string is a valid UUID. + * + * @param string $uuid The string UUID to test + * @return boolean + */ + public static function isValid($uuid) + { + $uuid = str_replace(array('urn:', 'uuid:', '{', '}'), '', $uuid); + + if ($uuid == self::NIL) { + return true; + } + + if (!preg_match('/' . self::VALID_PATTERN . '/D', $uuid)) { + return false; + } + + return true; + } + + /** + * Generate a version 1 UUID from a host ID, sequence number, and the current time. + * + * @param int|string $node A 48-bit number representing the hardware address + * This number may be represented as an integer or a hexadecimal string. + * @param int $clockSeq A 14-bit number used to help avoid duplicates that + * could arise when the clock is set backwards in time or if the node ID + * changes. + * @return UuidInterface + * @throws \Ramsey\Uuid\Exception\UnsatisfiedDependencyException if called on a 32-bit system and + * `Moontoast\Math\BigNumber` is not present + * @throws \InvalidArgumentException + * @throws \Exception if it was not possible to gather sufficient entropy + */ + public static function uuid1($node = null, $clockSeq = null) + { + return self::getFactory()->uuid1($node, $clockSeq); + } + + /** + * Generate a version 3 UUID based on the MD5 hash of a namespace identifier + * (which is a UUID) and a name (which is a string). + * + * @param string $ns The UUID namespace in which to create the named UUID + * @param string $name The name to create a UUID for + * @return UuidInterface + * @throws \Ramsey\Uuid\Exception\InvalidUuidStringException + */ + public static function uuid3($ns, $name) + { + return self::getFactory()->uuid3($ns, $name); + } + + /** + * Generate a version 4 (random) UUID. + * + * @return UuidInterface + * @throws \Ramsey\Uuid\Exception\UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present + * @throws \InvalidArgumentException + * @throws \Exception + */ + public static function uuid4() + { + return self::getFactory()->uuid4(); + } + + /** + * Generate a version 5 UUID based on the SHA-1 hash of a namespace + * identifier (which is a UUID) and a name (which is a string). + * + * @param string $ns The UUID namespace in which to create the named UUID + * @param string $name The name to create a UUID for + * @return UuidInterface + * @throws \Ramsey\Uuid\Exception\InvalidUuidStringException + */ + public static function uuid5($ns, $name) + { + return self::getFactory()->uuid5($ns, $name); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/UuidFactory.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/UuidFactory.php new file mode 100644 index 00000000..99644d4b --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/UuidFactory.php @@ -0,0 +1,314 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid; + +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Provider\NodeProviderInterface; +use Ramsey\Uuid\Generator\RandomGeneratorInterface; +use Ramsey\Uuid\Generator\TimeGeneratorInterface; +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Builder\UuidBuilderInterface; + +class UuidFactory implements UuidFactoryInterface +{ + /** + * @var CodecInterface + */ + private $codec = null; + + /** + * @var NodeProviderInterface + */ + private $nodeProvider = null; + + /** + * @var NumberConverterInterface + */ + private $numberConverter = null; + + /** + * @var RandomGeneratorInterface + */ + private $randomGenerator = null; + + /** + * @var TimeGeneratorInterface + */ + private $timeGenerator = null; + + /** + * @var UuidBuilderInterface + */ + private $uuidBuilder = null; + + /** + * Constructs a `UuidFactory` for creating `Ramsey\Uuid\UuidInterface` instances + * + * @param FeatureSet $features A set of features for use when creating UUIDs + */ + public function __construct(FeatureSet $features = null) + { + $features = $features ?: new FeatureSet(); + + $this->codec = $features->getCodec(); + $this->nodeProvider = $features->getNodeProvider(); + $this->numberConverter = $features->getNumberConverter(); + $this->randomGenerator = $features->getRandomGenerator(); + $this->timeGenerator = $features->getTimeGenerator(); + $this->uuidBuilder = $features->getBuilder(); + } + + /** + * Returns the UUID coder-decoder used by this factory + * + * @return CodecInterface + */ + public function getCodec() + { + return $this->codec; + } + + /** + * Sets the UUID coder-decoder used by this factory + * + * @param CodecInterface $codec + */ + public function setCodec(CodecInterface $codec) + { + $this->codec = $codec; + } + + /** + * Returns the system node ID provider used by this factory + * + * @return NodeProviderInterface + */ + public function getNodeProvider() + { + return $this->nodeProvider; + } + + /** + * Returns the random UUID generator used by this factory + * + * @return RandomGeneratorInterface + */ + public function getRandomGenerator() + { + return $this->randomGenerator; + } + + /** + * Returns the time-based UUID generator used by this factory + * + * @return TimeGeneratorInterface + */ + public function getTimeGenerator() + { + return $this->timeGenerator; + } + + /** + * Sets the time-based UUID generator this factory will use to generate version 1 UUIDs + * + * @param TimeGeneratorInterface $generator + */ + public function setTimeGenerator(TimeGeneratorInterface $generator) + { + $this->timeGenerator = $generator; + } + + /** + * Returns the number converter used by this factory + * + * @return NumberConverterInterface + */ + public function getNumberConverter() + { + return $this->numberConverter; + } + + /** + * Sets the random UUID generator this factory will use to generate version 4 UUIDs + * + * @param RandomGeneratorInterface $generator + */ + public function setRandomGenerator(RandomGeneratorInterface $generator) + { + $this->randomGenerator = $generator; + } + + /** + * Sets the number converter this factory will use + * + * @param NumberConverterInterface $converter + */ + public function setNumberConverter(NumberConverterInterface $converter) + { + $this->numberConverter = $converter; + } + + /** + * Returns the UUID builder this factory uses when creating `Uuid` instances + * + * @return UuidBuilderInterface $builder + */ + public function getUuidBuilder() + { + return $this->uuidBuilder; + } + + /** + * Sets the UUID builder this factory will use when creating `Uuid` instances + * + * @param UuidBuilderInterface $builder + */ + public function setUuidBuilder(UuidBuilderInterface $builder) + { + $this->uuidBuilder = $builder; + } + + /** + * @inheritdoc + */ + public function fromBytes($bytes) + { + return $this->codec->decodeBytes($bytes); + } + + /** + * @inheritdoc + */ + public function fromString($uuid) + { + $uuid = strtolower($uuid); + return $this->codec->decode($uuid); + } + + /** + * @inheritdoc + */ + public function fromInteger($integer) + { + $hex = $this->numberConverter->toHex($integer); + $hex = str_pad($hex, 32, '0', STR_PAD_LEFT); + + return $this->fromString($hex); + } + + /** + * @inheritdoc + */ + public function uuid1($node = null, $clockSeq = null) + { + $bytes = $this->timeGenerator->generate($node, $clockSeq); + $hex = bin2hex($bytes); + + return $this->uuidFromHashedName($hex, 1); + } + + /** + * @inheritdoc + */ + public function uuid3($ns, $name) + { + return $this->uuidFromNsAndName($ns, $name, 3, 'md5'); + } + + /** + * @inheritdoc + */ + public function uuid4() + { + $bytes = $this->randomGenerator->generate(16); + + // When converting the bytes to hex, it turns into a 32-character + // hexadecimal string that looks a lot like an MD5 hash, so at this + // point, we can just pass it to uuidFromHashedName. + $hex = bin2hex($bytes); + + return $this->uuidFromHashedName($hex, 4); + } + + /** + * @inheritdoc + */ + public function uuid5($ns, $name) + { + return $this->uuidFromNsAndName($ns, $name, 5, 'sha1'); + } + + /** + * Returns a `Uuid` + * + * Uses the configured builder and codec and the provided array of hexadecimal + * value UUID fields to construct a `Uuid` object. + * + * @param array $fields An array of fields from which to construct a UUID; + * see {@see \Ramsey\Uuid\UuidInterface::getFieldsHex()} for array structure. + * @return UuidInterface + */ + public function uuid(array $fields) + { + return $this->uuidBuilder->build($this->codec, $fields); + } + + /** + * Returns a version 3 or 5 namespaced `Uuid` + * + * @param string|UuidInterface $ns The UUID namespace to use + * @param string $name The string to hash together with the namespace + * @param int $version The version of UUID to create (3 or 5) + * @param string $hashFunction The hash function to use when hashing together + * the namespace and name + * @return UuidInterface + * @throws \Ramsey\Uuid\Exception\InvalidUuidStringException + */ + protected function uuidFromNsAndName($ns, $name, $version, $hashFunction) + { + if (!($ns instanceof UuidInterface)) { + $ns = $this->codec->decode($ns); + } + + $hash = call_user_func($hashFunction, ($ns->getBytes() . $name)); + + return $this->uuidFromHashedName($hash, $version); + } + + /** + * Returns a `Uuid` created from `$hash` with the version field set to `$version` + * and the variant field set for RFC 4122 + * + * @param string $hash The hash to use when creating the UUID + * @param int $version The UUID version to set for this hash (1, 3, 4, or 5) + * @return UuidInterface + */ + protected function uuidFromHashedName($hash, $version) + { + $timeHi = BinaryUtils::applyVersion(substr($hash, 12, 4), $version); + $clockSeqHi = BinaryUtils::applyVariant(hexdec(substr($hash, 16, 2))); + + $fields = array( + 'time_low' => substr($hash, 0, 8), + 'time_mid' => substr($hash, 8, 4), + 'time_hi_and_version' => str_pad(dechex($timeHi), 4, '0', STR_PAD_LEFT), + 'clock_seq_hi_and_reserved' => str_pad(dechex($clockSeqHi), 2, '0', STR_PAD_LEFT), + 'clock_seq_low' => substr($hash, 18, 2), + 'node' => substr($hash, 20, 12), + ); + + return $this->uuid($fields); + } +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/UuidFactoryInterface.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/UuidFactoryInterface.php new file mode 100644 index 00000000..a228f5bc --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/UuidFactoryInterface.php @@ -0,0 +1,103 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid; + +/** + * UuidFactoryInterface defines common functionality all `UuidFactory` instances + * must implement + */ +interface UuidFactoryInterface +{ + /** + * Generate a version 1 UUID from a host ID, sequence number, and the current time. + * + * @param int|string|null $node A 48-bit number representing the hardware address + * This number may be represented as an integer or a hexadecimal string. + * @param int|null $clockSeq A 14-bit number used to help avoid duplicates that + * could arise when the clock is set backwards in time or if the node ID + * changes. + * @return UuidInterface + * @throws \Ramsey\Uuid\Exception\UnsatisfiedDependencyException if called on a 32-bit system and + * `Moontoast\Math\BigNumber` is not present + * @throws \InvalidArgumentException + * @throws \Exception if it was not possible to gather sufficient entropy + */ + public function uuid1($node = null, $clockSeq = null); + + /** + * Generate a version 3 UUID based on the MD5 hash of a namespace identifier + * (which is a UUID) and a name (which is a string). + * + * @param string $ns The UUID namespace in which to create the named UUID + * @param string $name The name to create a UUID for + * @return UuidInterface + * @throws \Ramsey\Uuid\Exception\InvalidUuidStringException + */ + public function uuid3($ns, $name); + + /** + * Generate a version 4 (random) UUID. + * + * @return UuidInterface + * @throws \Ramsey\Uuid\Exception\UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present + * @throws \InvalidArgumentException + * @throws \Exception + */ + public function uuid4(); + + /** + * Generate a version 5 UUID based on the SHA-1 hash of a namespace + * identifier (which is a UUID) and a name (which is a string). + * + * @param string $ns The UUID namespace in which to create the named UUID + * @param string $name The name to create a UUID for + * @return UuidInterface + * @throws \Ramsey\Uuid\Exception\InvalidUuidStringException + */ + public function uuid5($ns, $name); + + /** + * Creates a UUID from a byte string. + * + * @param string $bytes A 16-byte string representation of a UUID + * @return UuidInterface + * @throws \Ramsey\Uuid\Exception\InvalidUuidStringException + * @throws \InvalidArgumentException if string has not 16 characters + */ + public function fromBytes($bytes); + + /** + * Creates a UUID from the string standard representation + * + * @param string $uuid A string representation of a UUID + * @return UuidInterface + * @throws \Ramsey\Uuid\Exception\InvalidUuidStringException + */ + public function fromString($uuid); + + /** + * Creates a `Uuid` from an integer representation + * + * The integer representation may be a real integer, a string integer, or + * an integer representation supported by a configured number converter. + * + * @param mixed $integer The integer to use when creating a `Uuid` from an + * integer; may be of any type understood by the configured number converter + * @return UuidInterface + * @throws \Ramsey\Uuid\Exception\UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present + * @throws \Ramsey\Uuid\Exception\InvalidUuidStringException + */ + public function fromInteger($integer); +} diff --git a/lam/lib/3rdParty/composer/ramsey/uuid/src/UuidInterface.php b/lam/lib/3rdParty/composer/ramsey/uuid/src/UuidInterface.php new file mode 100644 index 00000000..ea3a46fb --- /dev/null +++ b/lam/lib/3rdParty/composer/ramsey/uuid/src/UuidInterface.php @@ -0,0 +1,270 @@ + + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid; + +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Exception\UnsupportedOperationException; + +/** + * UuidInterface defines common functionality for all universally unique + * identifiers (UUIDs) + */ +interface UuidInterface extends \JsonSerializable, \Serializable +{ + /** + * Compares this UUID to the specified UUID. + * + * The first of two UUIDs is greater than the second if the most + * significant field in which the UUIDs differ is greater for the first + * UUID. + * + * * Q. What's the value of being able to sort UUIDs? + * * A. Use them as keys in a B-Tree or similar mapping. + * + * @param UuidInterface $other UUID to which this UUID is compared + * @return int -1, 0 or 1 as this UUID is less than, equal to, or greater than `$uuid` + */ + public function compareTo(UuidInterface $other); + + /** + * Compares this object to the specified object. + * + * The result is true if and only if the argument is not null, is a UUID + * object, has the same variant, and contains the same value, bit for bit, + * as this UUID. + * + * @param object $other + * @return bool True if `$other` is equal to this UUID + */ + public function equals($other); + + /** + * Returns the UUID as a 16-byte string (containing the six integer fields + * in big-endian byte order). + * + * @return string + */ + public function getBytes(); + + /** + * Returns the number converter to use for converting hex values to/from integers. + * + * @return NumberConverterInterface + */ + public function getNumberConverter(); + + /** + * Returns the hexadecimal value of the UUID. + * + * @return string + */ + public function getHex(); + + /** + * Returns an array of the fields of this UUID, with keys named according + * to the RFC 4122 names for the fields. + * + * * **time_low**: The low field of the timestamp, an unsigned 32-bit integer + * * **time_mid**: The middle field of the timestamp, an unsigned 16-bit integer + * * **time_hi_and_version**: The high field of the timestamp multiplexed with + * the version number, an unsigned 16-bit integer + * * **clock_seq_hi_and_reserved**: The high field of the clock sequence + * multiplexed with the variant, an unsigned 8-bit integer + * * **clock_seq_low**: The low field of the clock sequence, an unsigned + * 8-bit integer + * * **node**: The spatially unique node identifier, an unsigned 48-bit + * integer + * + * @return array The UUID fields represented as hexadecimal values + */ + public function getFieldsHex(); + + /** + * Returns the high field of the clock sequence multiplexed with the variant + * (bits 65-72 of the UUID). + * + * @return string Hexadecimal value of clock_seq_hi_and_reserved + */ + public function getClockSeqHiAndReservedHex(); + + /** + * Returns the low field of the clock sequence (bits 73-80 of the UUID). + * + * @return string Hexadecimal value of clock_seq_low + */ + public function getClockSeqLowHex(); + + /** + * Returns the clock sequence value associated with this UUID. + * + * @return string Hexadecimal value of clock sequence + */ + public function getClockSequenceHex(); + + /** + * Returns a PHP `DateTime` object representing the timestamp associated + * with this UUID. + * + * The timestamp value is only meaningful in a time-based UUID, which + * has version type 1. If this UUID is not a time-based UUID then + * this method throws `UnsupportedOperationException`. + * + * @return \DateTime A PHP DateTime representation of the date + * @throws UnsupportedOperationException If this UUID is not a version 1 UUID + * @throws \Ramsey\Uuid\Exception\UnsatisfiedDependencyException if called in a 32-bit system and + * `Moontoast\Math\BigNumber` is not present + */ + public function getDateTime(); + + /** + * Returns the integer value of the UUID, converted to an appropriate number + * representation. + * + * @return mixed Converted representation of the unsigned 128-bit integer value + * @throws \Ramsey\Uuid\Exception\UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present + */ + public function getInteger(); + + /** + * Returns the least significant 64 bits of this UUID's 128 bit value. + * + * @return string Hexadecimal value of least significant bits + */ + public function getLeastSignificantBitsHex(); + + /** + * Returns the most significant 64 bits of this UUID's 128 bit value. + * + * @return string Hexadecimal value of most significant bits + */ + public function getMostSignificantBitsHex(); + + /** + * Returns the node value associated with this UUID + * + * For UUID version 1, the node field consists of an IEEE 802 MAC + * address, usually the host address. For systems with multiple IEEE + * 802 addresses, any available one can be used. The lowest addressed + * octet (octet number 10) contains the global/local bit and the + * unicast/multicast bit, and is the first octet of the address + * transmitted on an 802.3 LAN. + * + * For systems with no IEEE address, a randomly or pseudo-randomly + * generated value may be used; see RFC 4122, Section 4.5. The + * multicast bit must be set in such addresses, in order that they + * will never conflict with addresses obtained from network cards. + * + * For UUID version 3 or 5, the node field is a 48-bit value constructed + * from a name as described in RFC 4122, Section 4.3. + * + * For UUID version 4, the node field is a randomly or pseudo-randomly + * generated 48-bit value as described in RFC 4122, Section 4.4. + * + * @return string Hexadecimal value of node + * @link http://tools.ietf.org/html/rfc4122#section-4.1.6 + */ + public function getNodeHex(); + + /** + * Returns the high field of the timestamp multiplexed with the version + * number (bits 49-64 of the UUID). + * + * @return string Hexadecimal value of time_hi_and_version + */ + public function getTimeHiAndVersionHex(); + + /** + * Returns the low field of the timestamp (the first 32 bits of the UUID). + * + * @return string Hexadecimal value of time_low + */ + public function getTimeLowHex(); + + /** + * Returns the middle field of the timestamp (bits 33-48 of the UUID). + * + * @return string Hexadecimal value of time_mid + */ + public function getTimeMidHex(); + + /** + * Returns the timestamp value associated with this UUID. + * + * The 60 bit timestamp value is constructed from the time_low, + * time_mid, and time_hi fields of this UUID. The resulting + * timestamp is measured in 100-nanosecond units since midnight, + * October 15, 1582 UTC. + * + * The timestamp value is only meaningful in a time-based UUID, which + * has version type 1. If this UUID is not a time-based UUID then + * this method throws UnsupportedOperationException. + * + * @return string Hexadecimal value of the timestamp + * @throws UnsupportedOperationException If this UUID is not a version 1 UUID + * @link http://tools.ietf.org/html/rfc4122#section-4.1.4 + */ + public function getTimestampHex(); + + /** + * Returns the string representation of the UUID as a URN. + * + * @return string + * @link http://en.wikipedia.org/wiki/Uniform_Resource_Name + */ + public function getUrn(); + + /** + * Returns the variant number associated with this UUID. + * + * The variant number describes the layout of the UUID. The variant + * number has the following meaning: + * + * * 0 - Reserved for NCS backward compatibility + * * 2 - The RFC 4122 variant (used by this class) + * * 6 - Reserved, Microsoft Corporation backward compatibility + * * 7 - Reserved for future definition + * + * @return int + * @link http://tools.ietf.org/html/rfc4122#section-4.1.1 + */ + public function getVariant(); + + /** + * Returns the version number associated with this UUID. + * + * The version number describes how this UUID was generated and has the + * following meaning: + * + * * 1 - Time-based UUID + * * 2 - DCE security UUID + * * 3 - Name-based UUID hashed with MD5 + * * 4 - Randomly generated UUID + * * 5 - Name-based UUID hashed with SHA-1 + * + * Returns null if this UUID is not an RFC 4122 variant, since version + * is only meaningful for this variant. + * + * @return int|null + * @link http://tools.ietf.org/html/rfc4122#section-4.1.3 + */ + public function getVersion(); + + /** + * Converts this UUID into a string representation. + * + * @return string + */ + public function toString(); +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/base64url/.php_cs.dist b/lam/lib/3rdParty/composer/spomky-labs/base64url/.php_cs.dist new file mode 100644 index 00000000..a264e013 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/base64url/.php_cs.dist @@ -0,0 +1,61 @@ +in(__DIR__.'/src') + ->in(__DIR__.'/tests') +; + +return PhpCsFixer\Config::create() + ->setRules([ + '@PSR1' => true, + '@PSR2' => 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', + ], + 'mb_str_functions' => true, + 'method_chaining_indentation' => true, + 'linebreak_after_opening_tag' => true, + 'combine_consecutive_issets' => true, + 'combine_consecutive_unsets' => true, + 'compact_nullable_typehint' => true, + 'no_superfluous_phpdoc_tags' => 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, + ]) + ->setRiskyAllowed(true) + ->setUsingCache(true) + ->setFinder($finder) + ; diff --git a/lam/lib/3rdParty/composer/spomky-labs/base64url/LICENSE b/lam/lib/3rdParty/composer/spomky-labs/base64url/LICENSE new file mode 100644 index 00000000..506ff485 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/base64url/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014-2018 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/base64url/composer.json b/lam/lib/3rdParty/composer/spomky-labs/base64url/composer.json new file mode 100644 index 00000000..72074e95 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/base64url/composer.json @@ -0,0 +1,31 @@ +{ + "name": "spomky-labs/base64url", + "description": "Base 64 URL Safe Encoding/Decoding PHP Library", + "type": "library", + "license": "MIT", + "keywords": ["Base64", "URL", "Safe", "RFC4648"], + "homepage": "https://github.com/Spomky-Labs/base64url", + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky-Labs/base64url/contributors" + } + ], + "autoload": { + "psr-4": { + "Base64Url\\": "src/" + } + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0", + "php-coveralls/php-coveralls": "^2.0" + }, + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/base64url/src/Base64Url.php b/lam/lib/3rdParty/composer/spomky-labs/base64url/src/Base64Url.php new file mode 100644 index 00000000..efa9ecbc --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/base64url/src/Base64Url.php @@ -0,0 +1,50 @@ + diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/.github/PULL_REQUEST_TEMPLATE.md b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..c4218d73 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,17 @@ +| Q | A +| ------------- | --- +| Bug fix? | yes/no +| New feature? | yes/no +| BC breaks? | yes/no +| Deprecations? | yes/no +| Tests added | +| Doc PR | + + diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/.php_cs.dist b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/.php_cs.dist new file mode 100644 index 00000000..8591c7a3 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/.php_cs.dist @@ -0,0 +1,61 @@ +in('src') + ->in('tests') +; + +return PhpCsFixer\Config::create() + ->setRules([ + '@PSR1' => true, + '@PSR2' => 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', + ], + 'mb_str_functions' => true, + 'method_chaining_indentation' => true, + 'linebreak_after_opening_tag' => true, + 'combine_consecutive_issets' => true, + 'combine_consecutive_unsets' => true, + 'compact_nullable_typehint' => true, + 'no_superfluous_phpdoc_tags' => 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, + ]) + ->setRiskyAllowed(true) + ->setUsingCache(true) + ->setFinder($finder) + ; diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/CODE_OF_CONDUCT.md b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..4ec12c72 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at contact@spomky-labs.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/LICENSE b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/LICENSE new file mode 100644 index 00000000..25cfdd66 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 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/cbor-php/composer.json b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/composer.json new file mode 100644 index 00000000..1ea25622 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/composer.json @@ -0,0 +1,50 @@ +{ + "name": "spomky-labs/cbor-php", + "type": "library", + "license": "MIT", + "keywords": ["CBOR", "Concise Binary Object Representation", "RFC7049"], + "description": "CBOR Encoder/Decoder for PHP", + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky" + },{ + "name": "All contributors", + "homepage": "https://github.com/Spomky-Labs/cbor-php/contributors" + } + ], + "autoload": { + "psr-4": { + "CBOR\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "CBOR\\Test\\": "tests/" + } + }, + "require": { + "php": "^7.1|^8.0", + "spomky-labs/base64url": "^1.0|^2.0", + "ext-gmp": "*", + "beberlei/assert": "^3.2" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.0", + "phpstan/phpstan": "^0.11", + "phpstan/phpstan-beberlei-assert": "^0.11.0", + "phpstan/phpstan-deprecation-rules": "^0.11", + "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-strict-rules": "^0.11", + "phpunit/phpunit": "^7.5|^8.0", + "rector/rector": "^0.5" + }, + "suggest": { + "ext-bcmath": "BCMath extension needed to handle the Big Float and Decimal Fraction Tags" + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/infection.json.dist b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/infection.json.dist new file mode 100644 index 00000000..7084dd28 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/infection.json.dist @@ -0,0 +1,11 @@ +{ + "timeout":20, + "source": { + "directories": [ + "src" + ] + }, + "logs": { + "text": "infection-log.txt" + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/phpstan.neon b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/phpstan.neon new file mode 100644 index 00000000..f28b5123 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/phpstan.neon @@ -0,0 +1,11 @@ +parameters: + level: 7 + paths: + - src + ignoreErrors: + - '#Method CBOR\\OtherObject\\DoublePrecisionFloatObject::rightShift\(\) should return GMP but returns resource\.#' +includes: + - vendor/phpstan/phpstan-strict-rules/rules.neon + - vendor/phpstan/phpstan-phpunit/extension.neon + - vendor/phpstan/phpstan-deprecation-rules/rules.neon + - vendor/phpstan/phpstan-beberlei-assert/extension.neon diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/AbstractCBORObject.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/AbstractCBORObject.php new file mode 100644 index 00000000..1cf7deba --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/AbstractCBORObject.php @@ -0,0 +1,48 @@ +majorType = $majorType; + $this->additionalInformation = $additionalInformation; + } + + public function getMajorType(): int + { + return $this->majorType; + } + + public function getAdditionalInformation(): int + { + return $this->additionalInformation; + } + + public function __toString(): string + { + return \chr($this->majorType << 5 | $this->additionalInformation); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/ByteStringObject.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/ByteStringObject.php new file mode 100644 index 00000000..930074c1 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/ByteStringObject.php @@ -0,0 +1,64 @@ +length = $length; + $this->value = $data; + } + + public function getValue(): string + { + return $this->value; + } + + public function getLength(): int + { + return mb_strlen($this->value, '8bit'); + } + + public function getNormalizedData(bool $ignoreTags = false): string + { + return $this->value; + } + + public function __toString(): string + { + $result = parent::__toString(); + if (null !== $this->length) { + $result .= $this->length; + } + $result .= $this->value; + + return $result; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/ByteStringWithChunkObject.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/ByteStringWithChunkObject.php new file mode 100644 index 00000000..9efec5fd --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/ByteStringWithChunkObject.php @@ -0,0 +1,87 @@ +chunks[] = $chunk; + } + + public function append(string $chunk): void + { + $this->add(new ByteStringObject($chunk)); + } + + public function getValue(): string + { + $result = ''; + foreach ($this->chunks as $chunk) { + $result .= $chunk->getValue(); + } + + return $result; + } + + public function getLength(): int + { + $length = 0; + foreach ($this->chunks as $chunk) { + $length += $chunk->getLength(); + } + + return $length; + } + + public function getNormalizedData(bool $ignoreTags = false): string + { + $result = ''; + foreach ($this->chunks as $chunk) { + $result .= $chunk->getNormalizedData($ignoreTags); + } + + return $result; + } + + public function __toString(): string + { + $result = parent::__toString(); + foreach ($this->chunks as $chunk) { + $result .= (string) $chunk; + } + $bin = hex2bin('FF'); + if (false === $bin) { + throw new InvalidArgumentException('Unable to convert the data'); + } + $result .= $bin; + + return $result; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/CBORObject.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/CBORObject.php new file mode 100644 index 00000000..09e94ea8 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/CBORObject.php @@ -0,0 +1,28 @@ +tagObjectManager = $tagObjectManager; + $this->otherTypeManager = $otherTypeManager; + } + + public function decode(Stream $stream): CBORObject + { + return $this->process($stream); + } + + private function process(Stream $stream, bool $breakable = false): CBORObject + { + $ib = \ord($stream->read(1)); + $mt = $ib >> 5; + $ai = $ib & 0b00011111; + $val = null; + switch ($ai) { + case 0b00011000: //24 + case 0b00011001: //25 + case 0b00011010: //26 + case 0b00011011: //27 + $val = $stream->read(2 ** ($ai & 0b00000111)); + break; + case 0b00011100: //28 + case 0b00011101: //29 + case 0b00011110: //30 + throw new InvalidArgumentException(sprintf('Cannot parse the data. Found invalid Additional Information "%s" (%d).', str_pad(decbin($ai), 5, '0', STR_PAD_LEFT), $ai)); + case 0b00011111: //31 + return $this->processInfinite($stream, $mt, $breakable); + } + + return $this->processFinite($stream, $mt, $ai, $val); + } + + private function processFinite(Stream $stream, int $mt, int $ai, ?string $val): CBORObject + { + switch ($mt) { + case 0b000: //0 + return UnsignedIntegerObject::createObjectForValue($ai, $val); + case 0b001: //1 + return SignedIntegerObject::createObjectForValue($ai, $val); + case 0b010: //2 + $length = null === $val ? $ai : gmp_intval(gmp_init(bin2hex($val), 16)); + + return new ByteStringObject($stream->read($length)); + case 0b011: //3 + $length = null === $val ? $ai : gmp_intval(gmp_init(bin2hex($val), 16)); + + return new TextStringObject($stream->read($length)); + case 0b100: //4 + $object = new ListObject(); + $nbItems = null === $val ? $ai : gmp_intval(gmp_init(bin2hex($val), 16)); + for ($i = 0; $i < $nbItems; ++$i) { + $object->add($this->process($stream)); + } + + return $object; + case 0b101: //5 + $object = new MapObject(); + $nbItems = null === $val ? $ai : gmp_intval(gmp_init(bin2hex($val), 16)); + for ($i = 0; $i < $nbItems; ++$i) { + $object->add($this->process($stream), $this->process($stream)); + } + + return $object; + case 0b110: //6 + return $this->tagObjectManager->createObjectForValue($ai, $val, $this->process($stream)); + case 0b111: //7 + return $this->otherTypeManager->createObjectForValue($ai, $val); + default: + throw new RuntimeException(sprintf('Unsupported major type "%s" (%d).', str_pad(decbin($mt), 5, '0', STR_PAD_LEFT), $mt)); // Should never append + } + } + + private function processInfinite(Stream $stream, int $mt, bool $breakable): CBORObject + { + switch ($mt) { + case 0b010: //2 + $object = new ByteStringWithChunkObject(); + while (!($it = $this->process($stream, true)) instanceof BreakObject) { + if (!$it instanceof ByteStringObject) { + throw new RuntimeException('Unable to parse the data. Infinite Byte String object can only get Byte String objects.'); + } + $object->add($it); + } + + return $object; + case 0b011: //3 + $object = new TextStringWithChunkObject(); + while (!($it = $this->process($stream, true)) instanceof BreakObject) { + if (!$it instanceof TextStringObject) { + throw new RuntimeException('Unable to parse the data. Infinite Text String object can only get Text String objects.'); + } + $object->add($it); + } + + return $object; + case 0b100: //4 + $object = new InfiniteListObject(); + while (!($it = $this->process($stream, true)) instanceof BreakObject) { + $object->add($it); + } + + return $object; + case 0b101: //5 + $object = new InfiniteMapObject(); + while (!($it = $this->process($stream, true)) instanceof BreakObject) { + $object->append($it, $this->process($stream)); + } + + return $object; + case 0b111: //7 + if (!$breakable) { + throw new InvalidArgumentException('Cannot parse the data. No enclosing indefinite.'); + } + + return new BreakObject(); + case 0b000: //0 + case 0b001: //1 + case 0b110: //6 + default: + throw new InvalidArgumentException(sprintf('Cannot parse the data. Found infinite length for Major Type "%s" (%d).', str_pad(decbin($mt), 5, '0', STR_PAD_LEFT), $mt)); + } + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/InfiniteListObject.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/InfiniteListObject.php new file mode 100644 index 00000000..f8b042bb --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/InfiniteListObject.php @@ -0,0 +1,69 @@ +getNormalizedData($ignoreTags); + }, $this->data); + } + + public function add(CBORObject $item): void + { + $this->data[] = $item; + } + + public function count(): int + { + return \count($this->data); + } + + public function getIterator(): \Iterator + { + return new \ArrayIterator($this->data); + } + + public function __toString(): string + { + $result = parent::__toString(); + foreach ($this->data as $object) { + $result .= (string) $object; + } + $bin = hex2bin('FF'); + if (false === $bin) { + throw new InvalidArgumentException('Unable to convert the data'); + } + $result .= $bin; + + return $result; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/InfiniteMapObject.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/InfiniteMapObject.php new file mode 100644 index 00000000..68a3381e --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/InfiniteMapObject.php @@ -0,0 +1,73 @@ +data[] = new MapItem($key, $value); + } + + public function count(): int + { + return \count($this->data); + } + + public function getIterator(): \Iterator + { + return new \ArrayIterator($this->data); + } + + public function getNormalizedData(bool $ignoreTags = false): array + { + $result = []; + foreach ($this->data as $object) { + $result[$object->getKey()->getNormalizedData($ignoreTags)] = $object->getValue()->getNormalizedData($ignoreTags); + } + + return $result; + } + + public function __toString(): string + { + $result = parent::__toString(); + foreach ($this->data as $object) { + $result .= (string) $object->getKey(); + $result .= (string) $object->getValue(); + } + $bin = hex2bin('FF'); + if (false === $bin) { + throw new InvalidArgumentException('Unable to convert the data'); + } + $result .= $bin; + + return $result; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/LengthCalculator.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/LengthCalculator.php new file mode 100644 index 00000000..310be254 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/LengthCalculator.php @@ -0,0 +1,66 @@ +data = $data; + $this->length = $length; + } + + public function add(CBORObject $object): void + { + $this->data[] = $object; + list($this->additionalInformation, $this->length) = LengthCalculator::getLengthOfArray($this->data); + } + + public function get(int $index): CBORObject + { + if (!\array_key_exists($index, $this->data)) { + throw new InvalidArgumentException('Index not found.'); + } + + return $this->data[$index]; + } + + public function getNormalizedData(bool $ignoreTags = false): array + { + return array_map(function (CBORObject $item) use ($ignoreTags) { + return $item->getNormalizedData($ignoreTags); + }, $this->data); + } + + public function count(): int + { + return \count($this->data); + } + + public function getIterator(): \Iterator + { + return new \ArrayIterator($this->data); + } + + public function __toString(): string + { + $result = parent::__toString(); + if (null !== $this->length) { + $result .= $this->length; + } + foreach ($this->data as $object) { + $result .= (string) $object; + } + + return $result; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/MapItem.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/MapItem.php new file mode 100644 index 00000000..686baa37 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/MapItem.php @@ -0,0 +1,43 @@ +key = $key; + $this->value = $value; + } + + public function getKey(): CBORObject + { + return $this->key; + } + + public function getValue(): CBORObject + { + return $this->value; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/MapObject.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/MapObject.php new file mode 100644 index 00000000..45f145a9 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/MapObject.php @@ -0,0 +1,88 @@ +data = $data; + $this->length = $length; + } + + public function add(CBORObject $key, CBORObject $value): void + { + $this->data[] = new MapItem($key, $value); + list($this->additionalInformation, $this->length) = LengthCalculator::getLengthOfArray($this->data); + } + + public function count(): int + { + return \count($this->data); + } + + public function getIterator(): \Iterator + { + return new \ArrayIterator($this->data); + } + + public function getNormalizedData(bool $ignoreTags = false): array + { + $result = []; + foreach ($this->data as $object) { + $result[$object->getKey()->getNormalizedData($ignoreTags)] = $object->getValue()->getNormalizedData($ignoreTags); + } + + return $result; + } + + public function __toString(): string + { + $result = parent::__toString(); + if (null !== $this->length) { + $result .= $this->length; + } + foreach ($this->data as $object) { + $result .= (string) $object->getKey(); + $result .= (string) $object->getValue(); + } + + return $result; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject.php new file mode 100644 index 00000000..baf034a0 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject.php @@ -0,0 +1,47 @@ +data = $data; + } + + public function __toString(): string + { + $result = parent::__toString(); + if (null !== $this->data) { + $result .= $this->data; + } + + return $result; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/BreakObject.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/BreakObject.php new file mode 100644 index 00000000..e6d59c6c --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/BreakObject.php @@ -0,0 +1,39 @@ +data; + Assertion::string($data, 'Invalid data'); + $single = gmp_init(bin2hex($data), 16); + $exp = gmp_intval($this->bitwiseAnd($this->rightShift($single, 52), gmp_init('7ff', 16))); + $mant = gmp_intval($this->bitwiseAnd($single, gmp_init('fffffffffffff', 16))); + $sign = gmp_intval($this->rightShift($single, 63)); + + if (0 === $exp) { + $val = $mant * 2 ** (-(1022 + 52)); + } elseif (0b11111111111 !== $exp) { + $val = ($mant + (1 << 52)) * 2 ** ($exp - (1023 + 52)); + } else { + $val = 0 === $mant ? INF : NAN; + } + + return 1 === $sign ? -$val : $val; + } + + public function getExponent(): int + { + $data = $this->data; + Assertion::string($data, 'Invalid data'); + $single = gmp_intval(gmp_init(bin2hex($data), 16)); + + return ($single >> 52) & 0x7ff; + } + + public function getMantissa(): int + { + $data = $this->data; + Assertion::string($data, 'Invalid data'); + $single = gmp_intval(gmp_init(bin2hex($data), 16)); + + return $single & 0x7fffff; + } + + public function getSign(): int + { + $data = $this->data; + Assertion::string($data, 'Invalid data'); + $single = gmp_intval(gmp_init(bin2hex($data), 16)); + + return 1 === ($single >> 63) ? -1 : 1; + } + + private function rightShift(\GMP $number, int $positions): \GMP + { + return gmp_div($number, gmp_pow(gmp_init(2, 10), $positions)); + } + + private function bitwiseAnd(\GMP $first, \GMP $other): \GMP + { + return gmp_and($first, $other); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/FalseObject.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/FalseObject.php new file mode 100644 index 00000000..bbc3e15c --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/FalseObject.php @@ -0,0 +1,39 @@ +data; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/HalfPrecisionFloatObject.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/HalfPrecisionFloatObject.php new file mode 100644 index 00000000..6afd3895 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/HalfPrecisionFloatObject.php @@ -0,0 +1,89 @@ +data; + Assertion::string($data, 'Invalid data'); + $half = gmp_intval(gmp_init(bin2hex($data), 16)); + $exp = ($half >> 10) & 0x1f; + $mant = $half & 0x3ff; + + if (0 === $exp) { + $val = $mant * 2 ** (-24); + } elseif (0b11111 !== $exp) { + $val = ($mant + (1 << 10)) * 2 ** ($exp - 25); + } else { + $val = 0 === $mant ? INF : NAN; + } + + return 1 === ($half >> 15) ? -$val : $val; + } + + public function getExponent(): int + { + $data = $this->data; + Assertion::string($data, 'Invalid data'); + $half = gmp_intval(gmp_init(bin2hex($data), 16)); + + return ($half >> 10) & 0x1f; + } + + public function getMantissa(): int + { + $data = $this->data; + Assertion::string($data, 'Invalid data'); + $half = gmp_intval(gmp_init(bin2hex($data), 16)); + + return $half & 0x3ff; + } + + public function getSign(): int + { + $data = $this->data; + Assertion::string($data, 'Invalid data'); + $half = gmp_intval(gmp_init(bin2hex($data), 16)); + + return 1 === ($half >> 15) ? -1 : 1; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/NullObject.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/NullObject.php new file mode 100644 index 00000000..ffbdd912 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/NullObject.php @@ -0,0 +1,38 @@ +classes[$ai] = $class; + } + } + + public function getClassForValue(int $value): string + { + return \array_key_exists($value, $this->classes) ? $this->classes[$value] : GenericObject::class; + } + + public function createObjectForValue(int $value, ?string $data): OtherObject + { + /** @var OtherObject $class */ + $class = $this->getClassForValue($value); + + return $class::createFromLoadedData($value, $data); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/SimpleObject.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/SimpleObject.php new file mode 100644 index 00000000..ff8a690f --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/SimpleObject.php @@ -0,0 +1,54 @@ +data) { + return $this->getAdditionalInformation(); + } + + return gmp_intval(gmp_init(bin2hex($this->data), 16)); + } + + /** + * @return SimpleObject + */ + public static function create(int $value): self + { + switch (true) { + case $value < 24: + return new self($value, null); + case $value < 256: + return new self(24, \chr($value)); + default: + throw new InvalidArgumentException('The value is not a valid simple value'); + } + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/SinglePrecisionFloatObject.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/SinglePrecisionFloatObject.php new file mode 100644 index 00000000..e9c56996 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/SinglePrecisionFloatObject.php @@ -0,0 +1,89 @@ +data; + Assertion::string($data, 'Invalid data'); + $single = gmp_intval(gmp_init(bin2hex($data), 16)); + $exp = ($single >> 23) & 0xff; + $mant = $single & 0x7fffff; + + if (0 === $exp) { + $val = $mant * 2 ** (-(126 + 23)); + } elseif (0b11111111 !== $exp) { + $val = ($mant + (1 << 23)) * 2 ** ($exp - (127 + 23)); + } else { + $val = 0 === $mant ? INF : NAN; + } + + return 1 === ($single >> 31) ? -$val : $val; + } + + public function getExponent(): int + { + $data = $this->data; + Assertion::string($data, 'Invalid data'); + $single = gmp_intval(gmp_init(bin2hex($data), 16)); + + return ($single >> 23) & 0xff; + } + + public function getMantissa(): int + { + $data = $this->data; + Assertion::string($data, 'Invalid data'); + $single = gmp_intval(gmp_init(bin2hex($data), 16)); + + return $single & 0x7fffff; + } + + public function getSign(): int + { + $data = $this->data; + Assertion::string($data, 'Invalid data'); + $single = gmp_intval(gmp_init(bin2hex($data), 16)); + + return 1 === ($single >> 31) ? -1 : 1; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/TrueObject.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/TrueObject.php new file mode 100644 index 00000000..1e354db3 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/OtherObject/TrueObject.php @@ -0,0 +1,39 @@ +data = $data; + } + + public static function createObjectForValue(int $additionalInformation, ?string $data): self + { + return new self($additionalInformation, $data); + } + + public static function create(int $value): self + { + return self::createFromGmpValue(gmp_init($value)); + } + + public static function createFromGmpValue(\GMP $value): self + { + if (gmp_cmp($value, gmp_init(0)) >= 0) { + throw new InvalidArgumentException('The value must be a negative integer.'); + } + + $minusOne = gmp_init(-1); + $computed_value = gmp_sub($minusOne, $value); + + switch (true) { + case gmp_intval($computed_value) < 24: + $ai = gmp_intval($computed_value); + $data = null; + break; + case gmp_cmp($computed_value, gmp_init('FF', 16)) < 0: + $ai = 24; + $data = self::hex2bin(str_pad(gmp_strval($computed_value, 16), 2, '0', STR_PAD_LEFT)); + break; + case gmp_cmp($computed_value, gmp_init('FFFF', 16)) < 0: + $ai = 25; + $data = self::hex2bin(str_pad(gmp_strval($computed_value, 16), 4, '0', STR_PAD_LEFT)); + break; + case gmp_cmp($computed_value, gmp_init('FFFFFFFF', 16)) < 0: + $ai = 26; + $data = self::hex2bin(str_pad(gmp_strval($computed_value, 16), 8, '0', STR_PAD_LEFT)); + break; + default: + throw new InvalidArgumentException('Out of range. Please use NegativeBigIntegerTag tag with ByteStringObject object instead.'); + } + + return new self($ai, $data); + } + + public function getValue(): string + { + return $this->getNormalizedData(); + } + + public function getNormalizedData(bool $ignoreTags = false): string + { + if (null === $this->data) { + return (string) (-1 - $this->additionalInformation); + } + + $result = gmp_init(bin2hex($this->data), 16); + $minusOne = gmp_init(-1); + $result = gmp_sub($minusOne, $result); + + return gmp_strval($result, 10); + } + + public function __toString(): string + { + $result = parent::__toString(); + if (null !== $this->data) { + $result .= $this->data; + } + + return $result; + } + + private static function hex2bin(string $data): string + { + $result = hex2bin($data); + if (false === $result) { + throw new InvalidArgumentException('Unable to convert the data'); + } + + return $result; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Stream.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Stream.php new file mode 100644 index 00000000..47c7387e --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Stream.php @@ -0,0 +1,19 @@ +resource = $resource; + } + + public function read(int $length): string + { + if (0 === $length) { + return ''; + } + $data = fread($this->resource, $length); + if (false === $data) { + throw new RuntimeException('Unable to read the memory'); + } + if (mb_strlen($data, '8bit') !== $length) { + throw new InvalidArgumentException(sprintf('Out of range. Expected: %d, read: %d.', $length, mb_strlen($data, '8bit'))); + } + + return $data; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/Base16EncodingTag.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/Base16EncodingTag.php new file mode 100644 index 00000000..205a82c5 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/Base16EncodingTag.php @@ -0,0 +1,57 @@ +object->getNormalizedData($ignoreTags); + } + + if (!$this->object instanceof ByteStringObject && !$this->object instanceof ByteStringWithChunkObject && !$this->object instanceof TextStringObject && !$this->object instanceof TextStringWithChunkObject) { + return $this->object->getNormalizedData($ignoreTags); + } + + return bin2hex($this->object->getNormalizedData($ignoreTags)); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/Base64EncodingTag.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/Base64EncodingTag.php new file mode 100644 index 00000000..3187a64f --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/Base64EncodingTag.php @@ -0,0 +1,62 @@ +object->getNormalizedData($ignoreTags); + } + + if (!$this->object instanceof ByteStringObject && !$this->object instanceof ByteStringWithChunkObject && !$this->object instanceof TextStringObject && !$this->object instanceof TextStringWithChunkObject) { + return $this->object->getNormalizedData($ignoreTags); + } + + $result = \base64_decode($this->object->getNormalizedData($ignoreTags), true); + if (false === $result) { + throw new InvalidArgumentException('Unable to decode the data'); + } + + return $result; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/Base64UrlEncodingTag.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/Base64UrlEncodingTag.php new file mode 100644 index 00000000..7481948c --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/Base64UrlEncodingTag.php @@ -0,0 +1,58 @@ +object->getNormalizedData($ignoreTags); + } + + if (!$this->object instanceof ByteStringObject && !$this->object instanceof ByteStringWithChunkObject && !$this->object instanceof TextStringObject && !$this->object instanceof TextStringWithChunkObject) { + return $this->object->getNormalizedData($ignoreTags); + } + + return Base64Url::decode($this->object->getNormalizedData($ignoreTags)); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/BigFloatTag.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/BigFloatTag.php new file mode 100644 index 00000000..b14c75bb --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/BigFloatTag.php @@ -0,0 +1,100 @@ +get(0); + if (!$e instanceof UnsignedIntegerObject && !$e instanceof SignedIntegerObject) { + throw new InvalidArgumentException('The exponent must be a Signed Integer or an Unsigned Integer object.'); + } + $m = $object->get(1); + if (!$m instanceof UnsignedIntegerObject && !$m instanceof SignedIntegerObject && !$m instanceof NegativeBigIntegerTag && !$m instanceof PositiveBigIntegerTag) { + throw new InvalidArgumentException('The mantissa must be a Positive or Negative Signed Integer or an Unsigned Integer object.'); + } + + return new self(5, null, $object); + } + + public static function createFromExponentAndMantissa(CBORObject $e, CBORObject $m): Base + { + $object = new ListObject(); + $object->add($e); + $object->add($m); + + return self::create($object); + } + + public function getNormalizedData(bool $ignoreTags = false) + { + if ($ignoreTags) { + return $this->object->getNormalizedData($ignoreTags); + } + + if (!$this->object instanceof ListObject || 2 !== \count($this->object)) { + return $this->object->getNormalizedData($ignoreTags); + } + $e = $this->object->get(0); + $m = $this->object->get(1); + + if (!$e instanceof UnsignedIntegerObject && !$e instanceof SignedIntegerObject) { + return $this->object->getNormalizedData($ignoreTags); + } + if (!$m instanceof UnsignedIntegerObject && !$m instanceof SignedIntegerObject && !$m instanceof NegativeBigIntegerTag && !$m instanceof PositiveBigIntegerTag) { + return $this->object->getNormalizedData($ignoreTags); + } + + return rtrim( + bcmul( + $m->getNormalizedData($ignoreTags), + bcpow( + '2', + $e->getNormalizedData($ignoreTags), + 100), + 100), + '0' + ); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/DecimalFractionTag.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/DecimalFractionTag.php new file mode 100644 index 00000000..c9f9094a --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/DecimalFractionTag.php @@ -0,0 +1,95 @@ +get(0); + if (!$e instanceof UnsignedIntegerObject && !$e instanceof SignedIntegerObject) { + throw new InvalidArgumentException('The exponent must be a Signed Integer or an Unsigned Integer object.'); + } + $m = $object->get(1); + if (!$m instanceof UnsignedIntegerObject && !$m instanceof SignedIntegerObject && !$m instanceof NegativeBigIntegerTag && !$m instanceof PositiveBigIntegerTag) { + throw new InvalidArgumentException('The mantissa must be a Positive or Negative Signed Integer or an Unsigned Integer object.'); + } + + parent::__construct(4, null, $object); + } + + public static function createFromExponentAndMantissa(CBORObject $e, CBORObject $m): Base + { + $object = new ListObject(); + $object->add($e); + $object->add($m); + + return new self($object); + } + + public function getNormalizedData(bool $ignoreTags = false) + { + if ($ignoreTags) { + return $this->object->getNormalizedData($ignoreTags); + } + + if (!$this->object instanceof ListObject || 2 !== \count($this->object)) { + return $this->object->getNormalizedData($ignoreTags); + } + $e = $this->object->get(0); + $m = $this->object->get(1); + + if (!$e instanceof UnsignedIntegerObject && !$e instanceof SignedIntegerObject) { + return $this->object->getNormalizedData($ignoreTags); + } + if (!$m instanceof UnsignedIntegerObject && !$m instanceof SignedIntegerObject && !$m instanceof NegativeBigIntegerTag && !$m instanceof PositiveBigIntegerTag) { + return $this->object->getNormalizedData($ignoreTags); + } + + return rtrim( + bcmul( + $m->getNormalizedData($ignoreTags), + bcpow( + '10', + $e->getNormalizedData($ignoreTags), + 100), + 100), + '0' + ); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/EpochTag.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/EpochTag.php new file mode 100644 index 00000000..8b9c1f7f --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/EpochTag.php @@ -0,0 +1,44 @@ +object->getNormalizedData($ignoreTags); + } + + return \DateTimeImmutable::createFromFormat(DATE_RFC3339, $this->object->getNormalizedData($ignoreTags)); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/GenericTag.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/GenericTag.php new file mode 100644 index 00000000..7538e812 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/GenericTag.php @@ -0,0 +1,35 @@ +object; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/NegativeBigIntegerTag.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/NegativeBigIntegerTag.php new file mode 100644 index 00000000..7dcda5d3 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/NegativeBigIntegerTag.php @@ -0,0 +1,56 @@ +object->getNormalizedData($ignoreTags); + } + + if (!$this->object instanceof ByteStringObject) { + return $this->object->getNormalizedData($ignoreTags); + } + $integer = gmp_init(bin2hex($this->object->getValue()), 16); + $minusOne = gmp_init('-1', 10); + + return gmp_strval(gmp_sub($minusOne, $integer), 10); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/PositiveBigIntegerTag.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/PositiveBigIntegerTag.php new file mode 100644 index 00000000..35eff504 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/PositiveBigIntegerTag.php @@ -0,0 +1,54 @@ +object->getNormalizedData($ignoreTags); + } + + if (!$this->object instanceof ByteStringObject) { + return $this->object->getNormalizedData($ignoreTags); + } + + return gmp_strval(gmp_init(bin2hex($this->object->getValue()), 16), 10); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/TagObjectManager.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/TagObjectManager.php new file mode 100644 index 00000000..b487284f --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/TagObjectManager.php @@ -0,0 +1,53 @@ +classes[$class::getTagId()] = $class; + } + + public function getClassForValue(int $value): string + { + return \array_key_exists($value, $this->classes) ? $this->classes[$value] : GenericTag::class; + } + + public function createObjectForValue(int $additionalInformation, ?string $data, CBORObject $object): TagObject + { + $value = $additionalInformation; + if ($additionalInformation >= 24) { + Assertion::string($data, 'Invalid data'); + $value = gmp_intval(gmp_init(bin2hex($data), 16)); + } + /** @var TagObject $class */ + $class = $this->getClassForValue($value); + + return $class::createFromLoadedData($additionalInformation, $data, $object); + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/TimestampTag.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/TimestampTag.php new file mode 100644 index 00000000..67592eb8 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/Tag/TimestampTag.php @@ -0,0 +1,61 @@ +object->getNormalizedData($ignoreTags); + } + switch (true) { + case $this->object instanceof UnsignedIntegerObject: + return \DateTimeImmutable::createFromFormat('U', \strval($this->object->getNormalizedData($ignoreTags))); + case $this->object instanceof HalfPrecisionFloatObject: + case $this->object instanceof SinglePrecisionFloatObject: + case $this->object instanceof DoublePrecisionFloatObject: + return \DateTimeImmutable::createFromFormat('U.u', \strval($this->object->getNormalizedData($ignoreTags))); + default: + return $this->object->getNormalizedData($ignoreTags); + } + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/TagObject.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/TagObject.php new file mode 100644 index 00000000..4efba2f3 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/TagObject.php @@ -0,0 +1,56 @@ +data = $data; + $this->object = $object; + } + + abstract public static function getTagId(): int; + + abstract public static function createFromLoadedData(int $additionalInformation, ?string $data, CBORObject $object): self; + + public function getValue(): CBORObject + { + return $this->object; + } + + public function __toString(): string + { + $result = parent::__toString(); + if (null !== $this->data) { + $result .= $this->data; + } + $result .= (string) $this->object; + + return $result; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/TextStringObject.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/TextStringObject.php new file mode 100644 index 00000000..b1d36c1b --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/TextStringObject.php @@ -0,0 +1,64 @@ +data = $data; + $this->length = $length; + } + + public function getValue(): string + { + return $this->data; + } + + public function getLength(): int + { + return mb_strlen($this->data, 'utf8'); + } + + public function getNormalizedData(bool $ignoreTags = false): string + { + return $this->data; + } + + public function __toString(): string + { + $result = parent::__toString(); + if (null !== $this->length) { + $result .= $this->length; + } + $result .= $this->data; + + return $result; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/TextStringWithChunkObject.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/TextStringWithChunkObject.php new file mode 100644 index 00000000..fb5db4f3 --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/TextStringWithChunkObject.php @@ -0,0 +1,87 @@ +data[] = $chunk; + } + + public function append(string $chunk): void + { + $this->add(new TextStringObject($chunk)); + } + + public function getValue(): string + { + $result = ''; + foreach ($this->data as $object) { + $result .= $object->getValue(); + } + + return $result; + } + + public function getLength(): int + { + $length = 0; + foreach ($this->data as $object) { + $length += $object->getLength(); + } + + return $length; + } + + public function getNormalizedData(bool $ignoreTags = false): string + { + $result = ''; + foreach ($this->data as $object) { + $result .= $object->getNormalizedData($ignoreTags); + } + + return $result; + } + + public function __toString(): string + { + $result = parent::__toString(); + foreach ($this->data as $object) { + $result .= (string) $object; + } + $bin = hex2bin('FF'); + if (false === $bin) { + throw new InvalidArgumentException('Unable to convert the data'); + } + $result .= $bin; + + return $result; + } +} diff --git a/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/UnsignedIntegerObject.php b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/UnsignedIntegerObject.php new file mode 100644 index 00000000..324d30db --- /dev/null +++ b/lam/lib/3rdParty/composer/spomky-labs/cbor-php/src/UnsignedIntegerObject.php @@ -0,0 +1,116 @@ +data = $data; + } + + public static function createObjectForValue(int $additionalInformation, ?string $data): self + { + return new self($additionalInformation, $data); + } + + public static function create(int $value): self + { + return self::createFromGmpValue(gmp_init($value)); + } + + public static function createFromGmpValue(\GMP $value): self + { + if (gmp_cmp($value, gmp_init(0)) < 0) { + throw new InvalidArgumentException('The value must be a positive integer.'); + } + + switch (true) { + case gmp_cmp($value, gmp_init(24)) < 0: + $ai = gmp_intval($value); + $data = null; + break; + case gmp_cmp($value, gmp_init('FF', 16)) < 0: + $ai = 24; + $data = self::hex2bin(str_pad(gmp_strval($value, 16), 2, '0', STR_PAD_LEFT)); + break; + case gmp_cmp($value, gmp_init('FFFF', 16)) < 0: + $ai = 25; + $data = self::hex2bin(str_pad(gmp_strval($value, 16), 4, '0', STR_PAD_LEFT)); + break; + case gmp_cmp($value, gmp_init('FFFFFFFF', 16)) < 0: + $ai = 26; + $data = self::hex2bin(str_pad(gmp_strval($value, 16), 8, '0', STR_PAD_LEFT)); + break; + default: + throw new InvalidArgumentException('Out of range. Please use PositiveBigIntegerTag tag with ByteStringObject object instead.'); + } + + return new self($ai, $data); + } + + public function getMajorType(): int + { + return self::MAJOR_TYPE; + } + + public function getAdditionalInformation(): int + { + return $this->additionalInformation; + } + + public function getValue(): string + { + return $this->getNormalizedData(); + } + + public function getNormalizedData(bool $ignoreTags = false): string + { + if (null === $this->data) { + return \strval($this->additionalInformation); + } + + return gmp_strval(gmp_init(bin2hex($this->data), 16), 10); + } + + public function __toString(): string + { + $result = parent::__toString(); + if (null !== $this->data) { + $result .= $this->data; + } + + return $result; + } + + private static function hex2bin(string $data): string + { + $result = hex2bin($data); + if (false === $result) { + throw new InvalidArgumentException('Unable to convert the data'); + } + + return $result; + } +} 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 00000000..58414dc7 --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-ctype/Ctype.php @@ -0,0 +1,227 @@ + + * + * 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 string|int $text + * + * @return bool + */ + public static function ctype_alnum($text) + { + $text = self::convert_int_to_char_for_ctype($text); + + 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 string|int $text + * + * @return bool + */ + public static function ctype_alpha($text) + { + $text = self::convert_int_to_char_for_ctype($text); + + 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 string|int $text + * + * @return bool + */ + public static function ctype_cntrl($text) + { + $text = self::convert_int_to_char_for_ctype($text); + + 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 string|int $text + * + * @return bool + */ + public static function ctype_digit($text) + { + $text = self::convert_int_to_char_for_ctype($text); + + 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 string|int $text + * + * @return bool + */ + public static function ctype_graph($text) + { + $text = self::convert_int_to_char_for_ctype($text); + + 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 string|int $text + * + * @return bool + */ + public static function ctype_lower($text) + { + $text = self::convert_int_to_char_for_ctype($text); + + 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 string|int $text + * + * @return bool + */ + public static function ctype_print($text) + { + $text = self::convert_int_to_char_for_ctype($text); + + 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 string|int $text + * + * @return bool + */ + public static function ctype_punct($text) + { + $text = self::convert_int_to_char_for_ctype($text); + + 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 string|int $text + * + * @return bool + */ + public static function ctype_space($text) + { + $text = self::convert_int_to_char_for_ctype($text); + + 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 string|int $text + * + * @return bool + */ + public static function ctype_upper($text) + { + $text = self::convert_int_to_char_for_ctype($text); + + 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 string|int $text + * + * @return bool + */ + public static function ctype_xdigit($text) + { + $text = self::convert_int_to_char_for_ctype($text); + + 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 string|int $int + * + * @return mixed + */ + private static function convert_int_to_char_for_ctype($int) + { + if (!\is_int($int)) { + return $int; + } + + if ($int < -128 || $int > 255) { + return (string) $int; + } + + 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 00000000..3f853aaf --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-ctype/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-2019 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 00000000..8add1ab0 --- /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/master/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 00000000..14d1d0fa --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-ctype/bootstrap.php @@ -0,0 +1,26 @@ + + * + * 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($text) { return p\Ctype::ctype_alnum($text); } + function ctype_alpha($text) { return p\Ctype::ctype_alpha($text); } + function ctype_cntrl($text) { return p\Ctype::ctype_cntrl($text); } + function ctype_digit($text) { return p\Ctype::ctype_digit($text); } + function ctype_graph($text) { return p\Ctype::ctype_graph($text); } + function ctype_lower($text) { return p\Ctype::ctype_lower($text); } + function ctype_print($text) { return p\Ctype::ctype_print($text); } + function ctype_punct($text) { return p\Ctype::ctype_punct($text); } + function ctype_space($text) { return p\Ctype::ctype_space($text); } + function ctype_upper($text) { return p\Ctype::ctype_upper($text); } + function ctype_xdigit($text) { 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 00000000..090f923e --- /dev/null +++ b/lam/lib/3rdParty/composer/symfony/polyfill-ctype/composer.json @@ -0,0 +1,34 @@ +{ + "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": ">=5.3.3" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Ctype\\": "" }, + "files": [ "bootstrap.php" ] + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "1.12-dev" + } + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/LICENSE b/lam/lib/3rdParty/composer/web-auth/cose-lib/LICENSE new file mode 100644 index 00000000..25cfdd66 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 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/cose-lib/README.md b/lam/lib/3rdParty/composer/web-auth/cose-lib/README.md new file mode 100644 index 00000000..11297ba5 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/README.md @@ -0,0 +1,31 @@ +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. + +# Installation + +Install the library with Composer: `composer require web-auth/cose-lib`. + +# Contribution + +This repository is a sub repository of [the Web Authentication Framework](https://github.com/web-auth/webauthn-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-auth/webauthn-framework) instead. + +# Documentation + +The official documentation is available at https://github.com/web-auth/webauthn-framework + +# Support + +I bring solutions to your problems and answer your questions. + +If you really love that project and the work I have done or if you want I prioritize your issues, then you can help me out for a couple of :beers: or more! + +[![Become a Patreon](https://c5.patreon.com/external/logo/become_a_patron_button.png)](https://www.patreon.com/FlorentMorselli) + +# Licence + +This project is release under [MIT licence](LICENSE). diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/composer.json b/lam/lib/3rdParty/composer/web-auth/cose-lib/composer.json new file mode 100644 index 00000000..e35ff676 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/composer.json @@ -0,0 +1,45 @@ +{ + "name": "web-auth/cose-lib", + "type": "library", + "license": "MIT", + "description": "CBOR Object Signing and Encryption (COSE) For PHP", + "keywords": ["COSE", "RFC8152"], + "homepage": "https://github.com/web-auth", + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky" + }, + { + "name": "All contributors", + "homepage": "https://github.com/web-auth/cose/contributors" + } + ], + "require": { + "php": "^7.2", + "ext-json": "*", + "ext-openssl": "*", + "ext-mbstring": "*", + "fgrosse/phpasn1": "^2.1", + "beberlei/assert": "^3.0" + }, + "autoload": { + "psr-4": { + "Cose\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Cose\\Tests\\Unit\\": "tests/unit/" + } + }, + "extra": { + "branch-alias": { + "v1.0": "1.0.x-dev", + "v1.1": "1.1.x-dev", + "v1.2": "1.2.x-dev", + "v2.0": "2.0.x-dev", + "v2.1": "2.1.x-dev" + } + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Algorithm.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Algorithm.php new file mode 100644 index 00000000..ed893835 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Algorithm.php @@ -0,0 +1,19 @@ +checKey($key); + $signature = hash_hmac($this->getHashAlgorithm(), $data, $key->get(-1), true); + + return mb_substr($signature, 0, $this->getSignatureLength() / 8, '8bit'); + } + + public function verify(string $data, Key $key, string $signature): bool + { + return hash_equals($this->hash($data, $key), $signature); + } + + private function checKey(Key $key): void + { + Assertion::eq($key->type(), 4, 'Invalid key. Must be of type symmetric'); + Assertion::true($key->has(-1), 'Invalid key. The value of the key is missing'); + } + + abstract protected function getHashAlgorithm(): string; + + abstract protected function getSignatureLength(): int; +} diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Mac/Mac.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Mac/Mac.php new file mode 100644 index 00000000..fcf9fb51 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Mac/Mac.php @@ -0,0 +1,24 @@ +algorithms[$identifier] = $algorithm; + } + + /** + * @deprecated Will be removed in v3.0. Please use all() instead + */ + public function getAlgorithms(): iterable + { + yield from $this->algorithms; + } + + public function list(): iterable + { + yield from array_keys($this->algorithms); + } + + /** + * @return Algorithm[] + */ + public function all(): iterable + { + yield from $this->algorithms; + } + + public function has(int $identifier): bool + { + return \array_key_exists($identifier, $this->algorithms); + } + + public function get(int $identifier): Algorithm + { + Assertion::true($this->has($identifier), 'Unsupported algorithm'); + + return $this->algorithms[$identifier]; + } +} 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 new file mode 100644 index 00000000..f2cb15b6 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/ManagerFactory.php @@ -0,0 +1,50 @@ +algorithms[$alias] = $algorithm; + } + + public function list(): iterable + { + yield from array_keys($this->algorithms); + } + + public function all(): iterable + { + yield from array_keys($this->algorithms); + } + + public function create(array $aliases): Manager + { + $manager = new Manager(); + foreach ($aliases as $alias) { + Assertion::keyExists($this->algorithms, $alias, sprintf('The algorithm with alias "%s" is not supported', $alias)); + $manager->add($this->algorithms[$alias]); + } + + return $manager; + } +} 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 new file mode 100644 index 00000000..da1265b0 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ECDSA.php @@ -0,0 +1,58 @@ +handleKey($key); + $result = openssl_sign($data, $signature, $key->asPEM(), $this->getHashAlgorithm()); + Assertion::true($result, 'Unable to sign the data'); + + return $signature; + } + + public function verify(string $data, Key $key, string $signature): bool + { + $key = $this->handleKey($key); + $publicKey = $key->toPublic(); + + return 1 === openssl_verify($data, $signature, $publicKey->asPEM(), $this->getHashAlgorithm()); + } + + private function handleKey(Key $key): Ec2Key + { + $key = new Ec2Key($key->getData()); + Assertion::eq($key->curve(), $this->getCurve(), 'This key cannot be used with this algorithm'); + + return $key; + } + + abstract protected function getCurve(): int; + + abstract protected function getHashAlgorithm(): int; +} 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 new file mode 100644 index 00000000..db99c188 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ECSignature.php @@ -0,0 +1,133 @@ + self::ASN1_MAX_SINGLE_BYTE ? self::ASN1_LENGTH_2BYTES : ''; + + return self::hex2bin( + self::ASN1_SEQUENCE + .$lengthPrefix.dechex($totalLength) + .self::ASN1_INTEGER.dechex($lengthR).$pointR + .self::ASN1_INTEGER.dechex($lengthS).$pointS + ); + } + + 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)); + + return self::hex2bin(str_pad($pointR, $length, '0', STR_PAD_LEFT).str_pad($pointS, $length, '0', STR_PAD_LEFT)); + } + + 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 (self::ASN1_NEGATIVE_INTEGER === mb_substr($data, 0, self::BYTE_SIZE, '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; + } + + 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 (self::ASN1_NEGATIVE_INTEGER === mb_substr($data, 0, self::BYTE_SIZE, '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 hex2bin(string $data): string + { + $result = \hex2bin($data); + if (false === $result) { + throw new InvalidArgumentException('Unable to convert the data'); + } + + return $result; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ES256.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ES256.php new file mode 100644 index 00000000..3378b6fd --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ES256.php @@ -0,0 +1,60 @@ +getSignaturePartLength()); + } + + public function verify(string $data, Key $key, string $signature): bool + { + if (mb_strlen($signature, '8bit') !== $this->getSignaturePartLength()) { + @trigger_error('Since v2.1, the method "verify" will only accept raw ECDSA signature in v3.0 and ASN.1 structures will be rejected', E_USER_DEPRECATED); + } else { + $signature = ECSignature::toAsn1($signature, $this->getSignaturePartLength()); + } + + return parent::verify($data, $key, $signature); + } + + protected function getHashAlgorithm(): int + { + return OPENSSL_ALGO_SHA256; + } + + protected function getCurve(): int + { + return Ec2Key::CURVE_P256; + } + + protected function getSignaturePartLength(): int + { + return 64; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ES256K.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ES256K.php new file mode 100644 index 00000000..206162af --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ES256K.php @@ -0,0 +1,60 @@ +getSignaturePartLength()); + } + + public function verify(string $data, Key $key, string $signature): bool + { + if (mb_strlen($signature, '8bit') !== $this->getSignaturePartLength()) { + @trigger_error('Since v2.1, the method "verify" will only accept raw ECDSA signature in v3.0 and ASN.1 structures will be rejected', E_USER_DEPRECATED); + } else { + $signature = ECSignature::toAsn1($signature, $this->getSignaturePartLength()); + } + + return parent::verify($data, $key, $signature); + } + + protected function getHashAlgorithm(): int + { + return OPENSSL_ALGO_SHA256; + } + + protected function getCurve(): int + { + return Ec2Key::CURVE_P256K; + } + + protected function getSignaturePartLength(): int + { + return 64; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ES384.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ES384.php new file mode 100644 index 00000000..b70dc313 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ES384.php @@ -0,0 +1,60 @@ +getSignaturePartLength()); + } + + public function verify(string $data, Key $key, string $signature): bool + { + if (mb_strlen($signature, '8bit') !== $this->getSignaturePartLength()) { + @trigger_error('Since v2.1, the method "verify" will only accept raw ECDSA signature in v3.0 and ASN.1 structures will be rejected', E_USER_DEPRECATED); + } else { + $signature = ECSignature::toAsn1($signature, $this->getSignaturePartLength()); + } + + return parent::verify($data, $key, $signature); + } + + protected function getHashAlgorithm(): int + { + return OPENSSL_ALGO_SHA384; + } + + protected function getCurve(): int + { + return Ec2Key::CURVE_P384; + } + + protected function getSignaturePartLength(): int + { + return 96; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ES512.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ES512.php new file mode 100644 index 00000000..b88f2c32 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/ECDSA/ES512.php @@ -0,0 +1,60 @@ +getSignaturePartLength()); + } + + public function verify(string $data, Key $key, string $signature): bool + { + if (mb_strlen($signature, '8bit') !== $this->getSignaturePartLength()) { + @trigger_error('Since v2.1, the method "verify" accepts ASN.1 structures and raw ECDSA signature. In v3.0 and ASN.1 structures will be rejected', E_USER_DEPRECATED); + } else { + $signature = ECSignature::toAsn1($signature, $this->getSignaturePartLength()); + } + + return parent::verify($data, $key, $signature); + } + + protected function getHashAlgorithm(): int + { + return OPENSSL_ALGO_SHA512; + } + + protected function getCurve(): int + { + return Ec2Key::CURVE_P521; + } + + protected function getSignaturePartLength(): int + { + return 132; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/EdDSA/ED256.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/EdDSA/ED256.php new file mode 100644 index 00000000..a8888704 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/EdDSA/ED256.php @@ -0,0 +1,40 @@ +handleKey($key); + Assertion::true($key->isPrivate(), 'The key is not private'); + + $x = $key->x(); + $d = $key->d(); + $secret = $d.$x; + + switch ($key->curve()) { + case OkpKey::CURVE_ED25519: + return sodium_crypto_sign_detached($data, $secret); + default: + throw new InvalidArgumentException('Unsupported curve'); + } + } + + public function verify(string $data, Key $key, string $signature): bool + { + $key = $this->handleKey($key); + + switch ($key->curve()) { + case OkpKey::CURVE_ED25519: + return sodium_crypto_sign_verify_detached($signature, $data, $key->x()); + default: + throw new InvalidArgumentException('Unsupported curve'); + } + } + + public static function identifier(): int + { + return Algorithms::COSE_ALGORITHM_EdDSA; + } + + private function handleKey(Key $key): OkpKey + { + return new OkpKey($key->getData()); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/PS256.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/PS256.php new file mode 100644 index 00000000..cde18db6 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/PS256.php @@ -0,0 +1,31 @@ +handleKey($key); + $modulusLength = mb_strlen($key->n(), '8bit'); + + $em = $this->encodeEMSAPSS($data, 8 * $modulusLength - 1, $this->getHashAlgorithm()); + $message = BigInteger::createFromBinaryString($em); + $signature = $this->exponentiate($key, $message); + + return $this->convertIntegerToOctetString($signature, $modulusLength); + } + + 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) { + throw new InvalidArgumentException('Invalid modulus length'); + } + $s2 = BigInteger::createFromBinaryString($signature); + $m2 = $this->exponentiate($key, $s2); + $em = $this->convertIntegerToOctetString($m2, $modulusLength); + $modBits = 8 * $modulusLength; + + return $this->verifyEMSAPSS($data, $em, $modBits - 1, $this->getHashAlgorithm()); + } + + private function handleKey(Key $key): RsaKey + { + return new RsaKey($key->getData()); + } + + abstract protected function getHashAlgorithm(): Hash; + + private function convertIntegerToOctetString(BigInteger $x, int $xLen): string + { + $x = $x->toBytes(); + if (mb_strlen($x, '8bit') > $xLen) { + throw new RuntimeException('Unable to convert the integer'); + } + + return str_pad($x, $xLen, \chr(0), STR_PAD_LEFT); + } + + /** + * MGF1. + */ + private 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 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 = $this->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 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 = $this->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); + } + + /** + * Exponentiate with or without Chinese Remainder Theorem. + * Operation with primes 'p' and 'q' is appox. 2x faster. + */ + public function exponentiate(RsaKey $key, BigInteger $c): BigInteger + { + if ($c->compare(BigInteger::createFromDecimal(0)) < 0 || $c->compare(BigInteger::createFromBinaryString($key->n())) > 0) { + throw new RuntimeException(); + } + if ($key->isPublic() || !$key->hasPrimes() || !$key->hasExponents() || !$key->hasCoefficient()) { + return $c->modPow(BigInteger::createFromBinaryString($key->e()), BigInteger::createFromBinaryString($key->n())); + } + + $p = $key->primes()[0]; + $q = $key->primes()[1]; + $dP = $key->exponents()[0]; + $dQ = $key->exponents()[1]; + $qInv = BigInteger::createFromBinaryString($key->QInv()); + + $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)); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/RS1.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/RS1.php new file mode 100644 index 00000000..c6421d9b --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/RSA/RS1.php @@ -0,0 +1,29 @@ +handleKey($key); + Assertion::true($key->isPrivate(), 'The key is not private'); + + $result = openssl_sign($data, $signature, $key->asPem(), $this->getHashAlgorithm()); + Assertion::true($result, 'Unable to sign the data'); + + return $signature; + } + + public function verify(string $data, Key $key, string $signature): bool + { + $key = $this->handleKey($key); + + return 1 === openssl_verify($data, $signature, $key->asPem(), $this->getHashAlgorithm()); + } + + private function handleKey(Key $key): RsaKey + { + return new RsaKey($key->getData()); + } + + abstract protected function getHashAlgorithm(): int; +} diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/Signature.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/Signature.php new file mode 100644 index 00000000..d9fa0d96 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Algorithm/Signature/Signature.php @@ -0,0 +1,24 @@ + OPENSSL_ALGO_SHA256, + self::COSE_ALGORITHM_ES384 => OPENSSL_ALGO_SHA384, + self::COSE_ALGORITHM_ES512 => OPENSSL_ALGO_SHA512, + self::COSE_ALGORITHM_RS256 => OPENSSL_ALGO_SHA256, + self::COSE_ALGORITHM_RS384 => OPENSSL_ALGO_SHA384, + self::COSE_ALGORITHM_RS512 => OPENSSL_ALGO_SHA512, + self::COSE_ALGORITHM_RS1 => OPENSSL_ALGO_SHA1, + ]; + + public const COSE_HASH_MAP = [ + self::COSE_ALGORITHM_ES256K => 'sha256', + self::COSE_ALGORITHM_ES256 => 'sha256', + self::COSE_ALGORITHM_ES384 => 'sha384', + self::COSE_ALGORITHM_ES512 => 'sha512', + self::COSE_ALGORITHM_RS256 => 'sha256', + self::COSE_ALGORITHM_RS384 => 'sha384', + self::COSE_ALGORITHM_RS512 => 'sha512', + self::COSE_ALGORITHM_PS256 => 'sha256', + self::COSE_ALGORITHM_PS384 => 'sha384', + self::COSE_ALGORITHM_PS512 => 'sha512', + self::COSE_ALGORITHM_RS1 => 'sha1', + ]; + + public static function getOpensslAlgorithmFor(int $algorithmIdentifier): int + { + Assertion::keyExists(self::COSE_ALGORITHM_MAP, $algorithmIdentifier, 'The specified algorithm identifier is not supported'); + + return self::COSE_ALGORITHM_MAP[$algorithmIdentifier]; + } + + public static function getHashAlgorithmFor(int $algorithmIdentifier): string + { + Assertion::keyExists(self::COSE_HASH_MAP, $algorithmIdentifier, 'The specified algorithm identifier is not supported'); + + return self::COSE_HASH_MAP[$algorithmIdentifier]; + } + + /** + * @deprecated Will be removed in v3.0. Please use the Manager or the ManagerFactory + */ + public static function getAlgorithm(int $identifier): Algorithm + { + $algs = static::getAlgorithms(); + Assertion::keyExists($algs, $identifier, 'The specified algorithm identifier is not supported'); + + return $algs[$identifier]; + } + + /** + * @deprecated Will be removed in v3.0. Please use the Manager or the ManagerFactory + * + * @return Algorithm[] + */ + public static function getAlgorithms(): array + { + return [ + Mac\HS256::identifier() => new Mac\HS256(), + Mac\HS384::identifier() => new Mac\HS384(), + Mac\HS512::identifier() => new Mac\HS512(), + RSA\RS256::identifier() => new RSA\RS256(), + RSA\RS384::identifier() => new RSA\RS384(), + RSA\RS512::identifier() => new RSA\RS512(), + RSA\PS256::identifier() => new RSA\PS256(), + RSA\PS384::identifier() => new RSA\PS384(), + RSA\PS512::identifier() => new RSA\PS512(), + ECDSA\ES256K::identifier() => new ECDSA\ES256K(), + ECDSA\ES256::identifier() => new ECDSA\ES256(), + ECDSA\ES384::identifier() => new ECDSA\ES384(), + ECDSA\ES512::identifier() => new ECDSA\ES512(), + EdDSA\ED512::identifier() => new EdDSA\ED512(), + ]; + } +} 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 new file mode 100644 index 00000000..9db05592 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/Ec2Key.php @@ -0,0 +1,144 @@ + '1.2.840.10045.3.1.7', // NIST P-256 / secp256r1 + self::CURVE_P256K => '1.3.132.0.10', // NIST P-256K / secp256k1 + self::CURVE_P384 => '1.3.132.0.34', // NIST P-384 / secp384r1 + self::CURVE_P521 => '1.3.132.0.35', // NIST P-521 / secp521r1 + ]; + + private const CURVE_KEY_LENGTH = [ + self::CURVE_P256 => 32, + self::CURVE_P256K => 32, + self::CURVE_P384 => 48, + self::CURVE_P521 => 66, + ]; + + public function __construct(array $data) + { + parent::__construct($data); + Assertion::eq($data[self::TYPE], self::TYPE_EC2, 'Invalid EC2 key. The key type does not correspond to an EC2 key'); + Assertion::keyExists($data, self::DATA_CURVE, 'Invalid EC2 key. The curve is missing'); + Assertion::keyExists($data, self::DATA_X, 'Invalid EC2 key. The x coordinate is missing'); + Assertion::keyExists($data, self::DATA_Y, 'Invalid EC2 key. The y coordinate is missing'); + Assertion::length($data[self::DATA_X], self::CURVE_KEY_LENGTH[$data[self::DATA_CURVE]], 'Invalid length for x coordinate', null, '8bit'); + Assertion::length($data[self::DATA_Y], self::CURVE_KEY_LENGTH[$data[self::DATA_CURVE]], 'Invalid length for y coordinate', null, '8bit'); + Assertion::inArray((int) $data[self::DATA_CURVE], self::SUPPORTED_CURVES, 'The curve is not supported'); + } + + public function toPublic(): self + { + $data = $this->getData(); + unset($data[self::DATA_D]); + + return new self($data); + } + + public function x(): string + { + return $this->get(self::DATA_X); + } + + public function y(): string + { + return $this->get(self::DATA_Y); + } + + public function isPrivate(): bool + { + return \array_key_exists(self::DATA_D, $this->getData()); + } + + public function d(): string + { + Assertion::true($this->isPrivate(), 'The key is not private'); + + return $this->get(self::DATA_D); + } + + public function curve(): int + { + return (int) $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()))) + ); + + return $this->pem('EC PRIVATE KEY', $der->getBinary()); + } + + $der = new Sequence( + new Sequence( + new ObjectIdentifier('1.2.840.10045.2.1'), + new ObjectIdentifier($this->getCurveOid()) + ), + new BitString(\bin2hex($this->getUncompressedCoordinates())) + ); + + return $this->pem('PUBLIC KEY', $der->getBinary()); + } + + private function getCurveOid(): string + { + return self::NAMED_CURVE_OID[$this->curve()]; + } + + public function getUncompressedCoordinates(): string + { + return "\x04".$this->x().$this->y(); + } + + 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)); + } +} 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 new file mode 100644 index 00000000..d7cbaa89 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/Key.php @@ -0,0 +1,90 @@ +data = $data; + } + + public static function createFromData(array $data): self + { + Assertion::keyExists($data, self::TYPE, 'Invalid key: the type is not defined'); + switch ($data[self::TYPE]) { + case 1: + return new OkpKey($data); + case 2: + return new Ec2Key($data); + case 3: + return new RsaKey($data); + case 4: + return new SymmetricKey($data); + default: + return new self($data); + } + } + + /** + * @return int|string + */ + public function type() + { + return $this->data[self::TYPE]; + } + + public function alg(): int + { + return (int) $this->get(self::ALG); + } + + public function getData(): array + { + return $this->data; + } + + public function has(int $key): bool + { + return \array_key_exists($key, $this->data); + } + + /** + * @return mixed + */ + public function get(int $key) + { + Assertion::keyExists($this->data, $key, sprintf('The key has no data at index %d', $key)); + + return $this->data[$key]; + } +} 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 new file mode 100644 index 00000000..2dfcc695 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/OkpKey.php @@ -0,0 +1,66 @@ +get(self::DATA_X); + } + + public function isPrivate(): bool + { + return \array_key_exists(self::DATA_D, $this->getData()); + } + + public function d(): string + { + Assertion::true($this->isPrivate(), 'The key is not private'); + + return $this->get(self::DATA_D); + } + + public function curve(): int + { + return (int) $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 new file mode 100644 index 00000000..dcfa39df --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/RsaKey.php @@ -0,0 +1,197 @@ +get(self::DATA_N); + } + + public function e(): string + { + return $this->get(self::DATA_E); + } + + public function d(): string + { + Assertion::true($this->isPrivate(), 'The key is not private.'); + + return $this->get(self::DATA_D); + } + + public function p(): string + { + Assertion::true($this->isPrivate(), 'The key is not private.'); + + return $this->get(self::DATA_P); + } + + public function q(): string + { + Assertion::true($this->isPrivate(), 'The key is not private.'); + + return $this->get(self::DATA_Q); + } + + public function dP(): string + { + Assertion::true($this->isPrivate(), 'The key is not private.'); + + return $this->get(self::DATA_DP); + } + + public function dQ(): string + { + Assertion::true($this->isPrivate(), 'The key is not private.'); + + return $this->get(self::DATA_DQ); + } + + public function QInv(): string + { + Assertion::true($this->isPrivate(), 'The key is not private.'); + + return $this->get(self::DATA_QI); + } + + public function other(): array + { + Assertion::true($this->isPrivate(), 'The key is not private.'); + + return $this->get(self::DATA_OTHER); + } + + public function rI(): string + { + Assertion::true($this->isPrivate(), 'The key is not private.'); + + return $this->get(self::DATA_RI); + } + + public function dI(): string + { + Assertion::true($this->isPrivate(), 'The key is not private.'); + + return $this->get(self::DATA_DI); + } + + public function tI(): string + { + Assertion::true($this->isPrivate(), 'The key is not private.'); + + return $this->get(self::DATA_TI); + } + + public function hasPrimes(): bool + { + return $this->has(self::DATA_P) && $this->has(self::DATA_Q); + } + + public function primes(): array + { + return [ + $this->p(), + $this->q(), + ]; + } + + public function hasExponents(): bool + { + return $this->has(self::DATA_DP) && $this->has(self::DATA_DQ); + } + + public function exponents(): array + { + return [ + $this->dP(), + $this->dQ(), + ]; + } + + public function hasCoefficient(): bool + { + return $this->has(self::DATA_QI); + } + + public function isPublic(): bool + { + return !$this->isPrivate(); + } + + public function isPrivate(): bool + { + return \array_key_exists(self::DATA_D, $this->getData()); + } + + public function asPem(): string + { + Assertion::false($this->isPrivate(), 'Unsupported for private keys.'); + $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())) + ); + + return $this->pem('PUBLIC KEY', $der->getBinary()); + } + + private function fromBase64ToInteger(string $value): string + { + return gmp_strval(gmp_init(current(unpack('H*', $value)), 16), 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)); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/SymmetricKey.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/SymmetricKey.php new file mode 100644 index 00000000..b718ea6d --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Key/SymmetricKey.php @@ -0,0 +1,33 @@ +get(self::DATA_K); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Verifier.php b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Verifier.php new file mode 100644 index 00000000..325c9bbb --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/cose-lib/src/Verifier.php @@ -0,0 +1,18 @@ +selfAttestedFRR; + } + + /** + * @return int + */ + public function getSelfAttestedFAR(): ?int + { + return $this->selfAttestedFAR; + } + + /** + * @return int|null + */ + public function getMaxTemplates(): ?int + { + return $this->maxTemplates; + } + + /** + * @return int|null + */ + public function getMaxRetries(): ?int + { + return $this->maxRetries; + } + + /** + * @return int|null + */ + public function getBlockSlowdown(): ?int + { + return $this->blockSlowdown; + } + + public static function createFromArray(array $data): self + { + $object = new self(); + $object->selfAttestedFRR = $data['selfAttestedFRR'] ?? null; + $object->selfAttestedFAR = $data['selfAttestedFAR'] ?? null; + $object->maxTemplates = $data['maxTemplates'] ?? null; + $object->maxRetries = $data['maxRetries'] ?? null; + $object->blockSlowdown = $data['blockSlowdown'] ?? null; + + return $object; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/BiometricStatusReport.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/BiometricStatusReport.php new file mode 100644 index 00000000..a37230de --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/BiometricStatusReport.php @@ -0,0 +1,101 @@ +certLevel; + } + + public function getModality(): int + { + 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; + } + + 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; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/CodeAccuracyDescriptor.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/CodeAccuracyDescriptor.php new file mode 100644 index 00000000..990df1ff --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/CodeAccuracyDescriptor.php @@ -0,0 +1,68 @@ +base; + } + + public function getMinLength(): int + { + return $this->minLength; + } + + public function getMaxRetries(): ?int + { + return $this->maxRetries; + } + + public function getBlockSlowdown(): ?int + { + return $this->blockSlowdown; + } + + public static function createFromArray(array $data): self + { + $object = new self(); + $object->base = $data['base'] ?? null; + $object->minLength = $data['minLength'] ?? null; + $object->maxRetries = $data['maxRetries'] ?? null; + $object->blockSlowdown = $data['blockSlowdown'] ?? null; + + return $object; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/DisplayPNGCharacteristicsDescriptor.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/DisplayPNGCharacteristicsDescriptor.php new file mode 100644 index 00000000..0cca7bb8 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/DisplayPNGCharacteristicsDescriptor.php @@ -0,0 +1,124 @@ +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 getPlte(): array + { + return $this->plte; + } + + public static function createFromArray(array $data): self + { + $object = new self(); + $object->width = $data['width'] ?? null; + $object->compression = $data['compression'] ?? null; + $object->height = $data['height'] ?? null; + $object->bitDepth = $data['bitDepth'] ?? null; + $object->colorType = $data['colorType'] ?? null; + $object->compression = $data['compression'] ?? null; + $object->filter = $data['filter'] ?? null; + $object->interlace = $data['interlace'] ?? null; + if (isset($data['plte'])) { + $plte = $data['plte']; + Assertion::isArray($plte, 'Invalid "plte" parameter'); + foreach ($plte as $item) { + $object->plte[] = RgbPaletteEntry::createFromArray($item); + } + } + + return $object; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/DistantSingleMetadata.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/DistantSingleMetadata.php new file mode 100644 index 00000000..529674a4 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/DistantSingleMetadata.php @@ -0,0 +1,60 @@ +uri = $uri; + $this->isBare64Encoded = $isBare64Encoded; + $this->httpClient = $httpClient; + $this->requestFactory = $requestFactory; + $this->additionalHeaders = $additionalHeaders; + } + + public function getMetadataStatement(): MetadataStatement + { + return MetadataStatementFetcher::fetchMetadataStatement($this->uri, $this->isBare64Encoded, $this->httpClient, $this->requestFactory, $this->additionalHeaders); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/DistantSingleMetadataFactory.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/DistantSingleMetadataFactory.php new file mode 100644 index 00000000..0120ce85 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/DistantSingleMetadataFactory.php @@ -0,0 +1,43 @@ +httpClient = $httpClient; + $this->requestFactory = $requestFactory; + } + + public function create(string $uri, bool $isBare64Encoded, array $additionalHeaders = [], ?ClientInterface $client = null): DistantSingleMetadata + { + $client = $client ?? $this->httpClient; + + return new DistantSingleMetadata($uri, $isBare64Encoded, $client, $this->requestFactory, $additionalHeaders); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/EcdaaTrustAnchor.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/EcdaaTrustAnchor.php new file mode 100644 index 00000000..891b766d --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/EcdaaTrustAnchor.php @@ -0,0 +1,90 @@ +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; + } + + public static function createFromArray(array $data): self + { + $object = new self(); + $object->X = $data['X'] ?? null; + $object->Y = $data['Y'] ?? null; + $object->c = $c['data'] ?? null; + $object->sx = $data['sx'] ?? null; + $object->sy = $data['sy'] ?? null; + $object->G1Curve = $data['G1Curve'] ?? null; + + return $object; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/ExtensionDescriptor.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/ExtensionDescriptor.php new file mode 100644 index 00000000..6d02f3f9 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/ExtensionDescriptor.php @@ -0,0 +1,68 @@ +id; + } + + public function getTag(): ?int + { + return $this->tag; + } + + public function getData(): ?string + { + return $this->data; + } + + public function isFailIfUnknown(): bool + { + return $this->fail_if_unknown; + } + + public static function createFromArray(array $data): self + { + $object = new self(); + $object->id = $data['id'] ?? null; + $object->tag = $data['tag'] ?? null; + $object->data = $data['data'] ?? null; + $object->fail_if_unknown = $data['fail_if_unknown'] ?? null; + + return $object; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataService.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataService.php new file mode 100644 index 00000000..ce38ebb0 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataService.php @@ -0,0 +1,84 @@ +serviceUri = $serviceUri; + $this->httpClient = $httpClient; + $this->requestFactory = $requestFactory; + $this->additionalQueryStringValues = $additionalQueryStringValues; + $this->additionalHeaders = $additionalHeaders; + } + + public function getMetadataStatementFor(MetadataTOCPayloadEntry $entry): MetadataStatement + { + $uri = $this->buildUri($entry->getUrl()); + + return MetadataStatementFetcher::fetchMetadataStatement($uri, true, $this->httpClient, $this->requestFactory, $this->additionalHeaders); + } + + public function getMetadataTOCPayload(): MetadataTOCPayload + { + $uri = $this->buildUri($this->serviceUri); + + return MetadataStatementFetcher::fetchTableOfContent($uri, $this->httpClient, $this->requestFactory, $this->additionalHeaders); + } + + private function buildUri(string $uri): string + { + $parsedUri = parse($uri); + $queryString = $parsedUri['query']; + $query = parse_query($queryString ?? ''); + foreach ($this->additionalQueryStringValues as $k => $v) { + $query[$k] = $v; + } + $parsedUri['query'] = build_query($query); + + return build($parsedUri); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataServiceFactory.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataServiceFactory.php new file mode 100644 index 00000000..aa6efa0b --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataServiceFactory.php @@ -0,0 +1,43 @@ +httpClient = $httpClient; + $this->requestFactory = $requestFactory; + } + + public function create(string $serviceUri, array $additionalQueryStringValues = [], array $additionalHeaders = [], ?ClientInterface $client = null): MetadataService + { + $client = $client ?? $this->httpClient; + + return new MetadataService($serviceUri, $client, $this->requestFactory, $additionalQueryStringValues, $additionalHeaders); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataStatement.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataStatement.php new file mode 100644 index 00000000..421ae686 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataStatement.php @@ -0,0 +1,489 @@ +legalHeader; + } + + 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 getDescription(): string + { + return $this->description; + } + + /** + * @return string[] + */ + public function getAlternativeDescriptions(): array + { + 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 getAssertionScheme(): ?string + { + return $this->assertionScheme; + } + + public function getAuthenticationAlgorithm(): ?int + { + return $this->authenticationAlgorithm; + } + + /** + * @return int[] + */ + public function getAuthenticationAlgorithms(): array + { + return $this->authenticationAlgorithms; + } + + public function getPublicKeyAlgAndEncoding(): ?int + { + return $this->publicKeyAlgAndEncoding; + } + + /** + * @return int[] + */ + public function getPublicKeyAlgAndEncodings(): array + { + return $this->publicKeyAlgAndEncodings; + } + + /** + * @return int[] + */ + public function getAttestationTypes(): array + { + return $this->attestationTypes; + } + + /** + * @return VerificationMethodANDCombinations[] + */ + public function getUserVerificationDetails(): array + { + return $this->userVerificationDetails; + } + + public function getKeyProtection(): int + { + return $this->keyProtection; + } + + public function isKeyRestricted(): ?bool + { + return (bool) $this->isKeyRestricted; + } + + public function isFreshUserVerificationRequired(): ?bool + { + return (bool) $this->isFreshUserVerificationRequired; + } + + public function getMatcherProtection(): int + { + return $this->matcherProtection; + } + + public function getCryptoStrength(): ?int + { + return $this->cryptoStrength; + } + + public function getOperatingEnv(): ?string + { + return $this->operatingEnv; + } + + public function getAttachmentHint(): int + { + return $this->attachmentHint; + } + + public function isSecondFactorOnly(): ?bool + { + return (bool) $this->isSecondFactorOnly; + } + + public function getTcDisplay(): int + { + 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; + } + + public static function createFromArray(array $data): self + { + $object = new self(); + foreach (['description', 'protocolFamily'] as $key) { + if (!isset($data[$key])) { + throw new InvalidArgumentException(sprintf('The parameter "%s" is missing', $key)); + } + } + $object->legalHeader = $data['legalHeader'] ?? null; + $object->aaid = $data['aaid'] ?? null; + $object->aaguid = $data['aaguid'] ?? null; + $object->attestationCertificateKeyIdentifiers = $data['attestationCertificateKeyIdentifiers'] ?? []; + $object->description = $data['description']; + $object->alternativeDescriptions = $data['alternativeDescriptions'] ?? []; + $object->authenticatorVersion = $data['authenticatorVersion'] ?? 0; + $object->protocolFamily = $data['protocolFamily']; + if (isset($data['upv'])) { + $upv = $data['upv']; + Assertion::isArray($upv, 'Invalid Metadata Statement'); + foreach ($upv as $value) { + Assertion::isArray($value, 'Invalid Metadata Statement'); + $object->upv[] = Version::createFromArray($value); + } + } + $object->assertionScheme = $data['assertionScheme'] ?? null; + $object->authenticationAlgorithm = $data['authenticationAlgorithm'] ?? null; + $object->authenticationAlgorithms = $data['authenticationAlgorithms'] ?? []; + $object->publicKeyAlgAndEncoding = $data['publicKeyAlgAndEncoding'] ?? null; + $object->publicKeyAlgAndEncodings = $data['publicKeyAlgAndEncodings'] ?? []; + $object->attestationTypes = $data['attestationTypes'] ?? []; + if (isset($data['userVerificationDetails'])) { + $userVerificationDetails = $data['userVerificationDetails']; + Assertion::isArray($userVerificationDetails, 'Invalid Metadata Statement'); + foreach ($userVerificationDetails as $value) { + Assertion::isArray($value, 'Invalid Metadata Statement'); + $object->userVerificationDetails[] = VerificationMethodANDCombinations::createFromArray($value); + } + } + $object->keyProtection = $data['keyProtection'] ?? 0; + $object->isKeyRestricted = $data['isKeyRestricted'] ?? null; + $object->isFreshUserVerificationRequired = $data['isFreshUserVerificationRequired'] ?? null; + $object->matcherProtection = $data['matcherProtection'] ?? 0; + $object->cryptoStrength = $data['cryptoStrength'] ?? null; + $object->operatingEnv = $data['operatingEnv'] ?? null; + $object->attachmentHint = $data['attachmentHint'] ?? 0; + $object->isSecondFactorOnly = $data['isSecondFactorOnly'] ?? null; + $object->tcDisplay = $data['tcDisplay'] ?? 0; + $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->attestationRootCertificates = $data['attestationRootCertificates'] ?? []; + $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; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataStatementFetcher.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataStatementFetcher.php new file mode 100644 index 00000000..7f6b7eb0 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataStatementFetcher.php @@ -0,0 +1,79 @@ +createRequest('GET', $uri); + foreach ($additionalHeaders as $k => $v) { + $request = $request->withHeader($k, $v); + } + $response = $client->sendRequest($request); + Assertion::eq(200, $response->getStatusCode(), sprintf('Unable to contact the server. Response code is %d', $response->getStatusCode())); + $content = $response->getBody()->getContents(); + Assertion::notEmpty($content, 'Unable to contact the server. The response has no content'); + + return $content; + } + + private static function getJwsPayload(string $token): 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']); + $algorithm = new ES256(); + $isValid = $algorithm->verify($key, $signature->getEncodedProtectedHeader().'.'.$jws->getEncodedPayload(), $signature->getSignature()); + Assertion::true($isValid, 'Invalid response from the metadata service. The token signature is invalid.'); + + return $jws->getPayload(); + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataStatementRepository.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataStatementRepository.php new file mode 100644 index 00000000..2743e184 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataStatementRepository.php @@ -0,0 +1,19 @@ +legalHeader; + } + + public function getNo(): int + { + return $this->no; + } + + public function getNextUpdate(): string + { + return $this->nextUpdate; + } + + /** + * @return MetadataTOCPayloadEntry[] + */ + public function getEntries(): array + { + return $this->entries; + } + + public static function createFromArray(array $data): self + { + $object = new self(); + $object->legalHeader = $data['legalHeader'] ?? null; + $object->nextUpdate = $data['nextUpdate'] ?? null; + $object->no = $data['no'] ?? null; + $object->entries = []; + if (isset($data['entries'])) { + foreach ($data['entries'] as $k => $entry) { + $object->entries[$k] = MetadataTOCPayloadEntry::createFromArray($entry); + } + } + + return $object; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataTOCPayloadEntry.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataTOCPayloadEntry.php new file mode 100644 index 00000000..a1320115 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/MetadataTOCPayloadEntry.php @@ -0,0 +1,145 @@ +aaid; + } + + public function getAaguid(): ?string + { + return $this->aaguid; + } + + public function getAttestationCertificateKeyIdentifiers(): array + { + return $this->attestationCertificateKeyIdentifiers; + } + + public function getHash(): ?string + { + return $this->hash; + } + + public function getUrl(): ?string + { + return $this->url; + } + + public function getBiometricStatusReports(): array + { + return $this->biometricStatusReports; + } + + /** + * @return StatusReport[] + */ + public function getStatusReports(): array + { + return $this->statusReports; + } + + public function getTimeOfLastStatusChange(): string + { + return $this->timeOfLastStatusChange; + } + + public function getRogueListURL(): string + { + return $this->rogueListURL; + } + + public function getRogueListHash(): string + { + return $this->rogueListHash; + } + + public static function createFromArray(array $data): self + { + $object = new self(); + $object->aaid = $data['aaid'] ?? null; + $object->aaguid = $data['aaguid'] ?? null; + $object->attestationCertificateKeyIdentifiers = $data['attestationCertificateKeyIdentifiers'] ?? null; + $object->hash = $data['hash'] ?? null; + $object->url = $data['url'] ?? null; + $object->biometricStatusReports = isset($data['biometricStatusReports']) ? BiometricStatusReport::createFromArray($data['biometricStatusReports']) : null; + $object->statusReports = []; + if (isset($data['statusReports'])) { + Assertion::isArray($data['statusReports'], 'Invalid status report'); + foreach ($data['statusReports'] as $k => $statusReport) { + $object->statusReports[$k] = StatusReport::createFromArray($statusReport); + } + } + $object->timeOfLastStatusChange = $data['timeOfLastStatusChange'] ?? null; + $object->rogueListURL = $data['rogueListURL'] ?? null; + $object->rogueListHash = $data['rogueListHash'] ?? null; + + return $object; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/PatternAccuracyDescriptor.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/PatternAccuracyDescriptor.php new file mode 100644 index 00000000..75352e1f --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/PatternAccuracyDescriptor.php @@ -0,0 +1,57 @@ +minComplexity; + } + + public function getMaxRetries(): ?int + { + return $this->maxRetries; + } + + public function getBlockSlowdown(): ?int + { + return $this->blockSlowdown; + } + + public static function createFromArray(array $data): self + { + $object = new self(); + $object->minComplexity = $data['minComplexity'] ?? null; + $object->maxRetries = $data['maxRetries'] ?? null; + $object->blockSlowdown = $data['blockSlowdown'] ?? null; + + return $object; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/RgbPaletteEntry.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/RgbPaletteEntry.php new file mode 100644 index 00000000..49f9fa20 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/RgbPaletteEntry.php @@ -0,0 +1,57 @@ +r; + } + + public function getG(): int + { + return $this->g; + } + + public function getB(): int + { + return $this->b; + } + + public static function createFromArray(array $data): self + { + $object = new self(); + $object->r = $data['r'] ?? null; + $object->g = $data['g'] ?? null; + $object->b = $data['b'] ?? null; + + return $object; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/RogueListEntry.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/RogueListEntry.php new file mode 100644 index 00000000..fc5fa5a5 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/RogueListEntry.php @@ -0,0 +1,45 @@ +sk; + } + + public function getDate(): string + { + return $this->date; + } + + public static function createFromArray(array $data): self + { + $object = new self(); + $object->sk = $data['sk'] ?? null; + $object->date = $data['date'] ?? null; + + return $object; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/SimpleMetadataStatementRepository.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/SimpleMetadataStatementRepository.php new file mode 100644 index 00000000..621a9d47 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/SimpleMetadataStatementRepository.php @@ -0,0 +1,138 @@ +cacheItemPool = $cacheItemPool; + } + + public function addService(string $name, MetadataService $service): void + { + $this->services[$name] = $service; + } + + public function addSingleStatement(string $name, SingleMetadata $singleStatements): void + { + $this->singleStatements[$name] = $singleStatements; + } + + public function findOneByAAGUID(string $aaguid): ?MetadataStatement + { + $metadataStatement = $this->findOneByAAGUIDFromServices($aaguid); + if (null !== $metadataStatement) { + return $metadataStatement; + } + + return $this->findOneByAAGUIDFromSingleStatements($aaguid); + } + + private function findOneByAAGUIDFromSingleStatements(string $aaguid): ?MetadataStatement + { + foreach ($this->singleStatements as $name => $singleStatement) { + try { + $singleCacheItem = $this->cacheItemPool->getItem(sprintf('MDS-%s', $name)); + if (!$singleCacheItem->isHit()) { + $metadataStatement = $singleStatement->getMetadataStatement(); + $singleCacheItem->set($metadataStatement); + $this->cacheItemPool->save($singleCacheItem); + } else { + $metadataStatement = $singleCacheItem->get(); + } + + if ($metadataStatement->getAaguid() === $aaguid) { + return $metadataStatement; + } + } catch (Throwable $throwable) { + continue; + } + } + + return null; + } + + private function findOneByAAGUIDFromServices(string $aaguid): ?MetadataStatement + { + foreach ($this->services as $name => $service) { + try { + $tocCacheItem = $this->cacheItemPool->getItem(sprintf('TOC-%s', $name)); + if (!$tocCacheItem->isHit()) { + $tableOfContent = $service->getMetadataTOCPayload(); + $tocCacheItem->set($tableOfContent); + $this->cacheItemPool->save($tocCacheItem); + $needCacheUpdate = true; + } else { + $tableOfContent = $tocCacheItem->get(); + $nextUpdate = DateTimeImmutable::createFromFormat('Y-m-d', $tableOfContent->getNextUpdate()); + if (false === $nextUpdate) { + $needCacheUpdate = true; + } else { + $needCacheUpdate = $nextUpdate->getTimestamp() < time(); + if ($needCacheUpdate) { + $tableOfContent = $service->getMetadataTOCPayload(); + $tocCacheItem->set($tableOfContent); + $this->cacheItemPool->save($tocCacheItem); + } + } + } + } catch (Throwable $throwable) { + continue; + } + foreach ($tableOfContent->getEntries() as $entry) { + $url = $entry->getUrl(); + if (null === $url) { + continue; + } + try { + $mdsCacheItem = $this->cacheItemPool->getItem(sprintf('MDS-%s', urlencode($url))); + if ($mdsCacheItem->isHit() && !$needCacheUpdate) { + $metadataStatement = $mdsCacheItem->get(); + } else { + $metadataStatement = $service->getMetadataStatementFor($entry); + $mdsCacheItem->set($metadataStatement); + $this->cacheItemPool->save($mdsCacheItem); + } + if ($metadataStatement->getAaguid() === $aaguid) { + return $metadataStatement; + } + } catch (Throwable $throwable) { + continue; + } + } + } + + return null; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/SingleMetadata.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/SingleMetadata.php new file mode 100644 index 00000000..86c35ef9 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/SingleMetadata.php @@ -0,0 +1,54 @@ +data = $data; + $this->isBare64Encoded = $isBare64Encoded; + } + + public function getMetadataStatement(): MetadataStatement + { + if (null === $this->statement) { + $json = $this->data; + if ($this->isBare64Encoded) { + $json = base64_decode($this->data, true); + Assertion::string($json, 'Unable to decode the data'); + } + $statement = json_decode($json, true); + Assertion::eq(JSON_ERROR_NONE, json_last_error(), 'Unable to decode the data'); + $this->statement = MetadataStatement::createFromArray($statement); + } + + return $this->statement; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/StatusReport.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/StatusReport.php new file mode 100644 index 00000000..29a82048 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/StatusReport.php @@ -0,0 +1,114 @@ +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; + } + + public static function createFromArray(array $data): self + { + $object = new self(); + $object->status = $data['status'] ?? null; + $object->effectiveDate = $data['effectiveDate'] ?? null; + $object->certificate = $data['certificate'] ?? null; + $object->url = $data['url'] ?? null; + $object->certificationDescriptor = $data['certificationDescriptor'] ?? null; + $object->certificateNumber = $data['certificateNumber'] ?? null; + $object->certificationPolicyVersion = $data['certificationPolicyVersion'] ?? null; + $object->certificationRequirementsVersion = $data['certificationRequirementsVersion'] ?? null; + + return $object; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/VerificationMethodANDCombinations.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/VerificationMethodANDCombinations.php new file mode 100644 index 00000000..acba589a --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/VerificationMethodANDCombinations.php @@ -0,0 +1,44 @@ +verificationMethods; + } + + public static function createFromArray(array $data): self + { + $object = new self(); + + foreach ($data as $datum) { + Assertion::isArray($datum, 'Invalid verificationMethod and combinations'); + $object->verificationMethods[] = VerificationMethodDescriptor::createFromArray($datum); + } + + return $object; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/VerificationMethodDescriptor.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/VerificationMethodDescriptor.php new file mode 100644 index 00000000..c397a9ab --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/VerificationMethodDescriptor.php @@ -0,0 +1,80 @@ +userVerification; + } + + public function getCaDesc(): ?CodeAccuracyDescriptor + { + return $this->caDesc; + } + + public function getBaDesc(): ?BiometricAccuracyDescriptor + { + return $this->baDesc; + } + + public function getPaDesc(): ?PatternAccuracyDescriptor + { + return $this->paDesc; + } + + public static function createFromArray(array $data): self + { + $object = new self(); + $object->userVerification = $data['userVerification'] ?? null; + $object->caDesc = isset($data['caDesc']) ? CodeAccuracyDescriptor::createFromArray($data['caDesc']) : null; + $object->baDesc = isset($data['baDesc']) ? BiometricAccuracyDescriptor::createFromArray($data['baDesc']) : null; + $object->paDesc = isset($data['paDesc']) ? PatternAccuracyDescriptor::createFromArray($data['paDesc']) : null; + + return $object; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Version.php b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Version.php new file mode 100644 index 00000000..64bb4380 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/metadata-service/src/Version.php @@ -0,0 +1,46 @@ +major; + } + + public function getMinor(): int + { + return $this->minor; + } + + public static function createFromArray(array $data): self + { + $object = new self(); + $object->major = $data['major'] ?? null; + $object->minor = $data['minor'] ?? null; + + return $object; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/LICENSE b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/LICENSE new file mode 100644 index 00000000..25cfdd66 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 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/webauthn-lib/README.md b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/README.md new file mode 100644 index 00000000..c3ee5e8d --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/README.md @@ -0,0 +1,31 @@ +FIDO2/Webauthn Support for PHP +============================== + +**FIDO2/Webauthn Support for PHP** is a **PHP library** that will help you to support compatible security tokens and devices. + +# Installation + +Install the library with Composer: `composer require web-auth/webauthn-lib`. + +# Contribution + +This repository is a sub repository of [the Web Authentication Framework](https://github.com/web-auth/webauthn-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-auth/webauthn-framework) instead. + +# Documentation + +The official documentation is available at https://github.com/web-auth/webauthn-framework + +# Support + +I bring solutions to your problems and answer your questions. + +If you really love that project and the work I have done or if you want I prioritize your issues, then you can help me out for a couple of :beers: or more! + +[![Become a Patreon](https://c5.patreon.com/external/logo/become_a_patron_button.png)](https://www.patreon.com/FlorentMorselli) + +# Licence + +This project is release under [MIT licence](LICENSE). diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/composer.json b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/composer.json new file mode 100644 index 00000000..91b51164 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/composer.json @@ -0,0 +1,59 @@ +{ + "name": "web-auth/webauthn-lib", + "type": "library", + "license": "MIT", + "description": "FIDO2/Webauthn Support For PHP", + "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/webauthn-library/contributors" + } + ], + "require": { + "php": "^7.2", + "ext-json": "*", + "ext-openssl": "*", + "ext-mbstring": "*", + "nyholm/psr7": "^1.1", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "ramsey/uuid": "^3.8", + "spomky-labs/base64url": "^2.0", + "spomky-labs/cbor-php": "^1.0.2", + "beberlei/assert": "^3.0", + "web-auth/cose-lib": "self.version", + "web-auth/metadata-service": "self.version" + }, + "autoload": { + "psr-4": { + "Webauthn\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Webauthn\\Tests\\Functional\\": "tests/functional/", + "Webauthn\\Tests\\Unit\\": "tests/unit/" + } + }, + "suggest": { + "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" + }, + "extra": { + "branch-alias": { + "v1.0": "1.0.x-dev", + "v1.1": "1.1.x-dev", + "v1.2": "1.2.x-dev", + "v2.0": "2.0.x-dev", + "v2.1": "2.1.x-dev" + } + } +} 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 new file mode 100644 index 00000000..c66876f1 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AndroidKeyAttestationStatementSupport.php @@ -0,0 +1,161 @@ +decoder = $decoder ?? new Decoder(new TagObjectManager(), new OtherObjectManager()); + $this->metadataStatementRepository = $metadataStatementRepository; + } + + public function name(): string + { + return 'android-key'; + } + + public function load(array $attestation): AttestationStatement + { + Assertion::keyExists($attestation, 'attStmt', 'Invalid attestation object'); + foreach (['sig', 'x5c', 'alg'] as $key) { + Assertion::keyExists($attestation['attStmt'], $key, 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 at least one certificate.'); + Assertion::greaterThan(\count($certificates), 0, 'The attestation statement value "x5c" must be a list with at least one certificate.'); + Assertion::allString($certificates, 'The attestation statement value "x5c" must be a list with at least one certificate.'); + $certificates = CertificateToolbox::convertAllDERToPEM($certificates); + + return AttestationStatement::createBasic($attestation['fmt'], $attestation['attStmt'], new CertificateTrustPath($certificates)); + } + + public function isValid(string $clientDataJSONHash, AttestationStatement $attestationStatement, AuthenticatorData $authenticatorData): bool + { + $trustPath = $attestationStatement->getTrustPath(); + Assertion::isInstanceOf($trustPath, CertificateTrustPath::class, 'Invalid trust path'); + + $certificates = $trustPath->getCertificates(); + if (null !== $this->metadataStatementRepository) { + $certificates = CertificateToolbox::checkAttestationMedata( + $attestationStatement, + $authenticatorData->getAttestedCredentialData()->getAaguid()->toString(), + $certificates, + $this->metadataStatementRepository + ); + } + + //Decode leaf attestation certificate + $leaf = $certificates[0]; + $this->checkCertificateAndGetPublicKey($leaf, $clientDataJSONHash, $authenticatorData); + + $signedData = $authenticatorData->getAuthData().$clientDataJSONHash; + $alg = $attestationStatement->get('alg'); + + return 1 === openssl_verify($signedData, $attestationStatement->get('sig'), $leaf, Algorithms::getOpensslAlgorithmFor((int) $alg)); + } + + private function checkCertificateAndGetPublicKey(string $certificate, string $clientDataHash, AuthenticatorData $authenticatorData): void + { + $resource = openssl_pkey_get_public($certificate); + Assertion::isResource($resource, 'Unable to read the certificate'); + $details = openssl_pkey_get_details($resource); + Assertion::isArray($details, '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'); + $publicDataStream = new StringStream($publicKeyData); + $coseKey = $this->decoder->decode($publicDataStream)->getNormalizedData(false); + Assertion::true($publicDataStream->isEOF(), 'Invalid public key data. Presence of extra bytes.'); + $publicDataStream->close(); + $publicKey = Key::createFromData($coseKey); + + Assertion::true(($publicKey instanceof Ec2Key) || ($publicKey instanceof RsaKey), 'Unsupported key type'); + Assertion::eq($publicKey->asPEM(), $details['key'], '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::keyExists($certDetails, 'extensions', 'The certificate has no extension'); + Assertion::isArray($certDetails['extensions'], 'The certificate has no extension'); + Assertion::keyExists($certDetails['extensions'], '1.3.6.1.4.1.11129.2.1.17', '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(); + + //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, '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'); + + //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, '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, 'The certificate extension "1.3.6.1.4.1.11129.2.1.17" is invalid'); + $this->checkAbsenceOfAllApplicationsTag($teeEnforcedFlags); + } + + 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'); + } + } +} 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 new file mode 100644 index 00000000..bc0d5ee0 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AndroidSafetyNetAttestationStatementSupport.php @@ -0,0 +1,252 @@ +jwsSerializer = new CompactSerializer(); + $this->apiKey = $apiKey; + $this->client = $client; + $this->requestFactory = $requestFactory; + $this->initJwsVerifier(); + $this->leeway = $leeway; + $this->maxAge = $maxAge; + $this->metadataStatementRepository = $metadataStatementRepository; + } + + public function name(): string + { + return 'android-safetynet'; + } + + public function load(array $attestation): AttestationStatement + { + Assertion::keyExists($attestation, 'attStmt', 'Invalid attestation object'); + foreach (['ver', 'response'] as $key) { + Assertion::keyExists($attestation['attStmt'], $key, sprintf('The attestation statement value "%s" is missing.', $key)); + Assertion::notEmpty($attestation['attStmt'][$key], 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', 'The response in the attestation statement must contain a "x5c" header.'); + Assertion::notEmpty($jwsHeader['x5c'], '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( + $this->name(), + $attestation['attStmt'], + new CertificateTrustPath($certificates) + ); + } + + public function isValid(string $clientDataJSONHash, AttestationStatement $attestationStatement, AuthenticatorData $authenticatorData): bool + { + $trustPath = $attestationStatement->getTrustPath(); + Assertion::isInstanceOf($trustPath, CertificateTrustPath::class, 'Invalid trust path'); + $certificates = $trustPath->getCertificates(); + if (null !== $this->metadataStatementRepository) { + $certificates = CertificateToolbox::checkAttestationMedata( + $attestationStatement, + $authenticatorData->getAttestedCredentialData()->getAaguid()->toString(), + $certificates, + $this->metadataStatementRepository + ); + } + + $parsedCertificate = openssl_x509_parse(current($certificates)); + 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'); + + /** @var JWS $jws */ + $jws = $attestationStatement->get('jws'); + $payload = $jws->getPayload(); + $this->validatePayload($payload, $clientDataJSONHash, $authenticatorData); + + //Check the signature + $this->validateSignature($jws, $trustPath); + + //Check against Google service + $this->validateUsingGoogleApi($attestationStatement); + + return true; + } + + private function validatePayload(?string $payload, 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'); + 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, sprintf('Invalid attestation object. Issued in the future. Current time: %d. Response time: %d', $currentTime, $payload['timestampMs'])); + Assertion::lessOrEqualThan($currentTime - $payload['timestampMs'], $this->maxAge, sprintf('Invalid attestation object. Too old. Current time: %d. Response time: %d', $currentTime, $payload['timestampMs'])); + } + + private function validateSignature(JWS $jws, CertificateTrustPath $trustPath): void + { + $jwk = JWKFactory::createFromCertificate($trustPath->getCertificates()[0]); + $isValid = $this->jwsVerifier->verifyWithKey($jws, $jwk, 0); + Assertion::true($isValid, 'Invalid response signature'); + } + + private function validateUsingGoogleApi(AttestationStatement $attestationStatement): void + { + if (null === $this->client || null === $this->apiKey || null === $this->requestFactory) { + return; + } + $uri = sprintf('https://www.googleapis.com/androidcheck/v1/attestations/verify?key=%s', 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); + Assertion::eq(JSON_ERROR_NONE, json_last_error(), 'Invalid response.'); + Assertion::keyExists($responseBodyJson, 'isValidSignature', 'Invalid response.'); + Assertion::boolean($responseBodyJson['isValidSignature'], 'Invalid response.'); + Assertion::true($responseBodyJson['isValidSignature'], 'Invalid response.'); + } + + private function getResponseBody(ResponseInterface $response): string + { + $responseBody = ''; + $response->getBody()->rewind(); + do { + $tmp = $response->getBody()->read(1024); + if ('' === $tmp) { + break; + } + $responseBody .= $tmp; + } while (true); + + 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 (0 === mb_strpos($header, 'application/json')) { + return; + } + } + + throw new InvalidArgumentException('Unrecognized response'); + } + + private function convertCertificatesToPem(array $certificates): array + { + foreach ($certificates as $k => $v) { + $certificates[$k] = CertificateToolbox::fixPEMStructure($v); + } + + return $certificates; + } + + private function initJwsVerifier(): void + { + $algorithmClasses = [ + 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, + ]; + $algorithms = []; + foreach ($algorithmClasses as $key => $algorithm) { + if (class_exists($algorithm)) { + $algorithms[] = new $algorithm(); + } + } + $algorithmManager = new AlgorithmManager($algorithms); + $this->jwsVerifier = new JWSVerifier($algorithmManager); + } +} 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 new file mode 100644 index 00000000..5d8d5464 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationObject.php @@ -0,0 +1,54 @@ +rawAttestationObject = $rawAttestationObject; + $this->attStmt = $attStmt; + $this->authData = $authData; + } + + public function getRawAttestationObject(): string + { + return $this->rawAttestationObject; + } + + public function getAttStmt(): AttestationStatement + { + return $this->attStmt; + } + + public function getAuthData(): AuthenticatorData + { + return $this->authData; + } +} 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 new file mode 100644 index 00000000..c9d4c939 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationObjectLoader.php @@ -0,0 +1,98 @@ +decoder = $decoder ?? new Decoder(new TagObjectManager(), new OtherObjectManager()); + $this->attestationStatementSupportManager = $attestationStatementSupportManager; + } + + public function load(string $data): AttestationObject + { + $decodedData = Base64Url::decode($data); + $stream = new StringStream($decodedData); + $parsed = $this->decoder->decode($stream); + $attestationObject = $parsed->getNormalizedData(); + Assertion::true($stream->isEOF(), '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']; + + $attestationStatementSupport = $this->attestationStatementSupportManager->get($attestationObject['fmt']); + $attestationStatement = $attestationStatementSupport->load($attestationObject); + + $authDataStream = new StringStream($authData); + $rp_id_hash = $authDataStream->read(32); + $flags = $authDataStream->read(1); + $signCount = $authDataStream->read(4); + $signCount = unpack('N', $signCount)[1]; + + $attestedCredentialData = null; + if (0 !== (\ord($flags) & self::FLAG_AT)) { + $aaguid = Uuid::fromBytes($authDataStream->read(16)); + $credentialLength = $authDataStream->read(2); + $credentialLength = unpack('n', $credentialLength)[1]; + $credentialId = $authDataStream->read($credentialLength); + $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, $attestedCredentialData, $extension); + + return new AttestationObject($data, $attestationStatement, $authenticatorData); + } +} 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 new file mode 100644 index 00000000..3d3e24a4 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationStatement.php @@ -0,0 +1,140 @@ +fmt = $fmt; + $this->attStmt = $attStmt; + $this->type = $type; + $this->trustPath = $trustPath; + } + + public static function createNone(string $fmt, array $attStmt, TrustPath $trustPath): self + { + return new self($fmt, $attStmt, self::TYPE_NONE, $trustPath); + } + + public static function createBasic(string $fmt, array $attStmt, TrustPath $trustPath): self + { + return new self($fmt, $attStmt, self::TYPE_BASIC, $trustPath); + } + + public static function createSelf(string $fmt, array $attStmt, TrustPath $trustPath): self + { + return new self($fmt, $attStmt, self::TYPE_SELF, $trustPath); + } + + public static function createAttCA(string $fmt, array $attStmt, TrustPath $trustPath): self + { + return new self($fmt, $attStmt, self::TYPE_ATTCA, $trustPath); + } + + public static function createEcdaa(string $fmt, array $attStmt, TrustPath $trustPath): self + { + return new self($fmt, $attStmt, self::TYPE_ECDAA, $trustPath); + } + + public function getFmt(): string + { + return $this->fmt; + } + + public function getAttStmt(): array + { + return $this->attStmt; + } + + public function has(string $key): bool + { + return \array_key_exists($key, $this->attStmt); + } + + /** + * @return mixed + */ + public function get(string $key) + { + Assertion::true($this->has($key), sprintf('The attestation statement has no key "%s".', $key)); + + return $this->attStmt[$key]; + } + + public function getTrustPath(): TrustPath + { + return $this->trustPath; + } + + public function getType(): string + { + return $this->type; + } + + 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)); + } + + return new self( + $data['fmt'], + $data['attStmt'], + $data['type'], + TrustPathLoader::loadTrustPath($data['trustPath']) + ); + } + + public function jsonSerialize(): array + { + return [ + 'fmt' => $this->fmt, + 'attStmt' => $this->attStmt, + 'trustPath' => $this->trustPath, + 'type' => $this->type, + ]; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationStatementSupport.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationStatementSupport.php new file mode 100644 index 00000000..7826aab5 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/AttestationStatementSupport.php @@ -0,0 +1,25 @@ +attestationStatementSupports[$attestationStatementSupport->name()] = $attestationStatementSupport; + } + + public function has(string $name): bool + { + return \array_key_exists($name, $this->attestationStatementSupports); + } + + public function get(string $name): AttestationStatementSupport + { + Assertion::true($this->has($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 new file mode 100644 index 00000000..cd27b330 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/FidoU2FAttestationStatementSupport.php @@ -0,0 +1,134 @@ +decoder = $decoder ?? new Decoder(new TagObjectManager(), new OtherObjectManager()); + $this->metadataStatementRepository = $metadataStatementRepository; + } + + public function name(): string + { + return 'fido-u2f'; + } + + public function load(array $attestation): AttestationStatement + { + Assertion::keyExists($attestation, 'attStmt', 'Invalid attestation object'); + foreach (['sig', 'x5c'] as $key) { + Assertion::keyExists($attestation['attStmt'], $key, 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, 'The attestation statement value "x5c" must be a list with one certificate.'); + Assertion::allString($certificates, 'The attestation statement value "x5c" must be a list with one certificate.'); + + reset($certificates); + $certificates = CertificateToolbox::convertAllDERToPEM($certificates); + $this->checkCertificate($certificates[0]); + + return AttestationStatement::createBasic($attestation['fmt'], $attestation['attStmt'], new CertificateTrustPath($certificates)); + } + + public function isValid(string $clientDataJSONHash, 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"' + ); + if (null !== $this->metadataStatementRepository) { + CertificateToolbox::checkAttestationMedata( + $attestationStatement, + $authenticatorData->getAttestedCredentialData()->getAaguid()->toString(), + [], + $this->metadataStatementRepository + ); + } + $trustPath = $attestationStatement->getTrustPath(); + Assertion::isInstanceOf($trustPath, CertificateTrustPath::class, 'Invalid trust path'); + $dataToVerify = "\0"; + $dataToVerify .= $authenticatorData->getRpIdHash(); + $dataToVerify .= $clientDataJSONHash; + $dataToVerify .= $authenticatorData->getAttestedCredentialData()->getCredentialId(); + $dataToVerify .= $this->extractPublicKey($authenticatorData->getAttestedCredentialData()->getCredentialPublicKey()); + + return 1 === openssl_verify($dataToVerify, $attestationStatement->get('sig'), $trustPath->getCertificates()[0], OPENSSL_ALGO_SHA256); + } + + private function extractPublicKey(?string $publicKey): string + { + Assertion::notNull($publicKey, '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->close(); + Assertion::isInstanceOf($coseKey, MapObject::class, 'The attested credential data does not contain a valid public key.'); + + $coseKey = $coseKey->getNormalizedData(); + $ec2Key = new Ec2Key($coseKey + [Ec2Key::TYPE => 2, Ec2Key::DATA_CURVE => Ec2Key::CURVE_P256]); + + return "\x04".$ec2Key->x().$ec2Key->y(); + } + + private function checkCertificate(string $publicKey): void + { + try { + $resource = openssl_pkey_get_public($publicKey); + Assertion::isResource($resource, 'Unable to load the public key'); + } catch (Throwable $throwable) { + throw new InvalidArgumentException('Invalid certificate or certificate chain', 0, $throwable); + } + $details = openssl_pkey_get_details($resource); + 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'); + } +} 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 new file mode 100644 index 00000000..09287992 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/NoneAttestationStatementSupport.php @@ -0,0 +1,38 @@ +getAttStmt()); + } +} 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 new file mode 100644 index 00000000..4d4a01aa --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/PackedAttestationStatementSupport.php @@ -0,0 +1,204 @@ +decoder = $decoder ?? new Decoder(new TagObjectManager(), new OtherObjectManager()); + $this->algorithmManager = $algorithmManager; + $this->metadataStatementRepository = $metadataStatementRepository; + } + + public function name(): string + { + return 'packed'; + } + + 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.'); + switch (true) { + case \array_key_exists('x5c', $attestation['attStmt']): + return $this->loadBasicType($attestation); + case \array_key_exists('ecdaaKeyId', $attestation['attStmt']): + return $this->loadEcdaaType($attestation['attStmt']); + default: + return $this->loadEmptyType($attestation); + } + } + + public function isValid(string $clientDataJSONHash, AttestationStatement $attestationStatement, AuthenticatorData $authenticatorData): bool + { + $trustPath = $attestationStatement->getTrustPath(); + switch (true) { + case $trustPath instanceof CertificateTrustPath: + return $this->processWithCertificate($clientDataJSONHash, $attestationStatement, $authenticatorData, $trustPath); + case $trustPath instanceof EcdaaKeyIdTrustPath: + return $this->processWithECDAA(); + case $trustPath instanceof EmptyTrustPath: + return $this->processWithSelfAttestation($clientDataJSONHash, $attestationStatement, $authenticatorData); + default: + throw new InvalidArgumentException('Unsupported attestation statement'); + } + } + + private function loadBasicType(array $attestation): AttestationStatement + { + $certificates = $attestation['attStmt']['x5c']; + Assertion::isArray($certificates, 'The attestation statement value "x5c" must be a list with at least one certificate.'); + Assertion::minCount($certificates, 1, 'The attestation statement value "x5c" must be a list with at least one certificate.'); + $certificates = CertificateToolbox::convertAllDERToPEM($certificates); + + return AttestationStatement::createBasic($attestation['fmt'], $attestation['attStmt'], new CertificateTrustPath($certificates)); + } + + private function loadEcdaaType(array $attestation): AttestationStatement + { + $ecdaaKeyId = $attestation['attStmt']['ecdaaKeyId']; + Assertion::string($ecdaaKeyId, 'The attestation statement value "ecdaaKeyId" is invalid.'); + + return AttestationStatement::createEcdaa($attestation['fmt'], $attestation['attStmt'], new EcdaaKeyIdTrustPath($attestation['ecdaaKeyId'])); + } + + private function loadEmptyType(array $attestation): AttestationStatement + { + return AttestationStatement::createSelf($attestation['fmt'], $attestation['attStmt'], new EmptyTrustPath()); + } + + private function checkCertificate(string $attestnCert, AuthenticatorData $authenticatorData): void + { + $parsed = openssl_x509_parse($attestnCert); + Assertion::isArray($parsed, 'Invalid certificate'); + + //Check version + Assertion::false(!isset($parsed['version']) || 2 !== $parsed['version'], 'Invalid certificate version'); + + //Check subject field + Assertion::false(!isset($parsed['name']) || false === mb_strpos($parsed['name'], '/OU=Authenticator Attestation'), 'Invalid certificate name. The Subject Organization Unit must be "Authenticator Attestation"'); + + //Check extensions + Assertion::false(!isset($parsed['extensions']) || !\is_array($parsed['extensions']), 'Certificate extensions are missing'); + + //Check certificate is not a CA cert + Assertion::false(!isset($parsed['extensions']['basicConstraints']) || 'CA:FALSE' !== $parsed['extensions']['basicConstraints'], 'The Basic Constraints extension must have the CA component set to false'); + + $attestedCredentialData = $authenticatorData->getAttestedCredentialData(); + Assertion::notNull($attestedCredentialData, '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()->getBytes(), $parsed['extensions']['1.3.6.1.4.1.45724.1.1.4']), 'The value of the "aaguid" does not match with the certificate'); + } + + private function processWithCertificate(string $clientDataJSONHash, AttestationStatement $attestationStatement, AuthenticatorData $authenticatorData, CertificateTrustPath $trustPath): bool + { + $certificates = $trustPath->getCertificates(); + + if (null !== $this->metadataStatementRepository) { + $certificates = CertificateToolbox::checkAttestationMedata( + $attestationStatement, + $authenticatorData->getAttestedCredentialData()->getAaguid()->toString(), + $certificates, + $this->metadataStatementRepository + ); + } + + // Check leaf certificate + $this->checkCertificate($certificates[0], $authenticatorData); + + // Get the COSE algorithm identifier and the corresponding OpenSSL one + $coseAlgorithmIdentifier = (int) $attestationStatement->get('alg'); + $opensslAlgorithmIdentifier = Algorithms::getOpensslAlgorithmFor($coseAlgorithmIdentifier); + + // Verification of the signature + $signedData = $authenticatorData->getAuthData().$clientDataJSONHash; + $result = openssl_verify($signedData, $attestationStatement->get('sig'), $certificates[0], $opensslAlgorithmIdentifier); + + return 1 === $result; + } + + private function processWithECDAA(): bool + { + throw new RuntimeException('ECDAA not supported'); + } + + private function processWithSelfAttestation(string $clientDataJSONHash, 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'); + $publicKeyStream = new StringStream($credentialPublicKey); + $publicKey = $this->decoder->decode($publicKeyStream); + Assertion::true($publicKeyStream->isEOF(), 'Invalid public key. Presence of extra bytes.'); + $publicKeyStream->close(); + Assertion::isInstanceOf($publicKey, MapObject::class, 'The attested credential data does not contain a valid public key.'); + $publicKey = $publicKey->getNormalizedData(false); + $publicKey = new Key($publicKey); + Assertion::eq($publicKey->alg(), (int) $attestationStatement->get('alg'), 'The algorithm of the attestation statement and the key are not identical.'); + + $dataToVerify = $authenticatorData->getAuthData().$clientDataJSONHash; + $algorithm = $this->algorithmManager->get((int) $attestationStatement->get('alg')); + if (!$algorithm instanceof Signature) { + throw new RuntimeException('Invalid algorithm'); + } + $signature = CoseSignatureFixer::fix($attestationStatement->get('sig'), $algorithm); + + return $algorithm->verify($dataToVerify, $publicKey, $signature); + } +} 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 new file mode 100644 index 00000000..38605185 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestationStatement/TPMAttestationStatementSupport.php @@ -0,0 +1,325 @@ +metadataStatementRepository = $metadataStatementRepository; + } + + public function load(array $attestation): AttestationStatement + { + Assertion::keyExists($attestation, 'attStmt', 'Invalid attestation object'); + Assertion::keyNotExists($attestation['attStmt'], 'ecdaaKeyId', 'ECDAA not supported'); + foreach (['ver', 'ver', 'sig', 'alg', 'certInfo', 'pubArea'] as $key) { + Assertion::keyExists($attestation['attStmt'], $key, sprintf('The attestation statement value "%s" is missing.', $key)); + } + Assertion::eq('2.0', $attestation['attStmt']['ver'], 'Invalid attestation object'); + + $certInfo = $this->checkCertInfo($attestation['attStmt']['certInfo']); + Assertion::eq('8017', bin2hex($certInfo['type']), 'Invalid attestation object'); + + $pubArea = $this->checkPubArea($attestation['attStmt']['pubArea']); + $pubAreaAttestedNameAlg = mb_substr($certInfo['attestedName'], 0, 2, '8bit'); + $pubAreaHash = hash($this->getTPMHash($pubAreaAttestedNameAlg), $attestation['attStmt']['pubArea'], true); + $attestedName = $pubAreaAttestedNameAlg.$pubAreaHash; + Assertion::eq($attestedName, $certInfo['attestedName'], 'Invalid attested name'); + + $attestation['attStmt']['parsedCertInfo'] = $certInfo; + $attestation['attStmt']['parsedPubArea'] = $pubArea; + + $certificates = CertificateToolbox::convertAllDERToPEM($attestation['attStmt']['x5c']); + Assertion::minCount($certificates, 1, 'The attestation statement value "x5c" must be a list with at least one certificate.'); + + return AttestationStatement::createAttCA( + $this->name(), + $attestation['attStmt'], + new CertificateTrustPath($certificates) + ); + } + + public function isValid(string $clientDataJSONHash, AttestationStatement $attestationStatement, AuthenticatorData $authenticatorData): bool + { + $attToBeSigned = $authenticatorData->getAuthData().$clientDataJSONHash; + $attToBeSignedHash = hash(Algorithms::getHashAlgorithmFor((int) $attestationStatement->get('alg')), $attToBeSigned, true); + Assertion::eq($attestationStatement->get('parsedCertInfo')['extraData'], $attToBeSignedHash, 'Invalid attestation hash'); + $this->checkUniquePublicKey( + $attestationStatement->get('parsedPubArea')['unique'], + $authenticatorData->getAttestedCredentialData()->getCredentialPublicKey() + ); + + switch (true) { + case $attestationStatement->getTrustPath() instanceof CertificateTrustPath: + return $this->processWithCertificate($clientDataJSONHash, $attestationStatement, $authenticatorData); + case $attestationStatement->getTrustPath() instanceof EcdaaKeyIdTrustPath: + return $this->processWithECDAA(); + default: + throw new InvalidArgumentException('Unsupported attestation statement'); + } + } + + private function checkUniquePublicKey(string $unique, string $cborPublicKey): void + { + $cborDecoder = new Decoder(new TagObjectManager(), new OtherObjectManager()); + $publicKey = $cborDecoder->decode(new StringStream($cborPublicKey)); + Assertion::isInstanceOf($publicKey, MapObject::class, 'Invalid public key'); + $key = new Key($publicKey->getNormalizedData(false)); + + switch ($key->type()) { + case Key::TYPE_OKP: + $uniqueFromKey = (new OkpKey($key->getData()))->x(); + break; + case Key::TYPE_EC2: + $ec2Key = new Ec2Key($key->getData()); + $uniqueFromKey = "\x04".$ec2Key->x().$ec2Key->y(); + break; + case Key::TYPE_RSA: + $uniqueFromKey = (new RsaKey($key->getData()))->n(); + break; + default: + throw new InvalidArgumentException('Invalid or unsupported key type.'); + } + + Assertion::eq($unique, $uniqueFromKey, 'Invalid pubArea.unique value'); + } + + private function checkCertInfo(string $data): array + { + $certInfo = new StringStream($data); + + $magic = $certInfo->read(4); + Assertion::eq('ff544347', bin2hex($magic), 'Invalid attestation object'); + + $type = $certInfo->read(2); + + $qualifiedSignerLength = unpack('n', $certInfo->read(2))[1]; + $qualifiedSigner = $certInfo->read($qualifiedSignerLength); //Ignored + + $extraDataLength = unpack('n', $certInfo->read(2))[1]; + $extraData = $certInfo->read($extraDataLength); + + $clockInfo = $certInfo->read(17); //Ignore + + $firmwareVersion = $certInfo->read(8); + + $attestedNameLength = unpack('n', $certInfo->read(2))[1]; + $attestedName = $certInfo->read($attestedNameLength); + + $attestedQualifiedNameLength = unpack('n', $certInfo->read(2))[1]; + $attestedQualifiedName = $certInfo->read($attestedQualifiedNameLength); //Ignore + Assertion::true($certInfo->isEOF(), 'Invalid certificate information. Presence of extra bytes.'); + $certInfo->close(); + + return [ + 'magic' => $magic, + 'type' => $type, + 'qualifiedSigner' => $qualifiedSigner, + 'extraData' => $extraData, + 'clockInfo' => $clockInfo, + 'firmwareVersion' => $firmwareVersion, + 'attestedName' => $attestedName, + 'attestedQualifiedName' => $attestedQualifiedName, + ]; + } + + private function checkPubArea(string $data): array + { + $pubArea = new StringStream($data); + + $type = $pubArea->read(2); + + $nameAlg = $pubArea->read(2); + + $objectAttributes = $pubArea->read(4); + + $authPolicyLength = unpack('n', $pubArea->read(2))[1]; + $authPolicy = $pubArea->read($authPolicyLength); + + $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.'); + $pubArea->close(); + + return [ + 'type' => $type, + 'nameAlg' => $nameAlg, + 'objectAttributes' => $objectAttributes, + 'authPolicy' => $authPolicy, + 'parameters' => $parameters, + 'unique' => $unique, + ]; + } + + private function getParameters(string $type, StringStream $stream): array + { + switch (bin2hex($type)) { + case '0001': + case '0014': + case '0016': + return [ + 'symmetric' => $stream->read(2), + 'scheme' => $stream->read(2), + 'keyBits' => unpack('n', $stream->read(2))[1], + 'exponent' => $this->getExponent($stream->read(4)), + ]; + case '0018': + return [ + 'symmetric' => $stream->read(2), + 'scheme' => $stream->read(2), + 'curveId' => $stream->read(2), + 'kdf' => $stream->read(2), + ]; + default: + throw new InvalidArgumentException('Unsupported type'); + } + } + + private function getExponent(string $exponent): string + { + return '00000000' === bin2hex($exponent) ? Base64Url::decode('AQAB') : $exponent; + } + + private function convertCertificatesToPem(array $certificates): array + { + foreach ($certificates as $k => $v) { + $tmp = '-----BEGIN CERTIFICATE-----'.PHP_EOL; + $tmp .= chunk_split(base64_encode($v), 64, PHP_EOL); + $tmp .= '-----END CERTIFICATE-----'.PHP_EOL; + $certificates[$k] = $tmp; + } + + return $certificates; + } + + private function getTPMHash(string $nameAlg): string + { + switch (bin2hex($nameAlg)) { + case '0004': + return 'sha1'; //: "TPM_ALG_SHA1", + case '000b': + return 'sha256'; //: "TPM_ALG_SHA256", + case '000c': + return 'sha384'; //: "TPM_ALG_SHA384", + case '000d': + return 'sha512'; //: "TPM_ALG_SHA512", + default: + throw new InvalidArgumentException('Unsupported hash algorithm'); + } + } + + private function processWithCertificate(string $clientDataJSONHash, AttestationStatement $attestationStatement, AuthenticatorData $authenticatorData): bool + { + $trustPath = $attestationStatement->getTrustPath(); + Assertion::isInstanceOf($trustPath, CertificateTrustPath::class, 'Invalid trust path'); + + $certificates = $trustPath->getCertificates(); + if (null !== $this->metadataStatementRepository) { + $certificates = CertificateToolbox::checkAttestationMedata( + $attestationStatement, + $authenticatorData->getAttestedCredentialData()->getAaguid()->toString(), + $certificates, + $this->metadataStatementRepository + ); + } + + // Check certificate CA chain and returns the Attestation Certificate + $this->checkCertificate($certificates[0], $authenticatorData); + + // Get the COSE algorithm identifier and the corresponding OpenSSL one + $coseAlgorithmIdentifier = (int) $attestationStatement->get('alg'); + $opensslAlgorithmIdentifier = Algorithms::getOpensslAlgorithmFor($coseAlgorithmIdentifier); + + $result = openssl_verify($attestationStatement->get('certInfo'), $attestationStatement->get('sig'), $certificates[0], $opensslAlgorithmIdentifier); + + return 1 === $result; + } + + private function checkCertificate(string $attestnCert, AuthenticatorData $authenticatorData): void + { + $parsed = openssl_x509_parse($attestnCert); + Assertion::isArray($parsed, 'Invalid certificate'); + + //Check version + Assertion::false(!isset($parsed['version']) || 2 !== $parsed['version'], 'Invalid certificate version'); + + //Check subject field is empty + Assertion::false(!isset($parsed['subject']) || !\is_array($parsed['subject']) || 0 !== \count($parsed['subject']), '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.'); + $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'); + + //Check subjectAltName + Assertion::false(!isset($parsed['extensions']['subjectAltName']), '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'); + + // 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()->getBytes(), $parsed['extensions']['1.3.6.1.4.1.45724.1.1.4']), 'The value of the "aaguid" does not match with the certificate'); + + // TODO: For attestationRoot in metadata.attestationRootCertificates, generate verification chain verifX5C by appending attestationRoot to the x5c. Try verifying verifX5C. If successful go to next step. If fail try next attestationRoot. If no attestationRoots left to try, fail. + } + + private function processWithECDAA(): bool + { + throw new RuntimeException('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 new file mode 100644 index 00000000..0b6cb87f --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AttestedCredentialData.php @@ -0,0 +1,98 @@ +aaguid = $aaguid; + $this->credentialId = $credentialId; + $this->credentialPublicKey = $credentialPublicKey; + } + + public function getAaguid(): UuidInterface + { + return $this->aaguid; + } + + public function getCredentialId(): string + { + return $this->credentialId; + } + + public function getCredentialPublicKey(): ?string + { + return $this->credentialPublicKey; + } + + public static function createFromArray(array $json): self + { + Assertion::keyExists($json, 'aaguid', 'Invalid input. "aaguid" is missing.'); + Assertion::keyExists($json, 'credentialId', 'Invalid input. "credentialId" is missing.'); + switch (true) { + case 36 === mb_strlen($json['aaguid'], '8bit'): + $uuid = Uuid::fromString($json['aaguid']); + break; + default: // Kept for compatibility with old format + $decoded = base64_decode($json['aaguid'], true); + Assertion::string($decoded, 'Unable to decode the data'); + $uuid = Uuid::fromBytes($decoded); + } + $credentialId = base64_decode($json['credentialId'], true); + Assertion::string($credentialId, 'Unable to decode the data'); + + return new self( + $uuid, + $credentialId, + isset($json['credentialPublicKey']) ? base64_decode($json['credentialPublicKey'], true) : null + ); + } + + public function jsonSerialize(): array + { + $result = [ + 'aaguid' => $this->aaguid->toString(), + 'credentialId' => base64_encode($this->credentialId), + ]; + if (null !== $this->credentialPublicKey) { + $result['credentialPublicKey'] = base64_encode($this->credentialPublicKey); + } + + return $result; + } +} 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 new file mode 100644 index 00000000..a7bb376a --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtension.php @@ -0,0 +1,59 @@ +name = $name; + $this->value = $value; + } + + public function name(): string + { + return $this->name; + } + + /** + * @return mixed + */ + public function value() + { + return $this->value; + } + + /** + * @return mixed + */ + public function jsonSerialize() + { + return $this->value; + } +} 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 new file mode 100644 index 00000000..863f0806 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtensionsClientInputs.php @@ -0,0 +1,75 @@ +extensions[$extension->name()] = $extension; + } + + public static function createFromArray(array $json): self + { + $object = new self(); + foreach ($json as $k => $v) { + $object->add(new AuthenticationExtension($k, $v)); + } + + return $object; + } + + public function has(string $key): bool + { + return \array_key_exists($key, $this->extensions); + } + + /** + * @return mixed + */ + public function get(string $key) + { + Assertion::true($this->has($key), sprintf('The extension with key "%s" is not available', $key)); + + return $this->extensions[$key]; + } + + public function jsonSerialize(): array + { + return $this->extensions; + } + + 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 new file mode 100644 index 00000000..0c986b6e --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtensionsClientOutputs.php @@ -0,0 +1,83 @@ +extensions[$extension->name()] = $extension; + } + + public static function createFromString(string $data): self + { + $data = json_decode($data, true); + Assertion::eq(JSON_ERROR_NONE, json_last_error(), 'Invalid data'); + Assertion::isArray($data, 'Invalid data'); + + return self::createFromArray($data); + } + + public static function createFromArray(array $json): self + { + $object = new self(); + foreach ($json as $k => $v) { + $object->add(new AuthenticationExtension($k, $v)); + } + + return $object; + } + + public function has(string $key): bool + { + return \array_key_exists($key, $this->extensions); + } + + /** + * @return mixed + */ + public function get(string $key) + { + Assertion::true($this->has($key), sprintf('The extension with key "%s" is not available', $key)); + + return $this->extensions[$key]; + } + + public function jsonSerialize(): array + { + return $this->extensions; + } + + 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 new file mode 100644 index 00000000..51cc4bb1 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/AuthenticationExtensionsClientOutputsLoader.php @@ -0,0 +1,34 @@ +getNormalizedData(); + $extensions = new AuthenticationExtensionsClientOutputs(); + foreach ($data as $key => $value) { + Assertion::string($key, 'Invalid extension key'); + $extensions->add(new AuthenticationExtension($key, $value)); + } + + return $extensions; + } +} 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 new file mode 100644 index 00000000..e9038076 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/ExtensionOutputChecker.php @@ -0,0 +1,22 @@ +checkers[] = $checker; + } + + /** + * @throws ExtensionOutputError + */ + public function check(AuthenticationExtensionsClientOutputs $extensions): void + { + foreach ($this->checkers as $checker) { + $checker->check($extensions); + } + } +} 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 new file mode 100644 index 00000000..2b552b18 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticationExtensions/ExtensionOutputError.php @@ -0,0 +1,36 @@ +authenticationExtension = $authenticationExtension; + } + + 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 new file mode 100644 index 00000000..19132c3b --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAssertionResponse.php @@ -0,0 +1,67 @@ +authenticatorData = $authenticatorData; + $this->signature = $signature; + $this->userHandle = $userHandle; + } + + public function getAuthenticatorData(): AuthenticatorData + { + return $this->authenticatorData; + } + + public function getSignature(): string + { + return $this->signature; + } + + public function getUserHandle(): ?string + { + if (null === $this->userHandle || '' === $this->userHandle) { + return $this->userHandle; + } + + $decoded = base64_decode($this->userHandle, true); + Assertion::string($decoded, 'Unable to decode the data'); + + return $decoded; + } +} 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 new file mode 100644 index 00000000..8998493a --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAssertionResponseValidator.php @@ -0,0 +1,205 @@ +publicKeyCredentialSourceRepository = $publicKeyCredentialSourceRepository; + $this->decoder = $decoder ?? new Decoder(new TagObjectManager(), new OtherObjectManager()); + $this->tokenBindingHandler = $tokenBindingHandler; + $this->extensionOutputCheckerHandler = $extensionOutputCheckerHandler; + $this->algorithmManager = $algorithmManager; + } + + /** + * @see https://www.w3.org/TR/webauthn/#verifying-assertion + */ + public function check(string $credentialId, AuthenticatorAssertionResponse $authenticatorAssertionResponse, PublicKeyCredentialRequestOptions $publicKeyCredentialRequestOptions, ServerRequestInterface $request, ?string $userHandle): PublicKeyCredentialSource + { + /* @see 7.2.1 */ + if (0 !== \count($publicKeyCredentialRequestOptions->getAllowCredentials())) { + Assertion::true($this->isCredentialIdAllowed($credentialId, $publicKeyCredentialRequestOptions->getAllowCredentials()), 'The credential ID is not allowed.'); + } + + /* @see 7.2.2 */ + $publicKeyCredentialSource = $this->publicKeyCredentialSourceRepository->findOneByCredentialId($credentialId); + Assertion::notNull($publicKeyCredentialSource, 'The credential ID is invalid.'); + + /* @see 7.2.3 */ + $attestedCredentialData = $publicKeyCredentialSource->getAttestedCredentialData(); + $credentialUserHandle = $publicKeyCredentialSource->getUserHandle(); + $responseUserHandle = $authenticatorAssertionResponse->getUserHandle(); + + /* @see 7.2.2 User Handle*/ + if (null !== $userHandle) { //If the user was identified before the authentication ceremony was initiated, + Assertion::eq($credentialUserHandle, $userHandle, 'Invalid user handle'); + if (null !== $responseUserHandle && '' !== $responseUserHandle) { + Assertion::eq($credentialUserHandle, $responseUserHandle, 'Invalid user handle'); + } + } else { + Assertion::notEmpty($responseUserHandle, 'User handle is mandatory'); + Assertion::eq($credentialUserHandle, $responseUserHandle, 'Invalid user handle'); + } + + $credentialPublicKey = $attestedCredentialData->getCredentialPublicKey(); + Assertion::notNull($credentialPublicKey, 'No public key available.'); + $stream = new StringStream($credentialPublicKey); + $credentialPublicKeyStream = $this->decoder->decode($stream); + Assertion::true($stream->isEOF(), 'Invalid key. Presence of extra bytes.'); + $stream->close(); + + /** @see 7.2.4 */ + /** @see 7.2.5 */ + //Nothing to do. Use of objects directly + + /** @see 7.2.6 */ + $C = $authenticatorAssertionResponse->getClientDataJSON(); + + /* @see 7.2.7 */ + Assertion::eq('webauthn.get', $C->getType(), 'The client data type is not "webauthn.get".'); + + /* @see 7.2.8 */ + Assertion::true(hash_equals($publicKeyCredentialRequestOptions->getChallenge(), $C->getChallenge()), 'Invalid challenge.'); + + /** @see 7.2.9 */ + $rpId = $publicKeyCredentialRequestOptions->getRpId() ?? $request->getUri()->getHost(); + $rpIdLength = mb_strlen($rpId); + $parsedRelyingPartyId = parse_url($C->getOrigin()); + Assertion::isArray($parsedRelyingPartyId, 'Invalid origin'); + $scheme = $parsedRelyingPartyId['scheme'] ?? ''; + Assertion::eq('https', $scheme, 'Invalid scheme. HTTPS required.'); + $clientDataRpId = $parsedRelyingPartyId['host'] ?? ''; + Assertion::notEmpty($clientDataRpId, 'Invalid origin rpId.'); + Assertion::eq(mb_substr($clientDataRpId, -$rpIdLength), $rpId, 'rpId mismatch.'); + + /* @see 7.2.10 */ + if (null !== $C->getTokenBinding()) { + $this->tokenBindingHandler->check($C->getTokenBinding(), $request); + } + + /** @see 7.2.11 */ + $facetId = $this->getFacetId($rpId, $publicKeyCredentialRequestOptions->getExtensions(), $authenticatorAssertionResponse->getAuthenticatorData()->getExtensions()); + $rpIdHash = hash('sha256', $rpId, true); + Assertion::true(hash_equals($rpIdHash, $authenticatorAssertionResponse->getAuthenticatorData()->getRpIdHash()), 'rpId hash mismatch.'); + + /* @see 7.2.12 */ + /* @see 7.2.13 */ + if (AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_REQUIRED === $publicKeyCredentialRequestOptions->getUserVerification()) { + Assertion::true($authenticatorAssertionResponse->getAuthenticatorData()->isUserPresent(), 'User was not present'); + Assertion::true($authenticatorAssertionResponse->getAuthenticatorData()->isUserVerified(), 'User authentication required.'); + } + + /* @see 7.2.14 */ + $extensions = $authenticatorAssertionResponse->getAuthenticatorData()->getExtensions(); + if (null !== $extensions) { + $this->extensionOutputCheckerHandler->check($extensions); + } + + /** @see 7.2.15 */ + $getClientDataJSONHash = hash('sha256', $authenticatorAssertionResponse->getClientDataJSON()->getRawData(), true); + + /* @see 7.2.16 */ + $dataToVerify = $authenticatorAssertionResponse->getAuthenticatorData()->getAuthData().$getClientDataJSONHash; + $signature = $authenticatorAssertionResponse->getSignature(); + $coseKey = new Key($credentialPublicKeyStream->getNormalizedData()); + $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.'); + + /* @see 7.2.17 */ + $storedCounter = $publicKeyCredentialSource->getCounter(); + $currentCounter = $authenticatorAssertionResponse->getAuthenticatorData()->getSignCount(); + if (0 !== $currentCounter || 0 !== $storedCounter) { + Assertion::greaterThan($currentCounter, $storedCounter, 'Invalid counter.'); + } + $publicKeyCredentialSource->setCounter($currentCounter); + $this->publicKeyCredentialSourceRepository->saveCredentialSource($publicKeyCredentialSource); + + /* @see 7.2.18 */ + //All good. We can continue. + return $publicKeyCredentialSource; + } + + private function isCredentialIdAllowed(string $credentialId, array $allowedCredentials): bool + { + foreach ($allowedCredentials as $allowedCredential) { + if (hash_equals($allowedCredential->getId(), $credentialId)) { + return true; + } + } + + return false; + } + + private function getFacetId(string $rpId, AuthenticationExtensionsClientInputs $authenticationExtensionsClientInputs, ?AuthenticationExtensionsClientOutputs $authenticationExtensionsClientOutputs): string + { + switch (true) { + case !$authenticationExtensionsClientInputs->has('appid'): + return $rpId; + case null === $authenticationExtensionsClientOutputs: + return $rpId; + case !$authenticationExtensionsClientOutputs->has('appid'): + return $rpId; + case true !== $authenticationExtensionsClientOutputs->get('appid'): + return $rpId; + default: + return $authenticationExtensionsClientInputs->get('appid'); + } + } +} 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 new file mode 100644 index 00000000..cf9c3a40 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAttestationResponse.php @@ -0,0 +1,38 @@ +attestationObject = $attestationObject; + } + + public function getAttestationObject(): AttestationObject + { + return $this->attestationObject; + } +} 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 new file mode 100644 index 00000000..072d621b --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorAttestationResponseValidator.php @@ -0,0 +1,152 @@ +attestationStatementSupportManager = $attestationStatementSupportManager; + $this->publicKeyCredentialSource = $publicKeyCredentialSource; + $this->tokenBindingHandler = $tokenBindingHandler; + $this->extensionOutputCheckerHandler = $extensionOutputCheckerHandler; + } + + /** + * @see https://www.w3.org/TR/webauthn/#registering-a-new-credential + */ + public function check(AuthenticatorAttestationResponse $authenticatorAttestationResponse, PublicKeyCredentialCreationOptions $publicKeyCredentialCreationOptions, ServerRequestInterface $request): PublicKeyCredentialSource + { + /** @see 7.1.1 */ + //Nothing to do + + /** @see 7.1.2 */ + $C = $authenticatorAttestationResponse->getClientDataJSON(); + + /* @see 7.1.3 */ + Assertion::eq('webauthn.create', $C->getType(), 'The client data type is not "webauthn.create".'); + + /* @see 7.1.4 */ + Assertion::true(hash_equals($publicKeyCredentialCreationOptions->getChallenge(), $C->getChallenge()), 'Invalid challenge.'); + + /** @see 7.1.5 */ + $rpId = $publicKeyCredentialCreationOptions->getRp()->getId() ?? $request->getUri()->getHost(); + + $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.'); + $scheme = $parsedRelyingPartyId['scheme'] ?? ''; + Assertion::eq('https', $scheme, 'Invalid scheme. HTTPS required.'); + $clientDataRpId = $parsedRelyingPartyId['host'] ?? ''; + Assertion::notEmpty($clientDataRpId, 'Invalid origin rpId.'); + $rpIdLength = mb_strlen($rpId); + Assertion::eq(mb_substr($clientDataRpId, -$rpIdLength), $rpId, 'rpId mismatch.'); + + /* @see 7.1.6 */ + if (null !== $C->getTokenBinding()) { + $this->tokenBindingHandler->check($C->getTokenBinding(), $request); + } + + /** @see 7.1.7 */ + $clientDataJSONHash = hash('sha256', $authenticatorAttestationResponse->getClientDataJSON()->getRawData(), true); + + /** @see 7.1.8 */ + $attestationObject = $authenticatorAttestationResponse->getAttestationObject(); + + /** @see 7.1.9 */ + $rpIdHash = hash('sha256', $rpId, true); + Assertion::true(hash_equals($rpIdHash, $attestationObject->getAuthData()->getRpIdHash()), 'rpId hash mismatch.'); + + /* @see 7.1.10 */ + /* @see 7.1.11 */ + if (AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_REQUIRED === $publicKeyCredentialCreationOptions->getAuthenticatorSelection()->getUserVerification()) { + Assertion::true($attestationObject->getAuthData()->isUserPresent(), 'User was not present'); + Assertion::true($attestationObject->getAuthData()->isUserVerified(), 'User authentication required.'); + } + + /* @see 7.1.12 */ + $extensions = $attestationObject->getAuthData()->getExtensions(); + if (null !== $extensions) { + $this->extensionOutputCheckerHandler->check($extensions); + } + + /** @see 7.1.13 */ + $fmt = $attestationObject->getAttStmt()->getFmt(); + Assertion::true($this->attestationStatementSupportManager->has($fmt), 'Unsupported attestation statement format.'); + + /** @see 7.1.14 */ + $attestationStatementSupport = $this->attestationStatementSupportManager->get($fmt); + Assertion::true($attestationStatementSupport->isValid($clientDataJSONHash, $attestationObject->getAttStmt(), $attestationObject->getAuthData()), 'Invalid attestation statement.'); + + /* @see 7.1.15 */ + /* @see 7.1.16 */ + /* @see 7.1.17 */ + 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.'); + + /* @see 7.1.18 */ + /* @see 7.1.19 */ + return $this->createPublicKeyCredentialSource( + $credentialId, + $attestedCredentialData, + $attestationObject, + $publicKeyCredentialCreationOptions->getUser()->getId() + ); + } + + private function createPublicKeyCredentialSource(string $credentialId, AttestedCredentialData $attestedCredentialData, AttestationObject $attestationObject, string $userHandle): PublicKeyCredentialSource + { + return new PublicKeyCredentialSource( + $credentialId, + PublicKeyCredentialDescriptor::CREDENTIAL_TYPE_PUBLIC_KEY, + [], + $attestationObject->getAttStmt()->getType(), + $attestationObject->getAttStmt()->getTrustPath(), + $attestedCredentialData->getAaguid(), + $attestedCredentialData->getCredentialPublicKey(), + $userHandle, + $attestationObject->getAuthData()->getSignCount() + ); + } +} 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 new file mode 100644 index 00000000..d7141b63 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorData.php @@ -0,0 +1,124 @@ +rpIdHash = $rpIdHash; + $this->flags = $flags; + $this->signCount = $signCount; + $this->attestedCredentialData = $attestedCredentialData; + $this->extensions = $extensions; + $this->authData = $authData; + } + + public function getAuthData(): string + { + return $this->authData; + } + + public function getRpIdHash(): string + { + return $this->rpIdHash; + } + + public function isUserPresent(): bool + { + return 0 !== (\ord($this->flags) & self::FLAG_UP) ? true : false; + } + + public function isUserVerified(): bool + { + return 0 !== (\ord($this->flags) & self::FLAG_UV) ? true : false; + } + + public function hasAttestedCredentialData(): bool + { + return 0 !== (\ord($this->flags) & self::FLAG_AT) ? true : false; + } + + public function hasExtensions(): bool + { + return 0 !== (\ord($this->flags) & self::FLAG_ED) ? true : false; + } + + public function getReservedForFutureUse1(): int + { + return \ord($this->flags) & self::FLAG_RFU1; + } + + public function getReservedForFutureUse2(): int + { + return \ord($this->flags) & self::FLAG_RFU2; + } + + public function getSignCount(): int + { + return $this->signCount; + } + + public function getAttestedCredentialData(): ?AttestedCredentialData + { + return $this->attestedCredentialData; + } + + public function getExtensions(): ?AuthenticationExtensionsClientOutputs + { + return null !== $this->extensions && $this->hasExtensions() ? $this->extensions : null; + } +} 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 new file mode 100644 index 00000000..05f3535f --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorResponse.php @@ -0,0 +1,35 @@ +clientDataJSON = $clientDataJSON; + } + + 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 new file mode 100644 index 00000000..6fb49ac1 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/AuthenticatorSelectionCriteria.php @@ -0,0 +1,96 @@ +authenticatorAttachment = $authenticatorAttachment; + $this->requireResidentKey = $requireResidentKey; + $this->userVerification = $userVerification; + } + + public function getAuthenticatorAttachment(): ?string + { + return $this->authenticatorAttachment; + } + + public function isRequireResidentKey(): bool + { + return $this->requireResidentKey; + } + + public function getUserVerification(): string + { + return $this->userVerification; + } + + public static function createFromString(string $data): self + { + $data = json_decode($data, true); + Assertion::eq(JSON_ERROR_NONE, json_last_error(), 'Invalid data'); + Assertion::isArray($data, 'Invalid data'); + + return self::createFromArray($data); + } + + public static function createFromArray(array $json): self + { + return new self( + $json['authenticatorAttachment'] ?? null, + $json['requireResidentKey'] ?? false, + $json['userVerification'] ?? self::USER_VERIFICATION_REQUIREMENT_PREFERRED + ); + } + + public function jsonSerialize(): array + { + $json = [ + 'requireResidentKey' => $this->requireResidentKey, + 'userVerification' => $this->userVerification, + ]; + if (null !== $this->authenticatorAttachment) { + $json['authenticatorAttachment'] = $this->authenticatorAttachment; + } + + return $json; + } +} 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 new file mode 100644 index 00000000..5b47144b --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CertificateToolbox.php @@ -0,0 +1,209 @@ +start(); + while ($process->isRunning()) { + } + foreach ($filenames as $filename) { + $result = unlink($filename); + Assertion::true($result, 'Unable to delete temporary file'); + } + + if (!$process->isSuccessful()) { + throw new InvalidArgumentException('Invalid certificate or certificate chain. Error is: '.$process->getErrorOutput()); + } + } + + public static function checkAttestationMedata(AttestationStatement $attestationStatement, string $aaguid, array $certificates, MetadataStatementRepository $metadataStatementRepository): array + { + $metadataStatement = $metadataStatementRepository->findOneByAAGUID($aaguid); + if (null === $metadataStatement) { + //Check certificate CA chain + self::checkChain($certificates); + + return $certificates; + } + + //FIXME: to decide later if relevant + /*Assertion::eq('fido2', $metadataStatement->getProtocolFamily(), sprintf('The protocol family of the authenticator "%s" should be "fido2". Got "%s".', $aaguid, $metadataStatement->getProtocolFamily())); + if (null !== $metadataStatement->getAssertionScheme()) { + Assertion::eq('FIDOV2', $metadataStatement->getAssertionScheme(), sprintf('The assertion scheme of the authenticator "%s" should be "FIDOV2". Got "%s".', $aaguid, $metadataStatement->getAssertionScheme())); + }*/ + + // Check Attestation Type is allowed + if (0 !== \count($metadataStatement->getAttestationTypes())) { + $type = self::getAttestationType($attestationStatement); + Assertion::inArray($type, $metadataStatement->getAttestationTypes(), 'Invalid attestation statement. The attestation type is not allowed for this authenticator'); + } + + $attestationRootCertificates = $metadataStatement->getAttestationRootCertificates(); + if (0 === \count($attestationRootCertificates)) { + self::checkChain($certificates); + + return $certificates; + } + + foreach ($attestationRootCertificates as $key => $attestationRootCertificate) { + $attestationRootCertificates[$key] = self::fixPEMStructure($attestationRootCertificate); + } + + //Check certificate CA chain + self::checkChain($certificates, $attestationRootCertificates); + + return $certificates; + } + + private static function getAttestationType(AttestationStatement $attestationStatement): int + { + switch ($attestationStatement->getType()) { + case AttestationStatement::TYPE_BASIC: + return MetadataStatement::ATTESTATION_BASIC_FULL; + case AttestationStatement::TYPE_SELF: + return MetadataStatement::ATTESTATION_BASIC_SURROGATE; + case AttestationStatement::TYPE_ATTCA: + return MetadataStatement::ATTESTATION_ATTCA; + case AttestationStatement::TYPE_ECDAA: + return MetadataStatement::ATTESTATION_ECDAA; + default: + throw new InvalidArgumentException('Invalid attestation type'); + } + } + + public static function fixPEMStructure(string $certificate): string + { + $pemCert = '-----BEGIN CERTIFICATE-----'.PHP_EOL; + $pemCert .= chunk_split($certificate, 64, PHP_EOL); + $pemCert .= '-----END CERTIFICATE-----'.PHP_EOL; + + return $pemCert; + } + + public static function convertDERToPEM(string $certificate): string + { + $derCertificate = self::unusedBytesFix($certificate); + + return self::fixPEMStructure(base64_encode($derCertificate)); + } + + public static function convertAllDERToPEM(array $certificates): array + { + $certs = []; + foreach ($certificates as $publicKey) { + $certs[] = self::convertDERToPEM($publicKey); + } + + return $certs; + } + + private static function unusedBytesFix(string $certificate): string + { + $certificateHash = hash('sha256', $certificate); + if (\in_array($certificateHash, self::getCertificateHashes(), true)) { + $certificate[mb_strlen($certificate, '8bit') - 257] = "\0"; + } + + return $certificate; + } + + /** + * @param string[] $certificates + */ + private static function checkCertificatesValidity(array $certificates): void + { + foreach ($certificates as $certificate) { + $parsed = openssl_x509_parse($certificate); + Assertion::isArray($parsed, 'Unable to read the certificate'); + 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'); + } + } + + /** + * @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/CollectedClientData.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CollectedClientData.php new file mode 100644 index 00000000..8b33f42a --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/CollectedClientData.php @@ -0,0 +1,138 @@ +type = $this->findData($data, 'type'); + $this->challenge = $this->findData($data, 'challenge', true, true); + $this->origin = $this->findData($data, 'origin'); + $this->tokenBinding = $this->findData($data, 'tokenBinding', false); + $this->rawData = $rawData; + $this->data = $data; + } + + public static function createFormJson(string $data): self + { + $rawData = Base64Url::decode($data); + $json = json_decode($rawData, true); + Assertion::eq(JSON_ERROR_NONE, json_last_error(), 'Invalid collected client data'); + Assertion::isArray($json, 'Invalid collected client data'); + + return new self($rawData, $json); + } + + public function getType(): string + { + return $this->type; + } + + public function getChallenge(): string + { + return $this->challenge; + } + + public function getOrigin(): string + { + return $this->origin; + } + + public function getTokenBinding(): ?TokenBinding + { + return null === $this->tokenBinding ? null : TokenBinding::createFormArray($this->tokenBinding); + } + + public function getRawData(): string + { + return $this->rawData; + } + + /** + * @return string[] + */ + public function all(): array + { + return array_keys($this->data); + } + + public function has(string $key): bool + { + return \array_key_exists($key, $this->data); + } + + /** + * @return mixed + */ + public function get(string $key) + { + if (!$this->has($key)) { + throw new InvalidArgumentException(sprintf('The key "%s" is missing', $key)); + } + + return $this->data[$key]; + } + + /** + * @return mixed|null + */ + private function findData(array $json, string $key, bool $isRequired = true, bool $isB64 = false) + { + if (!\array_key_exists($key, $json)) { + if ($isRequired) { + throw new InvalidArgumentException(sprintf('The key "%s" is missing', $key)); + } + + return; + } + + return $isB64 ? Base64Url::decode($json[$key]) : $json[$key]; + } +} 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 new file mode 100644 index 00000000..3d981c8a --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Credential.php @@ -0,0 +1,46 @@ +id = $id; + $this->type = $type; + } + + public function getId(): string + { + return $this->id; + } + + public function getType(): string + { + return $this->type; + } +} 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 new file mode 100644 index 00000000..956309d5 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredential.php @@ -0,0 +1,65 @@ +rawId = $rawId; + $this->response = $response; + } + + public function getRawId(): string + { + return $this->rawId; + } + + public function getResponse(): AuthenticatorResponse + { + return $this->response; + } + + /** + * @param string[] $transport + */ + public function getPublicKeyCredentialDescriptor(array $transport = []): PublicKeyCredentialDescriptor + { + return new PublicKeyCredentialDescriptor($this->getType(), $this->getRawId(), $transport); + } + + public function __toString() + { + $encoded = json_encode($this); + Assertion::string($encoded, 'Unable to encode the data'); + + return $encoded; + } +} 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 new file mode 100644 index 00000000..26828814 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialCreationOptions.php @@ -0,0 +1,177 @@ +rp = $rp; + $this->user = $user; + $this->pubKeyCredParams = array_values($pubKeyCredParams); + $this->excludeCredentials = array_values($excludeCredentials); + $this->authenticatorSelection = $authenticatorSelection; + $this->attestation = $attestation; + } + + public function getRp(): PublicKeyCredentialRpEntity + { + return $this->rp; + } + + public function getUser(): PublicKeyCredentialUserEntity + { + return $this->user; + } + + /** + * @return PublicKeyCredentialParameters[] + */ + public function getPubKeyCredParams(): array + { + return $this->pubKeyCredParams; + } + + /** + * @return PublicKeyCredentialDescriptor[] + */ + public function getExcludeCredentials(): array + { + return $this->excludeCredentials; + } + + public function getAuthenticatorSelection(): AuthenticatorSelectionCriteria + { + return $this->authenticatorSelection; + } + + public function getAttestation(): string + { + return $this->attestation; + } + + public static function createFromString(string $data): PublicKeyCredentialOptions + { + $data = json_decode($data, true); + Assertion::eq(JSON_ERROR_NONE, json_last_error(), 'Invalid data'); + Assertion::isArray($data, 'Invalid data'); + + return self::createFromArray($data); + } + + public static function createFromArray(array $json): PublicKeyCredentialOptions + { + 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.'); + + $pubKeyCredParams = []; + foreach ($json['pubKeyCredParams'] as $pubKeyCredParam) { + $pubKeyCredParams[] = PublicKeyCredentialParameters::createFromArray($pubKeyCredParam); + } + $excludeCredentials = []; + if (isset($json['excludeCredentials'])) { + foreach ($json['excludeCredentials'] as $excludeCredential) { + $excludeCredentials[] = PublicKeyCredentialDescriptor::createFromArray($excludeCredential); + } + } + + return new self( + PublicKeyCredentialRpEntity::createFromArray($json['rp']), + PublicKeyCredentialUserEntity::createFromArray($json['user']), + Base64Url::decode($json['challenge']), + $pubKeyCredParams, + $json['timeout'] ?? null, + $excludeCredentials, + AuthenticatorSelectionCriteria::createFromArray($json['authenticatorSelection']), + $json['attestation'], + isset($json['extensions']) ? AuthenticationExtensionsClientInputs::createFromArray($json['extensions']) : new AuthenticationExtensionsClientInputs() + ); + } + + public function jsonSerialize(): array + { + $json = [ + 'rp' => $this->rp, + 'pubKeyCredParams' => $this->pubKeyCredParams, + 'challenge' => Base64Url::encode($this->challenge), + 'attestation' => $this->attestation, + 'user' => $this->user, + 'authenticatorSelection' => $this->authenticatorSelection, + ]; + + if (0 !== \count($this->excludeCredentials)) { + $json['excludeCredentials'] = $this->excludeCredentials; + } + + if (0 !== $this->extensions->count()) { + $json['extensions'] = $this->extensions; + } + + if (null !== $this->timeout) { + $json['timeout'] = $this->timeout; + } + + 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 new file mode 100644 index 00000000..683f81cc --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialDescriptor.php @@ -0,0 +1,105 @@ +type = $type; + $this->id = $id; + $this->transports = $transports; + } + + public function getType(): string + { + return $this->type; + } + + public function getId(): string + { + return $this->id; + } + + /** + * @return string[] + */ + public function getTransports(): array + { + return $this->transports; + } + + public static function createFromString(string $data): self + { + $data = json_decode($data, true); + Assertion::eq(JSON_ERROR_NONE, json_last_error(), 'Invalid data'); + Assertion::isArray($data, 'Invalid data'); + + return self::createFromArray($data); + } + + 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.'); + + return new self( + $json['type'], + Base64Url::decode($json['id']), + $json['transports'] ?? [] + ); + } + + public function jsonSerialize(): array + { + $json = [ + 'type' => $this->type, + 'id' => Base64Url::encode($this->id), + ]; + if (0 !== \count($this->transports)) { + $json['transports'] = $this->transports; + } + + return $json; + } +} 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 new file mode 100644 index 00000000..8364c6b4 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialDescriptorCollection.php @@ -0,0 +1,82 @@ +publicKeyCredentialDescriptors[$publicKeyCredentialDescriptor->getId()] = $publicKeyCredentialDescriptor; + } + + public function has(string $id): bool + { + return \array_key_exists($id, $this->publicKeyCredentialDescriptors); + } + + public function remove(string $id): void + { + if (!$this->has($id)) { + return; + } + + unset($this->publicKeyCredentialDescriptors[$id]); + } + + public function getIterator(): Iterator + { + return new ArrayIterator($this->publicKeyCredentialDescriptors); + } + + public function count(int $mode = COUNT_NORMAL): int + { + return \count($this->publicKeyCredentialDescriptors, $mode); + } + + public function jsonSerialize(): array + { + return array_values($this->publicKeyCredentialDescriptors); + } + + public static function createFromString(string $data): self + { + $data = json_decode($data, true); + Assertion::eq(JSON_ERROR_NONE, json_last_error(), 'Invalid data'); + Assertion::isArray($data, 'Invalid data'); + + return self::createFromArray($data); + } + + public static function createFromArray(array $json): self + { + $collection = new self(); + foreach ($json as $item) { + $collection->add(PublicKeyCredentialDescriptor::createFromArray($item)); + } + + return $collection; + } +} 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 new file mode 100644 index 00000000..959bb17a --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialEntity.php @@ -0,0 +1,57 @@ +name = $name; + $this->icon = $icon; + } + + public function getName(): string + { + return $this->name; + } + + public function getIcon(): ?string + { + return $this->icon; + } + + public function jsonSerialize(): array + { + $json = [ + 'name' => $this->name, + ]; + if (null !== $this->icon) { + $json['icon'] = $this->icon; + } + + return $json; + } +} 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 new file mode 100644 index 00000000..9ff31fd8 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialLoader.php @@ -0,0 +1,130 @@ +decoder = $decoder ?? new Decoder(new TagObjectManager(), new OtherObjectManager()); + $this->attestationObjectLoader = $attestationObjectLoader; + } + + public function loadArray(array $json): PublicKeyCredential + { + 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)); + } + 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'])); + + $id = Base64Url::decode($json['id']); + $rawId = Base64Url::decode($json['rawId']); + Assertion::true(hash_equals($id, $rawId)); + + $publicKeyCredential = new PublicKeyCredential( + $json['id'], + $json['type'], + $rawId, + $this->createResponse($json['response']) + ); + + return $publicKeyCredential; + } + + public function load(string $data): PublicKeyCredential + { + $json = json_decode($data, true); + Assertion::eq(JSON_ERROR_NONE, json_last_error(), 'Invalid data'); + + return $this->loadArray($json); + } + + private function createResponse(array $response): AuthenticatorResponse + { + Assertion::keyExists($response, 'clientDataJSON'); + switch (true) { + case \array_key_exists('attestationObject', $response): + $attestationObject = $this->attestationObjectLoader->load($response['attestationObject']); + + return new AuthenticatorAttestationResponse(CollectedClientData::createFormJson($response['clientDataJSON']), $attestationObject); + case \array_key_exists('authenticatorData', $response) && \array_key_exists('signature', $response): + $authData = Base64Url::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)[1]; + + $attestedCredentialData = null; + if (0 !== (\ord($flags) & self::FLAG_AT)) { + $aaguid = Uuid::fromBytes($authDataStream->read(16)); + $credentialLength = $authDataStream->read(2); + $credentialLength = unpack('n', $credentialLength)[1]; + $credentialId = $authDataStream->read($credentialLength); + $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, $attestedCredentialData, $extension); + + return new AuthenticatorAssertionResponse( + CollectedClientData::createFormJson($response['clientDataJSON']), + $authenticatorData, + Base64Url::decode($response['signature']), + $response['userHandle'] ?? null + ); + default: + throw new InvalidArgumentException('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 new file mode 100644 index 00000000..e0440a47 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialOptions.php @@ -0,0 +1,61 @@ +challenge = $challenge; + $this->timeout = $timeout; + $this->extensions = $extensions ?? new AuthenticationExtensionsClientInputs(); + } + + public function getChallenge(): string + { + return $this->challenge; + } + + public function getTimeout(): ?int + { + return $this->timeout; + } + + public function getExtensions(): AuthenticationExtensionsClientInputs + { + return $this->extensions; + } + + abstract public static function createFromString(string $data): self; + + abstract public static function createFromArray(array $json): self; +} 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 new file mode 100644 index 00000000..c0600862 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialParameters.php @@ -0,0 +1,76 @@ +type = $type; + $this->alg = $alg; + } + + public function getType(): string + { + return $this->type; + } + + public function getAlg(): int + { + return $this->alg; + } + + public static function createFromString(string $data): self + { + $data = json_decode($data, true); + Assertion::eq(JSON_ERROR_NONE, json_last_error(), 'Invalid data'); + Assertion::isArray($data, 'Invalid data'); + + return self::createFromArray($data); + } + + 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.'); + + return new self( + $json['type'], + $json['alg'] + ); + } + + public function jsonSerialize(): array + { + 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 new file mode 100644 index 00000000..1a5062d0 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialRequestOptions.php @@ -0,0 +1,127 @@ +rpId = $rpId; + $this->allowCredentials = array_values($allowCredentials); + $this->userVerification = $userVerification; + } + + public function getRpId(): ?string + { + return $this->rpId; + } + + /** + * @return PublicKeyCredentialDescriptor[] + */ + public function getAllowCredentials(): array + { + return $this->allowCredentials; + } + + public function getUserVerification(): ?string + { + return $this->userVerification; + } + + public static function createFromString(string $data): PublicKeyCredentialOptions + { + $data = json_decode($data, true); + Assertion::eq(JSON_ERROR_NONE, json_last_error(), 'Invalid data'); + Assertion::isArray($data, 'Invalid data'); + + return self::createFromArray($data); + } + + public static function createFromArray(array $json): PublicKeyCredentialOptions + { + Assertion::keyExists($json, 'challenge', 'Invalid input. "challenge" is missing.'); + + $allowCredentials = []; + $allowCredentialList = $json['allowCredentials'] ?? []; + foreach ($allowCredentialList as $allowCredential) { + $allowCredentials[] = PublicKeyCredentialDescriptor::createFromArray($allowCredential); + } + + return new self( + Base64Url::decode($json['challenge']), + $json['timeout'] ?? null, + $json['rpId'] ?? null, + $allowCredentials, + $json['userVerification'] ?? null, + isset($json['extensions']) ? AuthenticationExtensionsClientInputs::createFromArray($json['extensions']) : new AuthenticationExtensionsClientInputs() + ); + } + + public function jsonSerialize(): array + { + $json = [ + 'challenge' => Base64Url::encode($this->challenge), + ]; + + if (null !== $this->rpId) { + $json['rpId'] = $this->rpId; + } + + if (null !== $this->userVerification) { + $json['userVerification'] = $this->userVerification; + } + + if (0 !== \count($this->allowCredentials)) { + $json['allowCredentials'] = $this->allowCredentials; + } + + if (0 !== $this->extensions->count()) { + $json['extensions'] = $this->extensions; + } + + if (null !== $this->timeout) { + $json['timeout'] = $this->timeout; + } + + return $json; + } +} 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 new file mode 100644 index 00000000..e17c5d0a --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialRpEntity.php @@ -0,0 +1,56 @@ +id = $id; + } + + public function getId(): ?string + { + return $this->id; + } + + public static function createFromArray(array $json): self + { + Assertion::keyExists($json, 'name', 'Invalid input. "name" is missing.'); + + return new self( + $json['name'], + $json['id'] ?? null, + $json['icon'] ?? null + ); + } + + public function jsonSerialize(): array + { + $json = parent::jsonSerialize(); + if (null !== $this->id) { + $json['id'] = $this->id; + } + + return $json; + } +} 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 new file mode 100644 index 00000000..0bd9ab2d --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialSource.php @@ -0,0 +1,233 @@ +publicKeyCredentialId = $publicKeyCredentialId; + $this->type = $type; + $this->transports = $transports; + $this->aaguid = $aaguid; + $this->credentialPublicKey = $credentialPublicKey; + $this->userHandle = $userHandle; + $this->counter = $counter; + $this->attestationType = $attestationType; + $this->trustPath = $trustPath; + } + + /** + * @deprecated Deprecated since v2.1. Will be removed in v3.0. Please use response from the credential source returned by the AuthenticatorAttestationResponseValidator after "check" method + */ + public static function createFromPublicKeyCredential(PublicKeyCredential $publicKeyCredential, string $userHandle): self + { + $response = $publicKeyCredential->getResponse(); + Assertion::isInstanceOf($response, AuthenticatorAttestationResponse::class, 'This method is only available with public key credential containing an authenticator attestation response.'); + $publicKeyCredentialDescriptor = $publicKeyCredential->getPublicKeyCredentialDescriptor(); + $attestationStatement = $response->getAttestationObject()->getAttStmt(); + $authenticatorData = $response->getAttestationObject()->getAuthData(); + $attestedCredentialData = $authenticatorData->getAttestedCredentialData(); + Assertion::notNull($attestedCredentialData, 'No attested credential data available'); + + return new self( + $publicKeyCredentialDescriptor->getId(), + $publicKeyCredentialDescriptor->getType(), + $publicKeyCredentialDescriptor->getTransports(), + $attestationStatement->getType(), + $attestationStatement->getTrustPath(), + $attestedCredentialData->getAaguid(), + $attestedCredentialData->getCredentialPublicKey(), + $userHandle, + $authenticatorData->getSignCount() + ); + } + + public function getPublicKeyCredentialId(): string + { + return $this->publicKeyCredentialId; + } + + public function getPublicKeyCredentialDescriptor(): PublicKeyCredentialDescriptor + { + return new PublicKeyCredentialDescriptor( + $this->type, + $this->publicKeyCredentialId, + $this->transports + ); + } + + public function getAttestationType(): string + { + return $this->attestationType; + } + + public function getTrustPath(): TrustPath + { + return $this->trustPath; + } + + public function getAttestedCredentialData(): AttestedCredentialData + { + return new AttestedCredentialData( + $this->aaguid, + $this->publicKeyCredentialId, + $this->credentialPublicKey + ); + } + + public function getType(): string + { + return $this->type; + } + + /** + * @return string[] + */ + public function getTransports(): array + { + return $this->transports; + } + + public function getAaguid(): UuidInterface + { + return $this->aaguid; + } + + public function getCredentialPublicKey(): string + { + return $this->credentialPublicKey; + } + + public function getUserHandle(): string + { + return $this->userHandle; + } + + public function getCounter(): int + { + return $this->counter; + } + + public function setCounter(int $counter): void + { + $this->counter = $counter; + } + + public static function createFromArray(array $data): self + { + $keys = array_keys(get_class_vars(self::class)); + foreach ($keys as $key) { + Assertion::keyExists($data, $key, sprintf('The parameter "%s" is missing', $key)); + } + switch (true) { + case 36 === mb_strlen($data['aaguid'], '8bit'): + $uuid = Uuid::fromString($data['aaguid']); + break; + default: // Kept for compatibility with old format + $decoded = base64_decode($data['aaguid'], true); + Assertion::string($decoded, 'Invalid AAGUID'); + $uuid = Uuid::fromBytes($decoded); + } + + try { + return new self( + Base64Url::decode($data['publicKeyCredentialId']), + $data['type'], + $data['transports'], + $data['attestationType'], + TrustPathLoader::loadTrustPath($data['trustPath']), + $uuid, + Base64Url::decode($data['credentialPublicKey']), + Base64Url::decode($data['userHandle']), + $data['counter'] + ); + } catch (Throwable $throwable) { + throw new InvalidArgumentException('Unable to load the data', $throwable->getCode(), $throwable); + } + } + + public function jsonSerialize(): array + { + return [ + 'publicKeyCredentialId' => Base64Url::encode($this->publicKeyCredentialId), + 'type' => $this->type, + 'transports' => $this->transports, + 'attestationType' => $this->attestationType, + 'trustPath' => $this->trustPath, + 'aaguid' => $this->aaguid->toString(), + 'credentialPublicKey' => Base64Url::encode($this->credentialPublicKey), + 'userHandle' => Base64Url::encode($this->userHandle), + 'counter' => $this->counter, + ]; + } +} 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 new file mode 100644 index 00000000..8df9142f --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/PublicKeyCredentialSourceRepository.php @@ -0,0 +1,26 @@ +id = $id; + $this->displayName = $displayName; + } + + public function getId(): string + { + return $this->id; + } + + public function getDisplayName(): string + { + return $this->displayName; + } + + public static function createFromString(string $data): self + { + $data = json_decode($data, true); + Assertion::eq(JSON_ERROR_NONE, json_last_error(), 'Invalid data'); + Assertion::isArray($data, 'Invalid data'); + + return self::createFromArray($data); + } + + 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.'); + $id = base64_decode($json['id'], true); + Assertion::string($id, 'Invalid parameter "id".'); + + return new self( + $json['name'], + $id, + $json['displayName'], + $json['icon'] ?? null + ); + } + + public function jsonSerialize(): array + { + $json = parent::jsonSerialize(); + $json['id'] = base64_encode($this->id); + $json['displayName'] = $this->displayName; + + return $json; + } +} diff --git a/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Server.php b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Server.php new file mode 100644 index 00000000..4580f325 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Server.php @@ -0,0 +1,264 @@ +rpEntity = $relayingParty; + + $this->coseAlgorithmManagerFactory = new ManagerFactory(); + $this->coseAlgorithmManagerFactory->add('RS1', new RSA\RS1()); + $this->coseAlgorithmManagerFactory->add('RS256', new RSA\RS256()); + $this->coseAlgorithmManagerFactory->add('RS384', new RSA\RS384()); + $this->coseAlgorithmManagerFactory->add('RS512', new RSA\RS512()); + $this->coseAlgorithmManagerFactory->add('PS256', new RSA\PS256()); + $this->coseAlgorithmManagerFactory->add('PS384', new RSA\PS384()); + $this->coseAlgorithmManagerFactory->add('PS512', new RSA\PS512()); + $this->coseAlgorithmManagerFactory->add('ES256', new ECDSA\ES256()); + $this->coseAlgorithmManagerFactory->add('ES256K', new ECDSA\ES256K()); + $this->coseAlgorithmManagerFactory->add('ES384', new ECDSA\ES384()); + $this->coseAlgorithmManagerFactory->add('ES512', new ECDSA\ES512()); + $this->coseAlgorithmManagerFactory->add('Ed25519', new EdDSA\Ed25519()); + + $this->selectedAlgorithms = ['RS256', 'RS512', 'PS256', 'PS512', 'ES256', 'ES512', 'Ed25519']; + $this->publicKeyCredentialSourceRepository = $publicKeyCredentialSourceRepository; + $this->tokenBindingHandler = new TokenBindingNotSupportedHandler(); + $this->extensionOutputCheckerHandler = new ExtensionOutputCheckerHandler(); + $this->metadataStatementRepository = $metadataStatementRepository; + } + + /** + * @param string[] $selectedAlgorithms + */ + public function setSelectedAlgorithms(array $selectedAlgorithms): void + { + $this->selectedAlgorithms = $selectedAlgorithms; + } + + public function setTokenBindingHandler(TokenBindingNotSupportedHandler $tokenBindingHandler): void + { + $this->tokenBindingHandler = $tokenBindingHandler; + } + + public function addAlgorithm(string $alias, Algorithm $algorithm): void + { + $this->coseAlgorithmManagerFactory->add($alias, $algorithm); + $this->selectedAlgorithms[] = $alias; + $this->selectedAlgorithms = array_unique($this->selectedAlgorithms); + } + + public function setExtensionOutputCheckerHandler(ExtensionOutputCheckerHandler $extensionOutputCheckerHandler): void + { + $this->extensionOutputCheckerHandler = $extensionOutputCheckerHandler; + } + + /** + * @param PublicKeyCredentialDescriptor[] $excludedPublicKeyDescriptors + */ + public function generatePublicKeyCredentialCreationOptions(PublicKeyCredentialUserEntity $userEntity, ?string $attestationMode = PublicKeyCredentialCreationOptions::ATTESTATION_CONVEYANCE_PREFERENCE_NONE, array $excludedPublicKeyDescriptors = [], ?AuthenticatorSelectionCriteria $criteria = null, ?AuthenticationExtensionsClientInputs $extensions = null): PublicKeyCredentialCreationOptions + { + $coseAlgorithmManager = $this->coseAlgorithmManagerFactory->create($this->selectedAlgorithms); + $publicKeyCredentialParametersList = []; + foreach ($coseAlgorithmManager->all() as $algorithm) { + $publicKeyCredentialParametersList[] = new PublicKeyCredentialParameters( + PublicKeyCredentialDescriptor::CREDENTIAL_TYPE_PUBLIC_KEY, + $algorithm::identifier() + ); + } + $criteria = $criteria ?? new AuthenticatorSelectionCriteria(); + $extensions = $extensions ?? new AuthenticationExtensionsClientInputs(); + $challenge = random_bytes($this->challengeSize); + + return new PublicKeyCredentialCreationOptions( + $this->rpEntity, + $userEntity, + $challenge, + $publicKeyCredentialParametersList, + $this->timeout, + $excludedPublicKeyDescriptors, + $criteria, + $attestationMode, + $extensions + ); + } + + /** + * @param PublicKeyCredentialDescriptor[] $allowedPublicKeyDescriptors + */ + public function generatePublicKeyCredentialRequestOptions(?string $userVerification = PublicKeyCredentialRequestOptions::USER_VERIFICATION_REQUIREMENT_PREFERRED, array $allowedPublicKeyDescriptors = [], ?AuthenticationExtensionsClientInputs $extensions = null): PublicKeyCredentialRequestOptions + { + return new PublicKeyCredentialRequestOptions( + random_bytes($this->challengeSize), + $this->timeout, + $this->rpEntity->getId(), + $allowedPublicKeyDescriptors, + $userVerification, + $extensions ?? new AuthenticationExtensionsClientInputs() + ); + } + + public function loadAndCheckAttestationResponse(string $data, PublicKeyCredentialCreationOptions $publicKeyCredentialCreationOptions, ServerRequestInterface $serverRequest): PublicKeyCredentialSource + { + $attestationStatementSupportManager = $this->getAttestationStatementSupportManager(); + $attestationObjectLoader = new AttestationObjectLoader($attestationStatementSupportManager); + $publicKeyCredentialLoader = new PublicKeyCredentialLoader($attestationObjectLoader); + + $publicKeyCredential = $publicKeyCredentialLoader->load($data); + $authenticatorResponse = $publicKeyCredential->getResponse(); + Assertion::isInstanceOf($authenticatorResponse, AuthenticatorAttestationResponse::class, 'Not an authenticator attestation response'); + + $authenticatorAttestationResponseValidator = new AuthenticatorAttestationResponseValidator( + $attestationStatementSupportManager, + $this->publicKeyCredentialSourceRepository, + $this->tokenBindingHandler, + $this->extensionOutputCheckerHandler + ); + + return $authenticatorAttestationResponseValidator->check($authenticatorResponse, $publicKeyCredentialCreationOptions, $serverRequest); + } + + public function loadAndCheckAssertionResponse(string $data, PublicKeyCredentialRequestOptions $publicKeyCredentialRequestOptions, ?PublicKeyCredentialUserEntity $userEntity, ServerRequestInterface $serverRequest): PublicKeyCredentialSource + { + $attestationStatementSupportManager = $this->getAttestationStatementSupportManager(); + $attestationObjectLoader = new AttestationObjectLoader($attestationStatementSupportManager); + $publicKeyCredentialLoader = new PublicKeyCredentialLoader($attestationObjectLoader); + + $publicKeyCredential = $publicKeyCredentialLoader->load($data); + $authenticatorResponse = $publicKeyCredential->getResponse(); + Assertion::isInstanceOf($authenticatorResponse, AuthenticatorAssertionResponse::class, 'Not an authenticator assertion response'); + + $authenticatorAssertionResponseValidator = new AuthenticatorAssertionResponseValidator( + $this->publicKeyCredentialSourceRepository, + null, + $this->tokenBindingHandler, + $this->extensionOutputCheckerHandler, + $this->coseAlgorithmManagerFactory->create($this->selectedAlgorithms) + ); + + return $authenticatorAssertionResponseValidator->check( + $publicKeyCredential->getRawId(), + $authenticatorResponse, + $publicKeyCredentialRequestOptions, + $serverRequest, + null !== $userEntity ? $userEntity->getId() : null + ); + } + + public function enforceAndroidSafetyNetVerification(ClientInterface $client, string $apiKey, RequestFactoryInterface $requestFactory): void + { + $this->httpClient = $client; + $this->googleApiKey = $apiKey; + $this->requestFactory = $requestFactory; + } + + private function getAttestationStatementSupportManager(): AttestationStatementSupportManager + { + $attestationStatementSupportManager = new AttestationStatementSupportManager(); + $attestationStatementSupportManager->add(new NoneAttestationStatementSupport()); + if (null !== $this->metadataStatementRepository) { + $coseAlgorithmManager = $this->coseAlgorithmManagerFactory->create($this->selectedAlgorithms); + $attestationStatementSupportManager->add(new FidoU2FAttestationStatementSupport(null, $this->metadataStatementRepository)); + $attestationStatementSupportManager->add(new AndroidSafetyNetAttestationStatementSupport($this->httpClient, $this->googleApiKey, $this->requestFactory, 2000, 60000, $this->metadataStatementRepository)); + $attestationStatementSupportManager->add(new AndroidKeyAttestationStatementSupport(null, $this->metadataStatementRepository)); + $attestationStatementSupportManager->add(new TPMAttestationStatementSupport($this->metadataStatementRepository)); + $attestationStatementSupportManager->add(new PackedAttestationStatementSupport(null, $coseAlgorithmManager, $this->metadataStatementRepository)); + } + + return $attestationStatementSupportManager; + } +} 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 new file mode 100644 index 00000000..8b8c9784 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/StringStream.php @@ -0,0 +1,72 @@ +length = mb_strlen($data, '8bit'); + $resource = fopen('php://memory', 'rb+'); + Assertion::isResource($resource, 'Unable to open memory'); + $result = fwrite($resource, $data); + Assertion::integer($result, 'Unable to write memory'); + $result = rewind($resource); + Assertion::true($result, 'Unable to read memory'); + $this->data = $resource; + } + + public function read(int $length): string + { + if (0 === $length) { + return ''; + } + $read = fread($this->data, $length); + Assertion::string($read, 'Unable to read memory'); + $bytesRead = mb_strlen($read, '8bit'); + Assertion::length($read, $length, sprintf('Out of range. Expected: %d, read: %d.', $length, $bytesRead), null, '8bit'); + $this->totalRead += $bytesRead; + + return $read; + } + + public function close(): void + { + $result = fclose($this->data); + Assertion::true($result, 'Unable to close the memory'); + } + + public function isEOF(): bool + { + return $this->totalRead === $this->length; + } +} 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 new file mode 100644 index 00000000..fe03da7e --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/IgnoreTokenBindingHandler.php @@ -0,0 +1,24 @@ +status = $status; + $this->id = $id; + } + + 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())) + ); + $id = \array_key_exists('id', $json) ? Base64Url::decode($json['id']) : null; + + return new self($status, $id); + } + + public function getStatus(): string + { + return $this->status; + } + + public function getId(): ?string + { + return $this->id; + } + + /** + * @return string[] + */ + private static function getSupportedStatus(): array + { + return [ + self::TOKEN_BINDING_STATUS_PRESENT, + self::TOKEN_BINDING_STATUS_SUPPORTED, + self::TOKEN_BINDING_STATUS_NOT_SUPPORTED, + ]; + } +} 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 new file mode 100644 index 00000000..803d82e3 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TokenBinding/TokenBindingHandler.php @@ -0,0 +1,21 @@ +getStatus(), '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 new file mode 100644 index 00000000..17537159 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/CertificateTrustPath.php @@ -0,0 +1,55 @@ +certificates = $certificates; + } + + /** + * @return string[] + */ + public function getCertificates(): array + { + return $this->certificates; + } + + public static function createFromArray(array $data): TrustPath + { + Assertion::keyExists($data, 'x5c', 'The trust path type is invalid'); + + return new CertificateTrustPath($data['x5c']); + } + + public function jsonSerialize(): array + { + 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 new file mode 100644 index 00000000..7656cb75 --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/EcdaaKeyIdTrustPath.php @@ -0,0 +1,49 @@ +ecdaaKeyId = $ecdaaKeyId; + } + + public function getEcdaaKeyId(): string + { + return $this->ecdaaKeyId; + } + + public function jsonSerialize(): array + { + return [ + 'type' => self::class, + 'ecdaaKeyId' => $this->ecdaaKeyId, + ]; + } + + public static function createFromArray(array $data): TrustPath + { + Assertion::keyExists($data, 'ecdaaKeyId', 'The trust path type is invalid'); + + return new EcdaaKeyIdTrustPath($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 new file mode 100644 index 00000000..d94ff09c --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/EmptyTrustPath.php @@ -0,0 +1,29 @@ + self::class, + ]; + } + + public static function createFromArray(array $data): TrustPath + { + return new EmptyTrustPath(); + } +} 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 new file mode 100644 index 00000000..b180d89f --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/TrustPath/TrustPath.php @@ -0,0 +1,21 @@ + EmptyTrustPath::class, + 'ecdaa_key_id' => EcdaaKeyIdTrustPath::class, + 'x5c' => CertificateTrustPath::class, + ]; + } +} 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 new file mode 100644 index 00000000..5418a87d --- /dev/null +++ b/lam/lib/3rdParty/composer/web-auth/webauthn-lib/src/Util/CoseSignatureFixer.php @@ -0,0 +1,54 @@ + TwoFactorProviderService::TWO_FACTOR_PRIVACYIDEA, 'YubiKey' => TwoFactorProviderService::TWO_FACTOR_YUBICO, 'Duo' => TwoFactorProviderService::TWO_FACTOR_DUO, - 'Webauthn' => TwoFactorProviderService::TWO_FACTOR_DUO, - 'Webauthn' => TwoFactorProviderService::TWO_FACTOR_WEBAUTHN, ); + if (version_compare(phpversion(), '7.2.0') >= 0) { + $twoFactorOptions['Webauthn'] = TwoFactorProviderService::TWO_FACTOR_WEBAUTHN; + } $twoFactorSelect = new htmlResponsiveSelect('twoFactor', $twoFactorOptions, array($conf->getTwoFactorAuthentication()), _('Provider'), '514'); $twoFactorSelect->setHasDescriptiveElements(true); $twoFactorSelect->setTableRowsToHide(array( diff --git a/lam/templates/lib/500_lam.js b/lam/templates/lib/500_lam.js index 1413f807..6452f71c 100644 --- a/lam/templates/lib/500_lam.js +++ b/lam/templates/lib/500_lam.js @@ -1396,12 +1396,42 @@ window.lam.webauthn.run = function(prefix) { }) .done(function(jsonData) { console.log(jsonData); + if (jsonData.action === 'register') { + window.lam.webauthn.register(jsonData.registration); + } }) .fail(function() { console.log('Webauthn failed'); }); } +/** + * Performs a webauthn registration. + * + * @param publicKey registration object + */ +window.lam.webauthn.register = function(publicKey) { + console.log(publicKey); + publicKey.challenge = Uint8Array.from(window.atob(publicKey.challenge), c=>c.charCodeAt(0)); + publicKey.user.id = Uint8Array.from(window.atob(publicKey.user.id), c=>c.charCodeAt(0)); + navigator.credentials.create({publicKey}) + .then(function (data) { + console.log(data); + let publicKeyCredential = { + id: data.id, + type: data.type, + rawId: btoa(String.fromCharCode(new Uint8Array(data.rawId))), + response: { + clientDataJSON: btoa(String.fromCharCode((new Uint8Array(data.response.clientDataJSON)))), + attestationObject: btoa(String.fromCharCode((new Uint8Array(data.response.attestationObject)))) + } + }; + console.log(publicKeyCredential); + //window.location = '/request_post?data='+btoa(JSON.stringify(publicKeyCredential)); + }, function (error) { + console.log(error); + }); +} jQuery(document).ready(function() { window.lam.gui.equalHeight(); diff --git a/lam/templates/misc/ajax.php b/lam/templates/misc/ajax.php index 09383d35..de69266c 100644 --- a/lam/templates/misc/ajax.php +++ b/lam/templates/misc/ajax.php @@ -7,6 +7,9 @@ use \htmlResponsiveRow; use \htmlLink; use \htmlOutputText; use \htmlButton; +use function LAM\LOGIN\WEBAUTHN\getRegistrationObject; +use function LAM\LOGIN\WEBAUTHN\isRegistered; + /* This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) @@ -71,7 +74,7 @@ class Ajax { $this->setHeader(); // check token validateSecurityToken(); - + $isSelfService = isset($_GET['selfservice']); if (isset($_GET['module']) && isset($_GET['scope']) && in_array($_GET['module'], getAvailableModules($_GET['scope']))) { enforceUserIsLoggedIn(); if (isset($_GET['useContainer']) && ($_GET['useContainer'] == '1')) { @@ -103,7 +106,7 @@ class Ajax { } if ($function === 'webauthn') { enforceUserIsLoggedIn(false); - $this->manageWebauthn(); + $this->manageWebauthn($isSelfService); die(); } enforceUserIsLoggedIn(); @@ -184,9 +187,25 @@ class Ajax { /** * Manages webauthn requests. + * + * @param bool $isSelfService request is from self service */ - private function manageWebauthn() { + private function manageWebauthn($isSelfService) { + include_once __DIR__ . '/../../lib/3rdParty/composer/autoload.php'; + include_once __DIR__ . '/../../lib/webauthn.inc'; $userDN = $_SESSION['ldap']->getUserName(); + $isRegistered = isRegistered($userDN); + if (!$isRegistered) { + $registrationObject = getRegistrationObject($userDN); + echo json_encode( + array( + 'action' => 'register', + 'registration' => $registrationObject + ), + JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE + ); + die(); + } } /**