Repository: yourkarma/JWT Branch: master Commit: 8414cafd0684 Files: 320 Total size: 837.8 KB Directory structure: gitextract_ums_flbi/ ├── .github/ │ ├── CONTRIBUTING.md │ ├── ISSUE_TEMPLATE.md │ ├── PULL_REQUEST_TEMPLATE.md │ └── workflows/ │ ├── library-builds.yaml │ ├── unit-tests.yaml │ └── validations.yaml ├── .gitignore ├── .gitmodules ├── .local_run_travis_script.sh ├── .travis.yml ├── Cartfile ├── Cartfile.resolved ├── Documentation/ │ └── Prerelease/ │ └── custom_claims.md ├── Example/ │ ├── JWTDesktop/ │ │ ├── JWTDesktop/ │ │ │ ├── AppDelegate.h │ │ │ ├── AppDelegate.m │ │ │ ├── Assets.xcassets/ │ │ │ │ └── AppIcon.appiconset/ │ │ │ │ └── Contents.json │ │ │ ├── Base.lproj/ │ │ │ │ └── Main.storyboard │ │ │ ├── Info.plist │ │ │ ├── JWTDecriptedCollectionViewItem.h │ │ │ ├── JWTDecriptedCollectionViewItem.m │ │ │ ├── JWTDecriptedCollectionViewItem.xib │ │ │ ├── JWTDecriptedViewController.h │ │ │ ├── JWTDecriptedViewController.m │ │ │ ├── JWTDecriptedViewController.xib │ │ │ ├── JWTTokenDecoder.h │ │ │ ├── JWTTokenDecoder.m │ │ │ ├── JWTTokenTextTypeDescription.h │ │ │ ├── JWTTokenTextTypeDescription.m │ │ │ ├── NSArrayExtension.h │ │ │ ├── NSArrayExtension.m │ │ │ ├── SignatureValidationDescription.h │ │ │ ├── SignatureValidationDescription.m │ │ │ ├── ViewController+Model.h │ │ │ ├── ViewController+Model.m │ │ │ ├── ViewController.h │ │ │ ├── ViewController.m │ │ │ └── main.m │ │ ├── JWTDesktop.xcodeproj/ │ │ │ ├── project.pbxproj │ │ │ └── project.xcworkspace/ │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata/ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── JWTDesktopTests/ │ │ ├── Info.plist │ │ └── JWTDesktopTests.m │ ├── JWTDesktopSwift/ │ │ ├── JWTDesktopSwift/ │ │ │ ├── AppDelegate.swift │ │ │ ├── Assets.xcassets/ │ │ │ │ └── AppIcon.appiconset/ │ │ │ │ └── Contents.json │ │ │ ├── Base.lproj/ │ │ │ │ └── Main.storyboard │ │ │ ├── DecriptedCollectionViewItem.swift │ │ │ ├── DecriptedCollectionViewItem.xib │ │ │ ├── DecriptedViewController.swift │ │ │ ├── DecriptedViewController.xib │ │ │ ├── Info.plist │ │ │ ├── ViewController+Model.swift │ │ │ └── ViewController.swift │ │ └── JWTDesktopSwift.xcodeproj/ │ │ ├── project.pbxproj │ │ └── project.xcworkspace/ │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata/ │ │ └── IDEWorkspaceChecks.plist │ ├── JWTDesktopSwiftToolkit/ │ │ ├── .gitignore │ │ ├── Package.swift │ │ ├── README.md │ │ ├── Sources/ │ │ │ └── JWTDesktopSwiftToolkit/ │ │ │ ├── Array+Extension.swift │ │ │ ├── ColorBridge+Platforms.swift │ │ │ ├── FontBridge+Platforms.swift │ │ │ ├── SignatureValidationType.swift │ │ │ ├── String+Extension.swift │ │ │ ├── TokenDecoder.swift │ │ │ └── TokenTextTypeDescription.swift │ │ └── Tests/ │ │ └── JWTDesktopSwiftToolkitTests/ │ │ └── JWTDesktopSwiftToolkitTests.swift │ └── JWTSwiftUI/ │ ├── JWTSwiftUI/ │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets/ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Base.lproj/ │ │ │ └── LaunchScreen.storyboard │ │ ├── BottomView.swift │ │ ├── ContentView.swift │ │ ├── HeaderView.swift │ │ ├── Info.plist │ │ ├── JWTModel.swift │ │ ├── Preview Content/ │ │ │ └── Preview Assets.xcassets/ │ │ │ └── Contents.json │ │ └── SceneDelegate.swift │ ├── JWTSwiftUI.xcodeproj/ │ │ ├── project.pbxproj │ │ └── project.xcworkspace/ │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata/ │ │ └── IDEWorkspaceChecks.plist │ ├── MacJWTSwiftUI/ │ │ ├── Assets.xcassets/ │ │ │ ├── AccentColor.colorset/ │ │ │ │ └── Contents.json │ │ │ ├── AppIcon.appiconset/ │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── ContentView.swift │ │ ├── Info.plist │ │ ├── MacJWTSwiftUI.entitlements │ │ ├── MacJWTSwiftUIApp.swift │ │ └── Preview Content/ │ │ └── Preview Assets.xcassets/ │ │ └── Contents.json │ └── iOSJWTSwiftUI/ │ ├── Assets.xcassets/ │ │ ├── AccentColor.colorset/ │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset/ │ │ │ └── Contents.json │ │ └── Contents.json │ ├── ContentView.swift │ ├── Info.plist │ ├── Preview Content/ │ │ └── Preview Assets.xcassets/ │ │ └── Contents.json │ └── iOSJWTSwiftUIApp.swift ├── JWT.podspec ├── LICENSE ├── Package.resolved ├── Package.swift ├── README.md ├── Scripts/ │ ├── Test certificate and private key 1.p12 │ ├── Test certificate and private key 2.p12 │ ├── Test certificate and public key 1.pem │ ├── Test certificate and public key 2.pem │ ├── cert_1.cer │ ├── cert_1.crt │ ├── cert_1.csr │ ├── cert_1.p12 │ ├── ci-xcode-select.sh │ ├── generate_ec_curved_keys.rb │ ├── generate_keys.rb │ ├── openssl_help.sh │ ├── private_1.pem │ ├── private_256_right.p12 │ ├── private_256_right.pem │ ├── private_256_wrong.p12 │ ├── private_256_wrong.pem │ ├── public_256_right.pem │ ├── public_256_wrong.pem │ ├── test_cert_public_256_right.pem │ └── test_cert_public_256_wrong.pem ├── Sources/ │ └── JWT/ │ ├── Algorithms/ │ │ ├── Base/ │ │ │ ├── JWTAlgorithmErrorDescription+Subclass.m │ │ │ ├── JWTAlgorithmErrorDescription.m │ │ │ ├── JWTAlgorithmFactory.m │ │ │ └── JWTAlgorithmNone.m │ │ ├── ESFamily/ │ │ │ ├── JWTAlgorithmAsymmetricBase.m │ │ │ └── JWTAlgorithmESBase.m │ │ ├── HSFamily/ │ │ │ └── JWTAlgorithmHSBase.m │ │ ├── Holders/ │ │ │ ├── JWTAlgorithmDataHolder+FluentStyle.m │ │ │ ├── JWTAlgorithmDataHolder.m │ │ │ └── JWTAlgorithmDataHolderChain.m │ │ └── RSFamily/ │ │ ├── JWTAlgorithmRSBase.m │ │ └── RSKeys/ │ │ ├── JWTCryptoKey.m │ │ ├── JWTCryptoKeyExtractor+FluentStyle.m │ │ ├── JWTCryptoKeyExtractor.m │ │ ├── JWTCryptoSecurity+ErrorHandling.m │ │ ├── JWTCryptoSecurity+ExternalRepresentation.m │ │ ├── JWTCryptoSecurity+Extraction.m │ │ └── JWTCryptoSecurity.m │ ├── ClaimSet/ │ │ ├── JWTClaim.m │ │ ├── JWTClaimBase.m │ │ ├── JWTClaimSerializerBase.m │ │ ├── JWTClaimSerializerVariations.m │ │ ├── JWTClaimVariations.m │ │ ├── JWTClaimVerifierBase.m │ │ ├── JWTClaimVerifierVariations.m │ │ ├── JWTClaimsProviderBase.m │ │ ├── JWTClaimsSet.m │ │ ├── JWTClaimsSetBase.m │ │ ├── JWTClaimsSetCoordinatorBase.m │ │ ├── JWTClaimsSetDSLBase.m │ │ ├── JWTClaimsSetSerializer.m │ │ ├── JWTClaimsSetSerializerBase.m │ │ ├── JWTClaimsSetVerifier.m │ │ └── JWTClaimsSetVerifierBase.m │ ├── Coding/ │ │ ├── JWTBuilder+FluentStyle.m │ │ ├── JWTCoding+ResultTypes.m │ │ ├── JWTCoding+VersionOne.m │ │ ├── JWTCoding+VersionThree.m │ │ ├── JWTCoding+VersionTwo.m │ │ ├── JWTCoding.m │ │ └── JWTCodingBuilder+FluentStyle.m │ ├── Supplement/ │ │ ├── JWTBase64Coder.m │ │ └── JWTErrorDescription.m │ └── include/ │ ├── JWTAlgorithm.h │ ├── JWTAlgorithmAsymmetricBase.h │ ├── JWTAlgorithmDataHolder+FluentStyle.h │ ├── JWTAlgorithmDataHolder.h │ ├── JWTAlgorithmDataHolderChain.h │ ├── JWTAlgorithmESBase.h │ ├── JWTAlgorithmErrorDescription+Subclass.h │ ├── JWTAlgorithmErrorDescription.h │ ├── JWTAlgorithmFactory.h │ ├── JWTAlgorithmHSBase.h │ ├── JWTAlgorithmNone.h │ ├── JWTAlgorithmRSBase.h │ ├── JWTBase64Coder.h │ ├── JWTBuilder+FluentStyle.h │ ├── JWTClaim.h │ ├── JWTClaimBase.h │ ├── JWTClaimSerializerBase.h │ ├── JWTClaimSerializerVariations.h │ ├── JWTClaimVariations.h │ ├── JWTClaimVerifierBase.h │ ├── JWTClaimVerifierVariations.h │ ├── JWTClaimsProviderBase.h │ ├── JWTClaimsSet.h │ ├── JWTClaimsSetBase.h │ ├── JWTClaimsSetCoordinatorBase.h │ ├── JWTClaimsSetDSLBase.h │ ├── JWTClaimsSetSerializer.h │ ├── JWTClaimsSetSerializerBase.h │ ├── JWTClaimsSetVerifier.h │ ├── JWTClaimsSetVerifierBase.h │ ├── JWTClaimsSetsProtocols.h │ ├── JWTCoding+ResultTypes.h │ ├── JWTCoding+VersionOne.h │ ├── JWTCoding+VersionThree.h │ ├── JWTCoding+VersionTwo.h │ ├── JWTCoding.h │ ├── JWTCodingBuilder+FluentStyle.h │ ├── JWTCryptoKey.h │ ├── JWTCryptoKeyExtractor+FluentStyle.h │ ├── JWTCryptoKeyExtractor.h │ ├── JWTCryptoSecurity+ErrorHandling.h │ ├── JWTCryptoSecurity+ExternalRepresentation.h │ ├── JWTCryptoSecurity+Extraction.h │ ├── JWTCryptoSecurity.h │ ├── JWTDeprecations.h │ ├── JWTErrorDescription.h │ └── JWTRSAlgorithm.h ├── Tests/ │ └── JWTTests/ │ ├── Helpers/ │ │ └── JWTAssetAccessor.m │ ├── Resources/ │ │ ├── Certificates.xcassets/ │ │ │ ├── Contents.json │ │ │ ├── es256/ │ │ │ │ ├── Contents.json │ │ │ │ ├── certificate.cer.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── ec-prime256v1.cer │ │ │ │ ├── original.private.pem.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── ec-prime256v1-private.pem │ │ │ │ ├── original.public.pem.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── ec-prime256v1-public.pem │ │ │ │ ├── p12_password.txt.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── ec-prime256v1-p12-password.txt │ │ │ │ ├── private.p12.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── ec-prime256v1-private.p12 │ │ │ │ ├── private.pem.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── ec-prime256v1-private.pem │ │ │ │ └── public.pem.dataset/ │ │ │ │ ├── Contents.json │ │ │ │ └── ec-prime256v1-public.pem │ │ │ ├── es384/ │ │ │ │ ├── Contents.json │ │ │ │ ├── certificate.cer.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── ec-secp384r1.cer │ │ │ │ ├── original.private.pem.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── ec-secp384r1-private.pem │ │ │ │ ├── original.public.pem.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── ec-secp384r1-public.pem │ │ │ │ ├── p12_password.txt.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── ec-secp384r1-p12-password.txt │ │ │ │ ├── private.p12.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── ec-secp384r1-private.p12 │ │ │ │ ├── private.pem.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── ec-secp384r1-private.pem │ │ │ │ └── public.pem.dataset/ │ │ │ │ ├── Contents.json │ │ │ │ └── ec-secp384r1-public.pem │ │ │ ├── es512/ │ │ │ │ ├── Contents.json │ │ │ │ ├── certificate.cer.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── ec-secp521r1.cer │ │ │ │ ├── original.private.pem.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── ec-secp521r1-private.pem │ │ │ │ ├── original.public.pem.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── ec-secp521r1-public.pem │ │ │ │ ├── p12_password.txt.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── ec-secp521r1-p12-password.txt │ │ │ │ ├── private.p12.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── ec-secp521r1-private.p12 │ │ │ │ ├── private.pem.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── ec-secp521r1-private.pem │ │ │ │ └── public.pem.dataset/ │ │ │ │ ├── Contents.json │ │ │ │ └── ec-secp521r1-public.pem │ │ │ ├── rs256/ │ │ │ │ ├── Contents.json │ │ │ │ ├── certificate.cer.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── rsa-2048.cer │ │ │ │ ├── p12_password.txt.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── rsa-2048-p12-password.txt │ │ │ │ ├── private.p12.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── rsa-2048-private.p12 │ │ │ │ ├── private.pem.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── rsa-2048-private.pem │ │ │ │ └── public.pem.dataset/ │ │ │ │ ├── Contents.json │ │ │ │ └── rsa-2048-public.pem │ │ │ ├── rs256old/ │ │ │ │ ├── Contents.json │ │ │ │ ├── certificate.cer.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── rs256-cert.cer │ │ │ │ ├── p12_password.txt.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── password.txt │ │ │ │ ├── private.p12.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── rs256-private.p12 │ │ │ │ ├── private.pem.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── rs256-private.pem │ │ │ │ └── public.pem.dataset/ │ │ │ │ ├── Contents.json │ │ │ │ └── rs256-public.pem │ │ │ ├── rs384/ │ │ │ │ ├── Contents.json │ │ │ │ ├── certificate.cer.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── rsa-3072.cer │ │ │ │ ├── p12_password.txt.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── rsa-3072-p12-password.txt │ │ │ │ ├── private.p12.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── rsa-3072-private.p12 │ │ │ │ ├── private.pem.dataset/ │ │ │ │ │ ├── Contents.json │ │ │ │ │ └── rsa-3072-private.pem │ │ │ │ └── public.pem.dataset/ │ │ │ │ ├── Contents.json │ │ │ │ └── rsa-3072-public.pem │ │ │ └── rs512/ │ │ │ ├── Contents.json │ │ │ ├── certificate.cer.dataset/ │ │ │ │ ├── Contents.json │ │ │ │ └── rsa-4096.cer │ │ │ ├── p12_password.txt.dataset/ │ │ │ │ ├── Contents.json │ │ │ │ └── rsa-4096-p12-password.txt │ │ │ ├── private.p12.dataset/ │ │ │ │ ├── Contents.json │ │ │ │ └── rsa-4096-private.p12 │ │ │ ├── private.pem.dataset/ │ │ │ │ ├── Contents.json │ │ │ │ └── rsa-4096-private.pem │ │ │ └── public.pem.dataset/ │ │ │ ├── Contents.json │ │ │ └── rsa-4096-public.pem │ │ └── template/ │ │ ├── Contents.json │ │ ├── certificate.cer.dataset/ │ │ │ └── Contents.json │ │ ├── p12_password.txt.dataset/ │ │ │ └── Contents.json │ │ ├── private.p12.dataset/ │ │ │ └── Contents.json │ │ ├── private.pem.dataset/ │ │ │ └── Contents.json │ │ ├── public.pem.dataset/ │ │ │ └── Contents.json │ │ └── request.csr.dataset/ │ │ └── Contents.json │ ├── Tests/ │ │ ├── Algorithms/ │ │ │ ├── JWTAlgorithmAsymmetricTests.m │ │ │ ├── JWTAlgorithmHSTests.m │ │ │ └── JWTAlgorithmNoneTests.m │ │ ├── ClaimSet/ │ │ │ ├── JWTClaimsCustomClaimsBaseTests.m │ │ │ ├── JWTClaimsSerializerBaseTests.m │ │ │ └── JWTClaimsSerializerTests.m │ │ ├── JWT/ │ │ │ ├── JWTIssuesTests.m │ │ │ └── JWTReadmeTests.m │ │ └── JWTCoding/ │ │ └── JWTCodingTests.m │ └── include/ │ └── JWTAssetAccessor.h └── VERSION ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/CONTRIBUTING.md ================================================ # Contributing to JWT We want to make contributing to this project as easy and transparent as possible. Here are a few guidelines for making all our lives easier. ## Reporting Issues A great way to contribute to the project is to send a detailed issue when you encounter an problem. It is very important to check for the same problem or suggestion in the project's issue list first. If you find a match, just add a small comment there. Doing this helps prioritize the most common problems and requests. When reporting issues, please include the following: - The platform name and version (e.g. iOS 8.1) - The library version - The integration method (e.g. CocoaPods/Carthage/manually) - The version of Xcode you're using - The full output of any stack trace or compiler error - A small demo project that replicates the issue (especially if the way to reproduce the issue is not straight-forward) - Any other details that would be useful in understanding the problem This information will help us review and fix your issue faster. Please do not be offended if we close your issue and reference this document. If you believe the issue is truely a fault in the project’s codebase, re-open it. ## Pull Requests We gladly accept any PR's assuming they are well written, documented ( if necessary ) and preferably have test code. If you're unsure if we'll accept a new feature please open an issue requesting it and we can have a discussion before you code and submit a PR. Checklist: - Fork the repo and create your branch from the latest master (to minimize the conflicts) - If you've added code that should be tested, add tests. - If you've changed APIs, update the documentation. - Ensure the test suite passes. - Make sure your code lints (pod lib lint) ================================================ FILE: .github/ISSUE_TEMPLATE.md ================================================ ### New Issue Checklist - [ ] I have read and understood the [CONTRIBUTING guide](https://github.com/yourkarma/JWT/blob/master/.github/CONTRIBUTING.md) - [ ] I have read the [Documentation](https://github.com/yourkarma/JWT#documentation) - [ ] I have searched for a similar issue in the [project](https://github.com/yourkarma/JWT/issues) and found none ### Issue Info Info | Value | -------------------------|-------------------------------------| Platform Name | e.g. ios / osx / tvos / watchos Platform Version | e.g. 8.0 CocoaLumberjack Version | e.g. 2.3.0 Integration Method | e.g. carthage / cocoapods / manually Xcode Version | e.g. Xcode 7.3 Repro rate | e.g. all the time (100%) / sometimes x% / only once Demo project link | e.g. link to a demo project that highlights the issue ### Issue Description and Steps Please fill in the detailed description of the issue (full output of any stack trace, compiler error, ...) and the steps to reproduce the issue. ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ ### New Pull Request Checklist - [ ] I have searched for a similar pull request in the [project](https://github.com/yourkarma/JWT/pulls) and found none - [ ] I have updated this branch with the latest master to avoid conflicts (via merge from master or rebase) - [ ] I have added the required tests to prove the fix/feature I am adding - [ ] I have updated the documentation (if necessary) - [ ] I have run the tests and they pass - [ ] I have run the lint and it passes (`pod lib lint`) Before merge, please, assure that your commits are grouped. Please, don't make several PRs with single commit, group PRs into one if possible. This merge request fixes / refers to the following issues: ... ### Pull Request Description ... ================================================ FILE: .github/workflows/library-builds.yaml ================================================ name: Library Builds on: push: branches: [ ci/github_actions, master ] pull_request: branches: [ master ] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: env: LC_CTYPE: en_US.UTF-8 LANG: en_US.UTF-8 jobs: static-library: runs-on: macos-11 strategy: matrix: include: - scheme: JWT sdk: macosx destination: 'platform=macosx' - scheme: JWT sdk: iphonesimulator destination: 'platform=iOS Simulator,name=iPhone 13,OS=latest' - scheme: JWT sdk: appletvsimulator destination: 'platform=tvOS Simulator,name=Apple TV,OS=latest' - scheme: JWT sdk: watchsimulator destination: 'platform=watchOS Simulator,name=Apple Watch Series 6 - 44mm,OS=latest' steps: - uses: actions/checkout@v2 - run: gem install xcpretty --no-document - run: set -o pipefail - run: ./Scripts/ci-xcode-select.sh - run: xcodebuild clean build -scheme "${{ matrix.scheme }}" -sdk "${{ matrix.sdk }}" -destination "${{ matrix.destination }}" | xcpretty && exit ${PIPESTATUS[0]} ================================================ FILE: .github/workflows/unit-tests.yaml ================================================ name: Unit Tests on: push: branches: [ ci/github_actions, master ] pull_request: branches: [ master ] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: env: LC_CTYPE: en_US.UTF-8 LANG: en_US.UTF-8 jobs: caution: runs-on: macos-11 steps: - run: echo "Do not forget to change runs-on (os target) to macos-latest when it become latest" - run: echo "Do not forget to add macOS tests when Apple fix Apple.car catalog compilation for macOS" xcode: runs-on: macos-11 strategy: matrix: include: - scheme: JWT sdk: iphonesimulator destination: 'platform=iOS Simulator,name=iPhone 13,OS=latest' - scheme: JWT sdk: appletvsimulator destination: 'platform=tvOS Simulator,name=Apple TV,OS=latest' - scheme: JWT sdk: watchsimulator destination: 'platform=watchOS Simulator,name=Apple Watch Series 6 - 44mm,OS=latest' steps: - uses: actions/checkout@v2 - run: gem install xcpretty --no-document - run: ./Scripts/ci-xcode-select.sh - run: xcodebuild test -scheme "${{ matrix.scheme }}" -sdk "${{ matrix.sdk }}" -destination "${{ matrix.destination }}" | xcpretty && exit ${PIPESTATUS[0]} ================================================ FILE: .github/workflows/validations.yaml ================================================ name: Validations on: push: branches: [ ci/github_actions, master ] pull_request: branches: [ master ] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: jobs: validate-third-party-packages-managers: runs-on: macos-11 steps: - uses: actions/checkout@v2 - run: gem install xcpretty --no-document - run: set -o pipefail - run: swift --version - run: xcodebuild -version - run: ./Scripts/ci-xcode-select.sh # cocoapods - run: pod lib lint --allow-warnings # also add validation for spm later. ================================================ FILE: .gitignore ================================================ # Mac OS .DS_Store # Xcode # build/ *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata *.xccheckout *.moved-aside DerivedData *.hmap *.ipa *.xcuserstate # AppCode JetBrains .idea/ # rvm .ruby-version .ruby-gemset Example/**/.ruby-version Example/**/.ruby-gemset Inspection/**/.ruby-version Inspection/**/.ruby-gemset # Pods Pods/Pods.xcodeproj/xcuserdata/ Pods/ Example/**/Pods/Pods.xcodeproj/xcuserdata/ Example/**/Pods/ Inspection/**/Pods/Pods.xcodeproj/xcuserdata/ Inspection/**/Pods/ # Carthage Example/CarthageCompatibility/Carthage/ ================================================ FILE: .gitmodules ================================================ ================================================ FILE: .local_run_travis_script.sh ================================================ cat .travis.yml | perl -lne '/^script:/ ... eof() and /^\s+-/ and s/^\s+-// and print and print qx($_)' ================================================ FILE: .travis.yml ================================================ language: objective-c matrix: include: - osx_image: xcode12.5 # - osx_image: xcode8.3 before_install: # - brew update #- if brew outdated | grep -qx xctool; then brew upgrade xctool; fi # install # - rvm use 2.2.2 --install --binary --fuzzy # - gem install cocoapods --no-rdoc --no-ri --no-document --quiet - gem install xcpretty --no-document # - pod --version # - pod setup --silent > /dev/null # - pod repo update --silent - xcpretty --version - xcodebuild -version - xcodebuild -showsdks script: # 32-bit tests # - xctool -sdk iphonesimulator clean test -destination "name=iPhone 5" -find-target "JWTTests" # 64-bit tests # - xctool -sdk iphonesimulator clean test -destination "name=iPhone 5s" -find-target "JWTTests" # Thanks CocoaLumberjack! - set -o pipefail - echo Check if the library described by the podspec can be built - pod lib lint --allow-warnings # Unused. # - echo "Build as dynamic framework (ObjectiveC), each platform (osx, ios)" # - xcodebuild clean build -project Framework/JWT.xcodeproj -scheme 'JWT-macOS' -configuration Release -sdk macosx | xcpretty -c # - xcodebuild clean build -project Framework/JWT.xcodeproj -scheme 'JWT-iOS' -configuration Release -sdk iphonesimulator | xcpretty -c # - echo "Build as dynamic framework (Swift), each platform (osx, ios)" # - xcodebuild clean build -project Framework/JWT.xcodeproj -scheme 'JWT-macOS-Swift' -configuration Release -sdk macosx | xcpretty -c # - xcodebuild clean build -project Framework/JWT.xcodeproj -scheme 'JWT-iOS-Swift' -configuration Release -sdk iphonesimulator | xcpretty -c # Framework. - echo "Build dynamic universal for each platform (osx, ios)" - xcodebuild clean build -project Framework/JWT.xcodeproj -scheme 'JWT' -configuration Release -sdk macosx | xcpretty -c - xcodebuild clean build -project Framework/JWT.xcodeproj -scheme 'JWT' -configuration Release -sdk iphonesimulator | xcpretty -c - xcodebuild clean build -project Framework/JWT.xcodeproj -scheme 'JWT' -configuration Release -sdk appletvsimulator | xcpretty -c - xcodebuild clean build -project Framework/JWT.xcodeproj -scheme 'JWT' -configuration Release -sdk watchsimulator | xcpretty -c # Static Library. # We need to change order in case of xcodebuild bug. # xcodebuild does not remove static library on -clean action. # In this case # static library after framework is ok. # framework after static library is bad. # beer and wine order, heh. - echo "Build iOS Static library" - xcodebuild clean build -project Framework/JWT.xcodeproj -scheme 'JWT-Static' -configuration Release -sdk macosx | xcpretty -c - xcodebuild clean build -project Framework/JWT.xcodeproj -scheme 'JWT-Static' -configuration Release -sdk iphonesimulator | xcpretty -c - xcodebuild clean build -project Framework/JWT.xcodeproj -scheme 'JWT-Static' -configuration Release -sdk appletvsimulator | xcpretty -c - xcodebuild clean build -project Framework/JWT.xcodeproj -scheme 'JWT-Static' -configuration Release -sdk watchsimulator | xcpretty -c # Tests. - echo Run iOS Tests # 32-bit tests # TODO: Add xsimctl invocation to install iPhone 5 or 5s simulators. # - echo 32-bit tests # - xcodebuild test -project 'Tests/Tests.xcodeproj' -scheme 'iOS_Tests' -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 5,OS=latest' | xcpretty -c # # 64-bit tests - echo Run iOS 64-bit tests - xcodebuild test -project 'Tests/Tests.xcodeproj' -scheme 'iOS_Tests' -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 11,OS=latest' | xcpretty -c # mac OS tests - echo Run Mac OS tests - xcodebuild test -project 'Tests/Tests.xcodeproj' -scheme 'macOS_Tests' -sdk macosx | xcpretty -c # tvOS tests - echo Run tvOS tests - xcodebuild test -project 'Tests/Tests.xcodeproj' -scheme 'tvOS_Tests' -sdk appletvsimulator -destination 'platform=tvOS Simulator,name=Apple TV,OS=latest' | xcpretty -c # watchOS tests - echo Run watchOS tests - xcodebuild test -project 'Tests/Tests.xcodeproj' -scheme 'watchOS_Tests' -sdk watchsimulator -destination 'platform=watchOS Simulator,name=Apple Watch Series 6 - 44mm,OS=latest' ================================================ FILE: Cartfile ================================================ github "https://github.com/soheilbm/Base64.git" "Cartfile" ================================================ FILE: Cartfile.resolved ================================================ github "soheilbm/Base64" "67083ec1e3e970ec920cbf126e6957c6e9e88ae4" ================================================ FILE: Documentation/Prerelease/custom_claims.md ================================================ # Custom Claims. ## Intro. Consider the following problem. You have an integer interval and you would like to know if untrusted and trusted intervals intersection is empty or not. If they have intersection and it is not empty, then, we would like to say "yes" to untrusted value. Otherwise we treat it as malicious and discard it. In simple example, we may have ``` trustedValue // 1...5 untrustedValue // 2...6 ``` They have non-empty intersection which equals to `2...5`. ## Example Data. We may encode this special claim as two numbers that are separated by comma. Let's call our claim as "intersection". JSON for this claim `1...5` will be equal to ```json { "intersection": "1,5" } ``` ## Example. We have to define three components for our case. 1. Define a claim. 2. Define a serializer. 3. Define a verifier. ## Define a claim. ```objective-c /// Define a name of a claim. @interface JWTClaimsNames (Custom) @property (copy, nonatomic, readonly, class) NSString *intersectionOfIntervals; @end @implementation JWTClaimsNames (Custom) + (NSString *)intersectionOfIntervals { return @"intersectionOfIntervals"; } @end /// Define a claim @interface JWTClaimCustomIntersectionOfIntervals : JWTClaimBase @end @implementation JWTClaimCustomIntersectionOfIntervals + (NSString *)name { return JWTClaimsNames.intersectionOfIntervals; } @end ``` ## Define a serializer. ```objective-c /// Define a serializer @interface JWTClaimSerializerForInterval : JWTClaimSerializerBase @end @implementation JWTClaimSerializerForInterval - (NSObject *)deserializedClaimValue:(NSObject *)value forName:(NSString *)name { if ([value isKindOfClass:NSString.class]) { __auto_type array = [(NSString *)value componentsSeparatedByString:@","]; __auto_type result = [NSMutableArray array]; for (NSString *item in array) { [result addObject:@(item.integerValue)]; } __auto_type descriptor = [[NSSortDescriptor alloc] initWithKey:@"integerValue" ascending:YES]; return [result sortedArrayUsingDescriptors:@[descriptor]]; } return value; } - (NSObject *)serializedClaimValue:(id)claim { __auto_type value = claim.value; if ([value isKindOfClass:NSArray.class]) { __auto_type descriptor = [[NSSortDescriptor alloc] initWithKey:@"integerValue" ascending:YES]; __auto_type sortedArray = [(NSArray *)claim.value sortedArrayUsingDescriptors:@[descriptor]]; return [sortedArray componentsJoinedByString:@","]; } return value; } @end ``` ## Define a verifier. ```objective-c /// Define a verifier. @interface JWTClaimVerifierForIntersection : JWTClaimVerifierBase @end @implementation JWTClaimVerifierForIntersection - (BOOL)verifyValue:(NSObject *)value withTrustedValue:(NSObject *)trustedValue { if ([value isKindOfClass:NSArray.class] && [trustedValue isKindOfClass:NSArray.class]) { __auto_type lhs = (NSArray *)value; __auto_type rhs = (NSArray *)trustedValue; if (rhs.count != 2) { return NO; } if (lhs.count > 2 || lhs.count == 0) { return NO; } __auto_type lowerBorder = ((NSNumber *)rhs.firstObject).integerValue; __auto_type upperBorder = ((NSNumber *)rhs.lastObject).integerValue; if (lhs.count == 1) { __auto_type checkValue = ((NSNumber *)lhs.firstObject).integerValue; return lowerBorder <= checkValue && upperBorder >= checkValue; } if (lhs.count == 2) { __auto_type untrustedLowerBorder = ((NSNumber *)lhs.firstObject).integerValue; __auto_type untrustedUpperBorder = ((NSNumber *)lhs.lastObject).integerValue; return (untrustedLowerBorder >= lowerBorder && untrustedLowerBorder <= upperBorder) || (untrustedUpperBorder >= lowerBorder && untrustedUpperBorder <= upperBorder); } } return NO; } @end ``` ## Add DSL if needed. ```objective-c @interface JWTClaimsSetDSLBase (CustomDSL) @property (copy, nonatomic, readwrite) NSArray *intersection; @end @implementation JWTClaimsSetDSLBase (CustomDSL) - (NSArray *)intersection { return (NSArray *)[self dslValueForName:JWTClaimsNames.intersectionOfIntervals]; } - (void)setIntersection:(NSArray *)intersection { [self dslSetValue:intersection forName:JWTClaimsNames.intersectionOfIntervals]; } @end @interface JWTClaimVariations (CustomDSL) + (id)intersectionOfIntervals; @end @implementation JWTClaimVariations (CustomDSL) + (id)intersectionOfIntervals { return [JWTClaimCustomIntersectionOfIntervals new]; } @end @interface JWTClaimSerializerVariations (CustomDSL) + (id)interval; @end @implementation JWTClaimSerializerVariations (CustomDSL) + (id)interval { return [JWTClaimSerializerForInterval new]; } @end @interface JWTClaimVerifierVariations (CustomDSL) + (id)intersection; @end @implementation JWTClaimVerifierVariations (CustomDSL) + (id)intersection { return [JWTClaimVerifierForIntersection new]; } @end ``` ## Put everything together. ```objective-c - (void)test { /// Setup ClaimsSetCoordinator __auto_type claim = JWTClaimVariations.intersectionOfIntervals; __auto_type claimSerializer = JWTClaimSerializerVariations.interval; __auto_type claimVerifier = JWTClaimVerifierVariations.intersection; id claimsSetCoordinator = [JWTClaimsSetCoordinatorBase new]; [claimsSetCoordinator registerClaim:claim serializer:claimSerializer verifier:claimVerifier forClaimName:JWTClaimsNames.intersectionOfIntervals]; __auto_type deserialized = ({ claimsSetCoordinator.configureClaimsSet(^JWTClaimsSetDSLBase *(JWTClaimsSetDSLBase *claimsSetDSL) { claimsSetDSL.intersection = @[@(2), @(5)]; return claimsSetDSL; }); self.claimsSetCoordinator.claimsSetStorage; }); __auto_type serialized = ({ __auto_type dictionary = [self.claimsSetCoordinator.claimsSetSerializer dictionaryFromClaimsSet:deserialized]; dictionary; }); __auto_type result = @{ JWTClaimsNames.intersectionOfIntervals : @"2,5" }; XCTAssertEqual(serialized.count, 1); XCTAssertEqualObjects(serialized, result); } ``` ## Use with decoding and encoding. ```objective-c - (void)testEncodingAndDecodingViaCoordinator { id claimsSetCoordinator = [JWTClaimsSetCoordinatorBase new]; __auto_type claimsSetDSL = claimsSetCoordinator.dslDesrciption; // fill it claimsSetDSL.issuer = @"Facebook"; claimsSetDSL.subject = @"Token"; claimsSetDSL.audience = @"https://jwt.io"; claimsSetCoordinator.claimsSetStorage = claimsSetDSL.claimsSetStorage; // encode it __auto_type secret = @"secret"; __auto_type algorithmName = @"HS384"; __auto_type headers = @{@"custom":@"value"}; idholder = [JWTAlgorithmHSFamilyDataHolder new].algorithmName(algorithmName).secret(secret); JWTCodingResultType *result = [JWTEncodingBuilder encodeClaimsSetWithCoordinator:claimsSetCoordinator].headers(headers).addHolder(holder).result; NSString *encodedToken = result.successResult.encoded; if (result.successResult) { // handle encoded result NSLog(@"encoded result: %@", result.successResult.encoded); } else { // handle error NSLog(@"encode failed, error: %@", result.errorResult.error); } // decode it // you can set any property that you want, all properties are optional __auto_type trustedClaimsSet = claimsSetDSL.claimsSetStorage; NSNumber *options = @(JWTCodingDecodingOptionsNone); NSString *yourJwt = encodedToken; // from previous example JWTCodingResultType *decodedResult = [JWTDecodingBuilder decodeMessage:yourJwt].claimsSetCoordinator(claimsSetCoordinator).addHolder(holder).options(options).and.result; if (decodedResult.successResult) { // handle decoded result NSLog(@"decoded result: %@", decodedResult.successResult.headerAndPayloadDictionary); NSLog(@"headers: %@", decodedResult.successResult.headers); NSLog(@"payload: %@", decodedResult.successResult.payload); NSLog(@"trustedClaimsSet: %@", [claimsSetCoordinator.claimsSetSerializer dictionaryFromClaimsSet:trustedClaimsSet]); NSLog(@"decodedClaimsSet: %@", [claimsSetCoordinator.claimsSetSerializer dictionaryFromClaimsSet:decodedResult.successResult.claimsSetStorage]); } else { // handle error NSLog(@"decode failed, error: %@", decodedResult.errorResult.error); } } ``` ================================================ FILE: Example/JWTDesktop/JWTDesktop/AppDelegate.h ================================================ // // AppDelegate.h // JWTDesktop // // Created by Lobanov Dmitry on 23.05.16. // Copyright © 2016 JWT. All rights reserved. // #import @interface AppDelegate : NSObject @end ================================================ FILE: Example/JWTDesktop/JWTDesktop/AppDelegate.m ================================================ // // AppDelegate.m // JWTDesktop // // Created by Lobanov Dmitry on 23.05.16. // Copyright © 2016 JWT. All rights reserved. // #import "AppDelegate.h" @interface AppDelegate () @end @implementation AppDelegate - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { // Insert code here to initialize your application } - (void)applicationWillTerminate:(NSNotification *)aNotification { // Insert code here to tear down your application } @end ================================================ FILE: Example/JWTDesktop/JWTDesktop/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "size" : "16x16", "idiom" : "mac", "filename" : "jwt_icon_16x16.png", "scale" : "1x" }, { "idiom" : "mac", "size" : "16x16", "filename" : "jwt_icon_32x32.png", "scale" : "2x" }, { "size" : "32x32", "idiom" : "mac", "filename" : "jwt_icon_32x32.png", "scale" : "1x" }, { "idiom" : "mac", "size" : "32x32", "filename" : "jwt_icon_64x64.png", "scale" : "2x" }, { "size" : "128x128", "idiom" : "mac", "filename" : "jwt_icon_128x128.png", "scale" : "1x" }, { "idiom" : "mac", "size" : "128x128", "filename" : "jwt_icon_256x256.png", "scale" : "2x" }, { "size" : "256x256", "idiom" : "mac", "filename" : "jwt_icon_256x256.png", "scale" : "1x" }, { "size" : "256x256", "idiom" : "mac", "filename" : "jwt_icon_512x512.png", "scale" : "2x" }, { "size" : "512x512", "idiom" : "mac", "filename" : "jwt_icon_512x512.png", "scale" : "1x" }, { "size" : "512x512", "idiom" : "mac", "filename" : "jwt_icon_1024x1024.png", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/JWTDesktop/JWTDesktop/Base.lproj/Main.storyboard ================================================ Default Left to Right Right to Left Default Left to Right Right to Left ================================================ FILE: Example/JWTDesktop/JWTDesktop/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIconFile CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright Copyright © 2016 JWT. All rights reserved. NSMainStoryboardFile Main NSPrincipalClass NSApplication ================================================ FILE: Example/JWTDesktop/JWTDesktop/JWTDecriptedCollectionViewItem.h ================================================ // // JWTDecriptedCollectionViewItem.h // JWTDesktop // // Created by Lobanov Dmitry on 25.09.16. // Copyright © 2016 JWT. All rights reserved. // #import @interface JWTDecriptedCollectionViewItem : NSCollectionViewItem - (void)updateWithText:(NSString *)text; - (void)updateWithTextColor:(NSColor *)color; + (NSFont *)defaultFont; @end ================================================ FILE: Example/JWTDesktop/JWTDesktop/JWTDecriptedCollectionViewItem.m ================================================ // // JWTDecriptedCollectionViewItem.m // JWTDesktop // // Created by Lobanov Dmitry on 25.09.16. // Copyright © 2016 JWT. All rights reserved. // #import "JWTDecriptedCollectionViewItem.h" @interface JWTDecriptedCollectionViewItem () @property (unsafe_unretained) IBOutlet NSTextView *textView; @end @implementation JWTDecriptedCollectionViewItem - (void)updateWithText:(NSString *)text { self.textView.string = text; } - (void)updateWithTextColor:(NSColor *)color { self.textView.textColor = color; } - (void)viewDidLoad { [super viewDidLoad]; self.textView.font = [self.class defaultFont]; // Do view setup here. } + (NSFont *)defaultFont { return [NSFont boldSystemFontOfSize:14]; } @end ================================================ FILE: Example/JWTDesktop/JWTDesktop/JWTDecriptedCollectionViewItem.xib ================================================ ================================================ FILE: Example/JWTDesktop/JWTDesktop/JWTDecriptedViewController.h ================================================ // // JWTDecriptedViewController.h // JWTDesktop // // Created by Lobanov Dmitry on 25.09.16. // Copyright © 2016 JWT. All rights reserved. // @import Cocoa; @import JWT; @interface JWTDecriptedViewController : NSViewController @property (strong, nonatomic, readwrite) JWTBuilder *builder; @property (strong, nonatomic, readwrite) JWTCodingResultType *resultType; @end ================================================ FILE: Example/JWTDesktop/JWTDesktop/JWTDecriptedViewController.m ================================================ // // JWTDecriptedViewController.m // JWTDesktop // // Created by Lobanov Dmitry on 25.09.16. // Copyright © 2016 JWT. All rights reserved. // #import "JWTDecriptedViewController.h" #import "JWTDecriptedCollectionViewItem.h" #import "JWTTokenTextTypeDescription.h" @interface JWTDecriptedViewController () @property (weak) IBOutlet NSCollectionView *collectionView; @property (copy, nonatomic, readwrite) NSString *collectionViewItemIdentifier; @property (strong, nonatomic, readwrite) NSArray *cachedResultArray; @property (strong, nonatomic, readwrite) NSDictionary *cachedErrorDictionary; @property (assign, nonatomic, readwrite) NSInteger countOfRows; @property (strong, nonatomic, readwrite) JWTTokenTextTypeDescription *tokenDescription; @end @interface JWTDecriptedViewController (NSCollectionViewDelegateFlowLayout) @end @interface JWTDecriptedViewController (NSCollectionViewDataSource) @end @implementation JWTDecriptedViewController - (void)setupUIElements { self.collectionView.delegate = self; self.collectionView.dataSource = self; self.collectionView.minItemSize = NSZeroSize; self.collectionView.maxItemSize = NSZeroSize; [self.collectionView registerClass:[JWTDecriptedCollectionViewItem class] forItemWithIdentifier:self.collectionViewItemIdentifier]; } - (void)viewDidLoad { [super viewDidLoad]; [self setupUIElements]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reload) name:NSWindowDidResizeNotification object:nil]; } - (void)reload { [self reloadCollectionView]; } - (void)reloadCollectionView { [self.collectionView reloadData]; } - (NSString *)jsonStringWithObject:(NSDictionary *)object { if (object == nil) { return @""; } NSError *error = nil; NSData *data = [NSJSONSerialization dataWithJSONObject:object options:NSJSONWritingPrettyPrinted error:&error]; if (error != nil) { return @""; } NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; return string ?: @""; } - (void)reloadData { self.cachedResultArray = nil; self.cachedErrorDictionary = nil; if (self.resultType) { if (self.resultType.successResult) { NSDictionary *result = self.resultType.successResult.headerAndPayloadDictionary; __auto_type claimsSetStorage = self.resultType.successResult.claimsSetStorage; __auto_type serializer = [JWTClaimsSetSerializerBase new]; serializer.skipClaimsProviderLookupCheck = YES; NSDictionary *claims = [serializer dictionaryFromClaimsSet:claimsSetStorage]; self.cachedResultArray = @[ @{@"header" : result[JWTCodingResultComponents.headers] ?: @""}, @{@"payload" : result[JWTCodingResultComponents.payload] ?: @""}, @{@"claimsSet" : claims ?: @""} ]; } else { NSString *errorDescription = self.resultType.errorResult.error ? self.resultType.errorResult.error.localizedDescription : @"UnknownError! Report about it!"; self.cachedErrorDictionary = @{ @"error" : errorDescription }; } } else { NSDictionary *result = self.builder.decode; if (self.builder.jwtError != nil) { self.cachedErrorDictionary = @{ @"error" : self.builder.jwtError.localizedDescription }; } else if (result != nil) { self.cachedResultArray = @[ @{@"header" : result[@"header"] ?: @""}, @{@"payload" : result[@"payload"] ?: @""} ]; } } } - (NSInteger)countOfRows { if (self.cachedErrorDictionary) { return 1; } else if (self.cachedResultArray) { return self.cachedResultArray.count; } else { return 0; } } - (NSString *)collectionViewItemIdentifier { if (_collectionViewItemIdentifier == nil) { _collectionViewItemIdentifier = NSStringFromClass([JWTDecriptedCollectionViewItem class]); } return _collectionViewItemIdentifier; } - (void)setBuilder:(JWTBuilder *)builder { if (_builder != builder) { _builder = builder; [self reloadData]; [self reloadCollectionView]; } } - (void)setResultType:(JWTCodingResultType *)resultType { if (_resultType != resultType) { _resultType = resultType; [self reloadData]; [self reloadCollectionView]; } } - (JWTTokenTextTypeDescription *)tokenDescription { if (!_tokenDescription) { _tokenDescription = [JWTTokenTextTypeDescription new]; } return _tokenDescription; } #pragma mark - Collection Helpers. - (NSString *)textForItemAtIndexPath:(NSIndexPath *)path { NSDictionary *itemResult = nil; if (self.cachedErrorDictionary != nil) { itemResult = self.cachedErrorDictionary; } else if(self.cachedResultArray != nil) { itemResult = self.cachedResultArray[path.item]; } NSString *text = [self jsonStringWithObject:itemResult]; return text; } - (NSColor *)colorWithIndexPath:(NSIndexPath *)path { NSColor *color = nil; if (self.cachedErrorDictionary) { color = [self.tokenDescription colorForType:JWTTokenTextTypeHeader]; } else if (self.cachedResultArray) { JWTTokenTextType type = MAX(JWTTokenTextTypeDefault, MIN(path.item + 1, JWTTokenTextTypeSignature)); color = [self.tokenDescription colorForType:type]; } return color; } @end @implementation JWTDecriptedViewController (NSCollectionViewDelegateFlowLayout) - (NSSize)sizeWithText:(NSString *)text withWidth:(NSInteger)width { return NSZeroSize; } - (NSSize)collectionView:(NSCollectionView *)collectionView layout:(NSCollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { NSString *stringToDisplay = [self textForItemAtIndexPath:indexPath]; CGFloat width = collectionView.frame.size.width;//[[collectionView enclosingScrollView] bounds].size.width; NSRect estimatedSize = [stringToDisplay boundingRectWithSize:CGSizeMake(width, 10000) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{/*NSForegroundColorAttributeName : nil,*/ NSFontAttributeName : JWTDecriptedCollectionViewItem.defaultFont }]; NSInteger height = estimatedSize.size.height; NSSize size = NSMakeSize(width, height); return size; } @end @implementation JWTDecriptedViewController (NSCollectionViewDataSource) - (NSInteger)collectionView:(NSCollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { NSInteger count = self.countOfRows; return count; } - (NSInteger)numberOfSectionsInCollectionView:(NSCollectionView *)collectionView { return 1; } - (NSCollectionViewItem *)collectionView:(NSCollectionView *)collectionView itemForRepresentedObjectAtIndexPath:(NSIndexPath *)indexPath { NSCollectionViewItem *item = [collectionView makeItemWithIdentifier:self.collectionViewItemIdentifier forIndexPath:indexPath]; NSString *text = [self textForItemAtIndexPath:indexPath]; JWTDecriptedCollectionViewItem *decriptedItem = (JWTDecriptedCollectionViewItem *)item; [decriptedItem updateWithText:text]; [decriptedItem updateWithTextColor:[self colorWithIndexPath:indexPath]]; return item; } @end ================================================ FILE: Example/JWTDesktop/JWTDesktop/JWTDecriptedViewController.xib ================================================ ================================================ FILE: Example/JWTDesktop/JWTDesktop/JWTTokenDecoder.h ================================================ // // JWTTokenDecoder.h // JWTDesktop // // Created by Lobanov Dmitry on 30.10.2017. // Copyright © 2017 JWT. All rights reserved. // #import @import JWT; @protocol JWTTokenDecoderNecessaryDataObject__Protocol @property (copy, nonatomic, readonly) NSString *chosenAlgorithmName; @property (copy, nonatomic, readonly) NSString *chosenSecret; @property (copy, nonatomic, readonly) NSData *chosenSecretData; @property (assign, nonatomic, readonly) BOOL isBase64EncodedSecret; @end @protocol JWTTokenDecoderProtocol - (JWTCodingResultType *)decodeToken:(NSString *)token skipSignatureVerification:(BOOL)skipVerification necessaryDataObject:(id)object; @end @interface JWTTokenDecoder : NSObject @end ================================================ FILE: Example/JWTDesktop/JWTDesktop/JWTTokenDecoder.m ================================================ // // JWTTokenDecoder.m // JWTDesktop // // Created by Lobanov Dmitry on 30.10.2017. // Copyright © 2017 JWT. All rights reserved. // #import "JWTTokenDecoder.h" @interface JWTTokenDecoder () @property (strong, nonatomic, readwrite) JWTBuilder *builder; @property (strong, nonatomic, readwrite) JWTCodingResultType *resultType; @property (strong, nonatomic, readonly) JWTTokenDecoder *theDecoder; @end @interface JWTTokenDecoder__V2 : NSObject @end @implementation JWTTokenDecoder__V2 - (JWTCodingResultType *)decodeToken:(NSString *)token skipSignatureVerification:(BOOL)skipVerification necessaryDataObject:(id)object { NSLog(@"JWT ENCODED TOKEN: %@", token); NSString *algorithmName = [object chosenAlgorithmName]; NSLog(@"JWT Algorithm NAME: %@", algorithmName); JWTBuilder *builder = [JWTBuilder decodeMessage:token].algorithmName(algorithmName).options(@(skipVerification)); NSData *secretData = [object chosenSecretData]; NSString *secret = [object chosenSecret]; BOOL isBase64EncodedSecret = [object isBase64EncodedSecret]; if (![algorithmName isEqualToString:JWTAlgorithmNameNone]) { if (isBase64EncodedSecret && secretData) { builder.secretData(secretData); } else { builder.secret(secret); } } NSDictionary *decoded = builder.decode; NSLog(@"JWT ERROR: %@", builder.jwtError); NSLog(@"JWT DICTIONARY: %@", decoded); NSError *theError = builder.jwtError; JWTCodingResultType *resultType = theError ? [[JWTCodingResultType alloc] initWithErrorResult:[[JWTCodingResultTypeError alloc] initWithError:theError]] : nil; return resultType; } @end @interface JWTTokenDecoder__V3 : NSObject @end @implementation JWTTokenDecoder__V3 - (JWTCodingResultType *)decodeToken:(NSString *)token skipSignatureVerification:(BOOL)skipVerification necessaryDataObject:(id)object { NSLog(@"JWT ENCODED TOKEN: %@", token); NSString *algorithmName = [object chosenAlgorithmName]; NSLog(@"JWT Algorithm NAME: %@", algorithmName); NSData *secretData = [object chosenSecretData]; NSString *secret = [object chosenSecret]; BOOL isBase64EncodedSecret = [object isBase64EncodedSecret]; NSError *theError = nil; id algorithm = [JWTAlgorithmFactory algorithmByName:algorithmName]; if (!algorithm) { return nil; } id holder = nil; if ([algorithm isKindOfClass:[JWTAlgorithmRSBase class]] || [algorithm.name hasPrefix:@"RS"]) { NSError *keyError = nil; idkey = [[JWTCryptoKeyPublic alloc] initWithPemEncoded:secret parameters:nil error:&keyError]; theError = keyError; if (!theError) { holder = [JWTAlgorithmRSFamilyDataHolder new].verifyKey(key).algorithmName(algorithmName); } } else if ([algorithm isKindOfClass:[JWTAlgorithmHSBase class]]){ JWTAlgorithmHSFamilyDataHolder *aHolder = [JWTAlgorithmHSFamilyDataHolder new]; if (isBase64EncodedSecret && secretData) { aHolder.secretData(secretData); } else { aHolder.secret(secret); } holder = aHolder.algorithmName(algorithmName); } else if ([algorithm isKindOfClass:[JWTAlgorithmNone class]]) { holder = [JWTAlgorithmNoneDataHolder new]; } if (theError) { NSLog(@"JWT internalError: %@", theError); return [[JWTCodingResultType alloc] initWithErrorResult:[[JWTCodingResultTypeError alloc] initWithError:theError]]; } JWTCodingBuilder *builder = [JWTDecodingBuilder decodeMessage:token].claimsSetCoordinator([JWTClaimsSetCoordinatorBase new]).addHolder(holder).options(@(skipVerification)); JWTCodingResultType *result = builder.result; // TODO: Fix // signature is not verified well even for JWT.IO example. // it happens in case of base64 data corruption. (url encoded vs not url uncoded) NSLog(@"JWT ERROR: %@ -> %@", result.errorResult, result.errorResult.error); NSLog(@"JWT RESULT: %@ -> %@", result.successResult, result.successResult.headerAndPayloadDictionary); return result; } @end @implementation JWTTokenDecoder - (id)theDecoder { return [JWTTokenDecoder__V3 new]; } - (JWTCodingResultType *)decodeToken:(NSString *)token skipSignatureVerification:(BOOL)skipVerification necessaryDataObject:(id)object { if (!object) { return nil; } return [self.theDecoder decodeToken:token skipSignatureVerification:skipVerification necessaryDataObject:object]; } @end ================================================ FILE: Example/JWTDesktop/JWTDesktop/JWTTokenTextTypeDescription.h ================================================ // // JWTTokenTextTypeDescription.h // JWTDesktop // // Created by Lobanov Dmitry on 25.09.16. // Copyright © 2016 JWT. All rights reserved. // #import #import #import #import "NSArrayExtension.h" typedef NS_ENUM(NSInteger, JWTTokenTextType) { JWTTokenTextTypeDefault, // dot text color JWTTokenTextTypeHeader, JWTTokenTextTypePayload, JWTTokenTextTypeSignature, JWTTokenTextTypeDot }; @interface JWTTokenTextTypeAppearanceAttributes : NSObject @property (copy, nonatomic, readwrite) NSColor *color; @property (copy, nonatomic, readwrite) NSFont *font; @end @interface JWTTokenTextTypeDescription: NSObject - (NSColor *)colorForType:(JWTTokenTextType)type; - (NSFont *)font; - (NSDictionary *)encodedTextAttributesForType:(JWTTokenTextType)type; + (NSArray *)typicalSchemeComponents; @end @interface JWTTokenTextTypeSerialization: NSObject - (NSString *)textPartFromTexts:(NSArray *)texts type:(JWTTokenTextType)type; @end @interface JWTTokenTextTypeAppearance: NSObject - (NSArray *)attributesForText:(NSString *)text; - (NSAttributedString *)attributedStringForText:(NSString *)text; @end ================================================ FILE: Example/JWTDesktop/JWTDesktop/JWTTokenTextTypeDescription.m ================================================ // // JWTTokenTextTypeDescription.m // JWTDesktop // // Created by Lobanov Dmitry on 25.09.16. // Copyright © 2016 JWT. All rights reserved. // #import "JWTTokenTextTypeDescription.h" @interface JWTTokenTextTypeAppearanceAttributes () @property (copy, nonatomic, readwrite) NSString *part; @end @implementation JWTTokenTextTypeAppearanceAttributes - (instancetype)initWithColor:(NSColor *)color font:(NSFont *)font { if (self = [super init]) { self.color = color; self.font = font; } return self; } @end @interface JWTTokenTextTypeDescription () @property (strong, nonatomic, readwrite) NSDictionary *textColors; @end @implementation JWTTokenTextTypeDescription - (NSDictionary *)encodedTextAttributesForType:(JWTTokenTextType)type { return @{}; } - (NSColor *)colorForType:(JWTTokenTextType)type { switch (type) { case JWTTokenTextTypeDefault: return [NSColor blackColor]; case JWTTokenTextTypeHeader: return [NSColor redColor]; case JWTTokenTextTypePayload: return [NSColor magentaColor]; case JWTTokenTextTypeSignature: return [NSColor colorWithRed:0 green:185/255.0f blue:241/255.0f alpha:1.0f]; case JWTTokenTextTypeDot: return [NSColor blackColor]; default: return nil; } } - (NSFont *)font { return [NSFont boldSystemFontOfSize:22]; } + (NSArray *)typicalSchemeComponents { return @[ @(JWTTokenTextTypeHeader), @(JWTTokenTextTypeDot), @(JWTTokenTextTypePayload), @(JWTTokenTextTypeDot), @(JWTTokenTextTypeSignature) ]; } @end @implementation JWTTokenTextTypeSerialization - (NSString *)textPartFromTexts:(NSArray *)texts type:(JWTTokenTextType)type { NSString *result = nil; switch (type) { case JWTTokenTextTypeHeader: { return [NSArrayExtension extendedArray:texts objectAtIndex:0]; } case JWTTokenTextTypePayload: { return [NSArrayExtension extendedArray:texts objectAtIndex:1]; } case JWTTokenTextTypeSignature: { if (texts.count > 2) { return [[texts subarrayWithRange:NSMakeRange(2, texts.count - 2)] componentsJoinedByString:@"."]; } return nil; } case JWTTokenTextTypeDot: return @"."; default: return nil; } return result; } @end @interface JWTTokenTextTypeAppearance () @property (strong, nonatomic, readwrite) JWTTokenTextTypeSerialization *serialization; @property (strong, nonatomic, readwrite) JWTTokenTextTypeDescription *tokenTypeDescription; @end @implementation JWTTokenTextTypeAppearance - (instancetype)init { if (self = [super init]) { self.serialization = [JWTTokenTextTypeSerialization new]; self.tokenTypeDescription = [JWTTokenTextTypeDescription new]; } return self; } - (NSArray *)attributesForText:(NSString *)text { __auto_type texts = [text componentsSeparatedByString:@"."]; __auto_type result = [NSMutableArray array]; for (NSNumber *component in JWTTokenTextTypeDescription.typicalSchemeComponents) { __auto_type type = (JWTTokenTextType)component.integerValue; __auto_type object = [self.serialization textPartFromTexts:texts type:type]; if (object) { __auto_type color = [self.tokenTypeDescription colorForType:type]; __auto_type font = self.tokenTypeDescription.font; __auto_type component = [[JWTTokenTextTypeAppearanceAttributes alloc] initWithColor:color font:font]; component.part = object; [result addObject:component]; } } return [result copy]; } - (NSAttributedString *)attributedStringForText:(NSString *)text { __auto_type string = [NSMutableAttributedString new]; __auto_type attributes = [self attributesForText:text]; for (JWTTokenTextTypeAppearanceAttributes *attribute in attributes) { __auto_type attributes = @{ NSForegroundColorAttributeName : attribute.color, NSFontAttributeName : attribute.font }; __auto_type component = [[NSAttributedString alloc] initWithString:attribute.part attributes:attributes]; [string appendAttributedString:component]; } return [string copy]; } @end ================================================ FILE: Example/JWTDesktop/JWTDesktop/NSArrayExtension.h ================================================ // // NSArrayExtension.h // JWTDesktop // // Created by Lobanov Dmitry on 30.10.2017. // Copyright © 2017 JWT. All rights reserved. // #import @interface NSArrayExtension : NSObject + (id)extendedArray:(NSArray *)array objectAtIndex:(NSInteger)index; @end ================================================ FILE: Example/JWTDesktop/JWTDesktop/NSArrayExtension.m ================================================ // // NSArrayExtension.m // JWTDesktop // // Created by Lobanov Dmitry on 30.10.2017. // Copyright © 2017 JWT. All rights reserved. // #import "NSArrayExtension.h" @implementation NSArrayExtension + (id)extendedArray:(NSArray *)array objectAtIndex:(NSInteger)index { if (array.count) { return index >= array.count ? nil : [array objectAtIndex:index]; } return nil; } @end ================================================ FILE: Example/JWTDesktop/JWTDesktop/SignatureValidationDescription.h ================================================ // // SignatureValidationDescription.h // JWTDesktop // // Created by Lobanov Dmitry on 30.10.2017. // Copyright © 2017 JWT. All rights reserved. // #import #import typedef NS_ENUM(NSInteger, SignatureValidationType) { SignatureValidationTypeUnknown, SignatureValidationTypeValid, SignatureValidationTypeInvalid }; @interface SignatureValidationDescription : NSObject @property (assign, nonatomic, readwrite) SignatureValidationType signatureValidation; @property (assign, nonatomic, readonly) NSColor* currentColor; @property (assign, nonatomic, readonly) NSString* currentTitle; @end ================================================ FILE: Example/JWTDesktop/JWTDesktop/SignatureValidationDescription.m ================================================ // // SignatureValidationDescription.m // JWTDesktop // // Created by Lobanov Dmitry on 30.10.2017. // Copyright © 2017 JWT. All rights reserved. // #import "SignatureValidationDescription.h" #import @interface SignatureValidationDescription () - (NSColor *)colorForSignatureValidation:(SignatureValidationType)signatureValidation; - (NSString *)titleForSignatureValidation:(SignatureValidationType)signatureValidation; @end @implementation SignatureValidationDescription - (NSColor *)colorForSignatureValidation:(SignatureValidationType)signatureValidation { id result = nil; switch (signatureValidation) { case SignatureValidationTypeUnknown: { result = [NSColor darkGrayColor]; break; } case SignatureValidationTypeInvalid: { result = [NSColor redColor]; break; } case SignatureValidationTypeValid: { result = [NSColor colorWithRed:0 green:185/255.0f blue:241/255.0f alpha:1.0f]; break; } default: break; } return result; } - (NSString *)titleForSignatureValidation:(SignatureValidationType)signatureValidation { id result = nil; switch (signatureValidation) { case SignatureValidationTypeUnknown: { result = @"Signature Unknown"; break; } case SignatureValidationTypeInvalid: { result = @"Signature Invalid"; break; } case SignatureValidationTypeValid: { result = @"Signature Valid"; break; } default: break; } return result ?: @"Signature Unknown"; } - (NSColor *)currentColor { return [self colorForSignatureValidation:self.signatureValidation]; } - (NSString *)currentTitle { return [self titleForSignatureValidation:self.signatureValidation]; } @end ================================================ FILE: Example/JWTDesktop/JWTDesktop/ViewController+Model.h ================================================ // // ViewController+Model.h // JWTDesktop // // Created by Lobanov Dmitry on 30.10.2017. // Copyright © 2017 JWT. All rights reserved. // #import "ViewController.h" #import "JWTTokenTextTypeDescription.h" #import "SignatureValidationDescription.h" #import "JWTTokenDecoder.h" @interface ViewController (Model) @end @interface ViewController__Model : NSObject @property (strong, nonatomic, readwrite) JWTTokenTextTypeAppearance *tokenAppearance; @property (strong, nonatomic, readwrite) SignatureValidationDescription *signatureValidationDescription; @property (strong, nonatomic, readwrite) JWTTokenDecoder *decoder; @end @interface ViewController__Model (JWTAlgorithms) @property (strong, nonatomic, readonly) NSArray *availableAlgorithms; @property (strong, nonatomic, readonly) NSArray *availableAlgorithmsNames; @end @interface ViewController__DataSeed: NSObject @property (copy, nonatomic, readonly) NSString *algorithmName; @property (copy, nonatomic, readonly) NSString *secret; @property (copy, nonatomic, readonly) NSString *token; @end @interface ViewController__DataSeed (Create) + (instancetype)defaultDataSeed; + (instancetype)HS256; + (instancetype)RS256; + (instancetype)HS256__WithoutClaimsSet; + (instancetype)HS256__LongSecret__32; + (instancetype)RS256__Corrupted; + (instancetype)RS256__Corrupted_2; @end ================================================ FILE: Example/JWTDesktop/JWTDesktop/ViewController+Model.m ================================================ // // ViewController+Model.m // JWTDesktop // // Created by Lobanov Dmitry on 30.10.2017. // Copyright © 2017 JWT. All rights reserved. // #import "ViewController+Model.h" @import JWT; @implementation ViewController (Model) @end @implementation ViewController__Model - (instancetype)init { if (self = [super init]) { self.tokenAppearance = [JWTTokenTextTypeAppearance new]; self.signatureValidationDescription = [SignatureValidationDescription new]; self.decoder = [JWTTokenDecoder new]; } return self; } @end @implementation ViewController__Model (JWTAlgorithms) - (NSArray *)availableAlgorithms { return [JWTAlgorithmFactory algorithms]; } - (NSArray *)availableAlgorithmsNames { return [[self availableAlgorithms] valueForKey:@"name"]; } @end @interface ViewController__DataSeed () @property (copy, nonatomic, readwrite) NSString *algorithmName; @property (copy, nonatomic, readwrite) NSString *secret; @property (copy, nonatomic, readwrite) NSString *token; @end @implementation ViewController__DataSeed - (instancetype)initWithAlgorithName:(NSString *)algorithmName secret:(NSString *)secret token:(NSString *)token { self = [super init]; if (self) { self.algorithmName = algorithmName; self.secret = secret; self.token = token; } return self; } @end @implementation ViewController__DataSeed (Create) + (instancetype)template { NSString *token = @""; NSString *secret = @""; NSString *algorithmName = @""; return [[self alloc] initWithAlgorithName:(NSString *)algorithmName secret:(NSString *)secret token:(NSString *)token]; } + (instancetype)defaultDataSeed { return // [self RS256]; [self RS256__Corrupted_2]; } + (instancetype)RS256 { NSString *token = @"eyJraWQiOiJqd3RfdWF0X2tleXMiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI1MDAxIiwiaXNzIjoiQ0xNIiwiZXhwIjoxNTA4MjQ5NTU3LCJqdGkiOiI2MjcyM2E4Yi0zOTZmLTQxYmYtOTljMi02NWRkMzk2MDNiNjQifQ.Cej8RJ6e2HEU27rh_TyHZBoMI1jErmhOfSFY4SRzRoijSP628hM82XxjDX24HsKqIsK1xeeGI1yg1bed4RPhnmDGt4jAY73nqguZ1oqZ2DTcfZ5olxCXyLLaytl2XH7-62M_mFUcGj7I2mwts1DQkHWnFky2i4uJXlksHFkUg2xZoGEjVHo0bxCxgQ5yQiOpxC5VodN5rAPM3A5yMG6EijOp-dvUThjoJ4RFTGKozw_x_Qg6RLGDusNcmLIMbHasTsyZAZle6RFkwO0Sij1k6z6_xssbOl-Q57m7CeYgVHMORdzy4Smkmh-0gzeiLsGbCL4fhgdHydpIFajW-eOXMw"; NSString *secret = @"-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoPryo3IisfK3a028bwgso/CW5kB84mk6Y7rO76FxJRTWnOAla0Uf0OpIID7go4Qck66yT4/uPpiOQIR0oW0plTekkDP75EG3d/2mtzhiCtELV4F1r9b/InCN5dYYK8USNkKXgjbeVyatdUvCtokz10/ibNZ9qikgKf58qXnn2anGvpE6ded5FOUEukOjr7KSAfD0KDNYWgZcG7HZBxn/3N7ND9D0ATu2vxlJsNGOkH6WL1EmObo/QygBXzuZm5o0N0W15EXpWVbl4Ye7xqPnvc1i2DTKxNUcyhXfDbLw1ee2d9T/WU5895Ko2bQ/O/zPwUSobM3m+fPMW8kp5914kwIDAQAB-----END PUBLIC KEY-----"; NSString *algorithmName = JWTAlgorithmNameRS256; return [[self alloc] initWithAlgorithName:(NSString *)algorithmName secret:(NSString *)secret token:(NSString *)token]; } + (instancetype)HS256 { NSString *token = @"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"; NSString *secret = @"secret"; NSString *algorithmName = JWTAlgorithmNameHS256; return [[self alloc] initWithAlgorithName:(NSString *)algorithmName secret:(NSString *)secret token:(NSString *)token]; } + (instancetype)HS256__WithoutClaimsSet { NSString *token = @"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvaG9oIjoiMTIzNDU2Nzg5MCIsImhhaGEiOiJKb2huIERvZSIsIm9oaGhoaCI6dHJ1ZX0.5V2Jk3Nnaj1czth5x7ssXgy12K_Oe1Lew1yfgQokpqE"; NSString *secret = @"secret"; NSString *algorithmName = JWTAlgorithmNameHS256; return [[self alloc] initWithAlgorithName:(NSString *)algorithmName secret:(NSString *)secret token:(NSString *)token]; } + (instancetype)HS256__LongSecret__32 { NSString *token = @"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSm9obiBEb2UifQ.RbAcmsAGL1QWvoT1DUrAF-3Wwxvj8VvPHYFNEcUNog8"; NSString *secret = @"qwertyuiopasdfghjklzxcvbnm123456"; NSString *algorithmName = JWTAlgorithmNameHS256; return [[self alloc] initWithAlgorithName:(NSString *)algorithmName secret:(NSString *)secret token:(NSString *)token]; } + (instancetype)RS256__Corrupted { NSString *token = @"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.EkN-DOsnsuRjRO6BxXemmJDm3HbxrbRzXglbN2S4sOkopdU4IsDxTI8jO19W_A4K8ZPJijNLis4EZsHeY559a4DFOd50_OqgHGuERTqYZyuhtF39yxJPAjUESwxk2J5k_4zM3O-vtd1Ghyo4IbqKKSy6J9mTniYJPenn5-HIirE"; NSString *secret = @"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdlatRjRjogo3WojgGHFHYLugdUWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQsHUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5Do2kQ+X5xK9cipRgEKwIDAQAB"; NSString *algorithmName = JWTAlgorithmNameRS256; return [[self alloc] initWithAlgorithName:(NSString *)algorithmName secret:(NSString *)secret token:(NSString *)token]; } + (instancetype)RS256__Corrupted_2 { NSString *token = @"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.EkN-DOsnsuRjRO6BxXemmJDm3HbxrbRzXglbN2S4sOkopdU4IsDxTI8jO19W_A4K8ZPJijNLis4EZsHeY559a4DFOd50_OqgHGuERTqYZyuhtF39yxJPAjUESwxk2J5k_4zM3O-vtd1Ghyo4IbqKKSy6J9mTniYJPenn5-HIirE"; NSString *secret = @"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdlatRjRjogo3WojgGHFHYLugdUWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQsHUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5Do2kQ+X5xK9cipRgEKwIDAQAB"; NSString *algorithmName = JWTAlgorithmNameRS256; return [[self alloc] initWithAlgorithName:(NSString *)algorithmName secret:(NSString *)secret token:(NSString *)token]; } @end ================================================ FILE: Example/JWTDesktop/JWTDesktop/ViewController.h ================================================ // // ViewController.h // JWTDesktop // // Created by Lobanov Dmitry on 23.05.16. // Copyright © 2016 JWT. All rights reserved. // #import @interface ViewController : NSViewController @end ================================================ FILE: Example/JWTDesktop/JWTDesktop/ViewController.m ================================================ // // ViewController.m // JWTDesktop // // Created by Lobanov Dmitry on 23.05.16. // Copyright © 2016 JWT. All rights reserved. // #import "ViewController.h" @import JWT; #import "JWTTokenTextTypeDescription.h" #import "SignatureValidationDescription.h" #import "JWTDecriptedViewController.h" #import "ViewController+Model.h" @interface ViewController() @property (weak) IBOutlet NSTextField *algorithmLabel; @property (weak) IBOutlet NSPopUpButton *algorithmPopUpButton; @property (weak) IBOutlet NSTextField *secretLabel; @property (weak) IBOutlet NSTextField *secretTextField; @property (weak) IBOutlet NSButton *secretIsBase64EncodedCheckButton; @property (weak) IBOutlet NSTextField *signatureLabel; @property (weak) IBOutlet NSButton *signatureVerificationCheckButton; @property (unsafe_unretained) IBOutlet NSTextView *encodedTextView; @property (unsafe_unretained) IBOutlet NSTextView *decodedTextView; @property (weak) IBOutlet NSTableView *decodedTableView; @property (weak) IBOutlet NSView * decriptedView; @property (strong, nonatomic, readwrite) JWTDecriptedViewController *decriptedViewController; @property (weak) IBOutlet NSTextField *signatureStatusLabel; @property (strong, nonatomic, readwrite) ViewController__Model *model; @end // it catches all data from view controller @interface ViewController (JWTTokenDecoderNecessaryDataObject__Protocol) @end @implementation ViewController (JWTTokenDecoderNecessaryDataObject__Protocol) - (NSString *)chosenAlgorithmName { return [self.algorithmPopUpButton selectedItem].title; } - (NSData *)chosenSecretData { NSString *secret = [self chosenSecret]; BOOL isBase64Encoded = [self isBase64EncodedSecret]; NSData *result = nil; if (isBase64Encoded) { result = [[NSData alloc] initWithBase64EncodedString:secret options:0]; if (!result) { self.secretIsBase64EncodedCheckButton.integerValue = 0; } } return result; } - (NSString *)chosenSecret { return self.secretTextField.stringValue; } - (BOOL)isBase64EncodedSecret { return self.secretIsBase64EncodedCheckButton.integerValue == 1; } @end @implementation ViewController //func encodedTextAttributes(_ enumerate: (NSRange, [NSAttributedString.Key : Any]) -> ()) { // let textStorage = self.encodedTextView.textStorage! // let string = textStorage.string // let range = NSMakeRange(0, string.count) // if let attributedString = self.model.appearance.encodedAttributedString(text: string) { // attributedString.enumerateAttributes(in: range, options: []) { (attributes, range, bool) in // enumerate(range, attributes) // } // } //} - (void)encodedTextAttributes:(void(^)(NSRange range, NSDictionary* dictionary))block { if (!block) { return; } __auto_type textStorage = self.encodedTextView.textStorage; __auto_type string = textStorage.string; __auto_type range = NSMakeRange(0, string.length); __auto_type attributedString = [self.model.tokenAppearance attributedStringForText:string]; if (attributedString != nil) { [attributedString enumerateAttributesInRange:range options:0 usingBlock:^(NSDictionary * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) { block(range, attrs); }]; } } #pragma mark - Refresh UI - (void)refreshUI { NSTextStorage *textStorage = self.encodedTextView.textStorage; NSString *string = textStorage.string; [self encodedTextAttributes:^(NSRange range, NSDictionary *dictionary) { [textStorage setAttributes:dictionary range:range]; }]; BOOL signatureVerified = [self.model.decoder decodeToken:string skipSignatureVerification:NO necessaryDataObject:self].errorResult == nil; [self signatureReactOnVerifiedToken:signatureVerified]; __auto_type shouldSkipVerification = self.signatureVerificationCheckButton.integerValue == 1; __auto_type result = [self.model.decoder decodeToken:string skipSignatureVerification:shouldSkipVerification necessaryDataObject:self]; // will be udpated. self.decriptedViewController.resultType = result; } #pragma mark - Signature Customization - (void)signatureReactOnVerifiedToken:(BOOL)verified { SignatureValidationType type = verified ? SignatureValidationTypeValid : SignatureValidationTypeInvalid; self.model.signatureValidationDescription.signatureValidation = type; self.signatureStatusLabel.textColor = self.model.signatureValidationDescription.currentColor; self.signatureStatusLabel.stringValue = self.model.signatureValidationDescription.currentTitle; } #pragma mark - Setup - (void)setupModel { self.model = [ViewController__Model new]; } - (void)setupTop { // top label. self.algorithmLabel.stringValue = @"Algorithm"; // pop up button. [self.algorithmPopUpButton removeAllItems]; [self.algorithmPopUpButton addItemsWithTitles:self.model.availableAlgorithmsNames]; [self.algorithmPopUpButton setAction:@selector(popUpButtonValueChanged:)]; [self.algorithmPopUpButton setTarget:self]; // secretLabel self.secretLabel.stringValue = @"Secret"; // secretTextField self.secretTextField.placeholderString = @"Secret"; self.secretTextField.delegate = self; // check button self.secretIsBase64EncodedCheckButton.title = @"is Base64Encoded Secret"; self.secretIsBase64EncodedCheckButton.integerValue = NO; [self.secretIsBase64EncodedCheckButton setTarget:self]; [self.secretIsBase64EncodedCheckButton setAction:@selector(checkBoxState:)]; // skip signature verification self.signatureLabel.stringValue = @"Signature"; self.signatureVerificationCheckButton.title = @"Skip signature verification"; self.signatureVerificationCheckButton.integerValue = 0; [self.signatureVerificationCheckButton setTarget:self]; [self.signatureVerificationCheckButton setAction:@selector(checkBoxState:)]; } - (void)setupBottom { self.signatureStatusLabel.alignment = NSTextAlignmentCenter; self.signatureStatusLabel.textColor = [NSColor whiteColor]; self.signatureStatusLabel.drawsBackground = YES; self.model.signatureValidationDescription.signatureValidation = SignatureValidationTypeUnknown; self.signatureStatusLabel.textColor = self.model.signatureValidationDescription.currentColor; self.signatureStatusLabel.stringValue = self.model.signatureValidationDescription.currentTitle; } - (void)setupEncodingDecodingViews { self.encodedTextView.delegate = self; // self.decodedTextView.delegate = self; self.decodedTableView.delegate = self; self.decodedTableView.dataSource = self; //thanks! //http://stackoverflow.com/questions/7545490/how-can-i-have-the-only-column-of-my-nstableview-take-all-the-width-of-the-table NSTableView *tableView = self.decodedTableView; [tableView setColumnAutoresizingStyle:NSTableViewUniformColumnAutoresizingStyle]; [tableView.tableColumns.firstObject setResizingMask:NSTableColumnAutoresizingMask]; //AND [tableView sizeLastColumnToFit]; } - (void)setupDecorations { [self setupTop]; [self setupBottom]; } - (void)setupDecriptedViews { NSView *view = self.decriptedView; self.decriptedViewController = [JWTDecriptedViewController new]; [view addSubview:self.decriptedViewController.view]; // maybe add contstraints. } - (void)viewDidLoad { [super viewDidLoad]; [self setupModel]; [self setupDecorations]; [self setupEncodingDecodingViews]; [self setupDecriptedViews]; [self defaultDataSetup]; [self refreshUI]; // Do any additional setup after loading the view. } - (void)defaultDataSetup { ViewController__DataSeed *dataSeed = [ViewController__DataSeed defaultDataSeed]; [self defaultDataSetupWithToken:dataSeed.token secret:dataSeed.secret algorithmName:dataSeed.algorithmName]; } - (void)defaultDataSetupWithToken:(NSString *)token secret:(NSString *)secret algorithmName:(NSString *)algorithmName { if (token == nil || secret == nil || algorithmName == nil) { NSLog(@"%@ failed! one of them is nil: token:(%@) secret(%@) algorithmName:(%@)algorithm", NSStringFromSelector(_cmd), token, secret, algorithmName); return; } // token [self.encodedTextView insertText:token replacementRange:NSMakeRange(0, token.length)]; // secret self.secretTextField.stringValue = secret; // algorithm NSInteger index = [self.model.availableAlgorithmsNames indexOfObject:algorithmName]; [self.algorithmPopUpButton selectItemAtIndex:index]; } - (void)viewWillAppear { [super viewWillAppear]; NSView *view = self.decriptedView; __auto_type decriptedView = self.decriptedViewController.view; view.translatesAutoresizingMaskIntoConstraints = NO; decriptedView.translatesAutoresizingMaskIntoConstraints = NO; __auto_type constraints = @[ [decriptedView.leftAnchor constraintEqualToAnchor:view.leftAnchor], [decriptedView.rightAnchor constraintEqualToAnchor:view.rightAnchor], [decriptedView.topAnchor constraintEqualToAnchor:view.topAnchor], [decriptedView.bottomAnchor constraintEqualToAnchor:view.bottomAnchor] ]; [NSLayoutConstraint activateConstraints:constraints]; } #pragma mark - Actions - (void)popUpButtonValueChanged:(id)sender { [self refreshUI]; } -(IBAction)checkBoxState:(id)sender { // Under construction [self refreshUI]; } #pragma marrk - Delegates / - (void)controlTextDidChange:(NSNotification *)obj { if ([obj.name isEqualToString:NSControlTextDidChangeNotification]) { NSTextField *textField = (NSTextField *)obj.object; if (textField == self.secretTextField) { // refresh UI [self refreshUI]; } } } #pragma mark - EncodedTextView / - (void)textDidChange:(NSNotification *)notification { [self refreshUI]; } #pragma mark - DecodedTableView / - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView { return 4; } #pragma mark - DecodedTableView / - (BOOL)tableView:(NSTableView *)tableView isGroupRow:(NSInteger)row { return row % 2 == 0; } - (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row { // choose by row is section or not if (row % 2) { // section NSView *cell = [tableView makeViewWithIdentifier:@"Cell" owner:self]; ((NSTableCellView *)cell).textField.stringValue = @"AH"; return cell; } else { NSView *cell = [tableView makeViewWithIdentifier:@"Cell" owner:self]; ((NSTableCellView *)cell).textField.stringValue = @"OH"; // return nil; return cell; } } - (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row { // calculate height of row. // NSView * view = [tableView viewAtColumn:0 row:row makeIfNecessary:NO]; return 40; } @end ================================================ FILE: Example/JWTDesktop/JWTDesktop/main.m ================================================ // // main.m // JWTDesktop // // Created by Lobanov Dmitry on 23.05.16. // Copyright © 2016 JWT. All rights reserved. // #import int main(int argc, const char * argv[]) { return NSApplicationMain(argc, argv); } ================================================ FILE: Example/JWTDesktop/JWTDesktop.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 52; objects = { /* Begin PBXBuildFile section */ 04526B1A1CF3A2690090C5A3 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 04526B191CF3A2690090C5A3 /* AppDelegate.m */; }; 04526B1D1CF3A2690090C5A3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 04526B1C1CF3A2690090C5A3 /* main.m */; }; 04526B201CF3A2690090C5A3 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04526B1F1CF3A2690090C5A3 /* ViewController.m */; }; 04526B221CF3A2690090C5A3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 04526B211CF3A2690090C5A3 /* Assets.xcassets */; }; 04526B251CF3A2690090C5A3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 04526B231CF3A2690090C5A3 /* Main.storyboard */; }; 04526B301CF3A2690090C5A3 /* JWTDesktopTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 04526B2F1CF3A2690090C5A3 /* JWTDesktopTests.m */; }; 04701E631D97F001007A0A86 /* JWTDecriptedViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04701E611D97F001007A0A86 /* JWTDecriptedViewController.m */; }; 04701E641D97F001007A0A86 /* JWTDecriptedViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 04701E621D97F001007A0A86 /* JWTDecriptedViewController.xib */; }; 04701E681D97F0E5007A0A86 /* JWTDecriptedCollectionViewItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 04701E661D97F0E5007A0A86 /* JWTDecriptedCollectionViewItem.m */; }; 04701E691D97F0E5007A0A86 /* JWTDecriptedCollectionViewItem.xib in Resources */ = {isa = PBXBuildFile; fileRef = 04701E671D97F0E5007A0A86 /* JWTDecriptedCollectionViewItem.xib */; }; 04701E6C1D981F8C007A0A86 /* JWTTokenTextTypeDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = 04701E6B1D981F8C007A0A86 /* JWTTokenTextTypeDescription.m */; }; 0A5BC6ED1FA77232000BDAB4 /* SignatureValidationDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A5BC6EC1FA77232000BDAB4 /* SignatureValidationDescription.m */; }; 0A5BC6F01FA773A8000BDAB4 /* ViewController+Model.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A5BC6EF1FA773A8000BDAB4 /* ViewController+Model.m */; }; 0A5BC6F31FA77809000BDAB4 /* NSArrayExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A5BC6F21FA77809000BDAB4 /* NSArrayExtension.m */; }; 0A5BC6F61FA77D9D000BDAB4 /* JWTTokenDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A5BC6F51FA77D9D000BDAB4 /* JWTTokenDecoder.m */; }; 0AC0027F27865AEB002167AD /* JWT in Frameworks */ = {isa = PBXBuildFile; productRef = 0AC0027E27865AEB002167AD /* JWT */; }; DB17256DE61643E08ADC47F5 /* libPods-JWTDesktopTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 447DF4A5AF64E7BE744EEE2F /* libPods-JWTDesktopTests.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 04526B2C1CF3A2690090C5A3 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 04526B0D1CF3A2690090C5A3 /* Project object */; proxyType = 1; remoteGlobalIDString = 04526B141CF3A2690090C5A3; remoteInfo = JWTDesktop; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ 0A2D85FD22B53D4800BB4760 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 04526B151CF3A2690090C5A3 /* JWTDesktop.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JWTDesktop.app; sourceTree = BUILT_PRODUCTS_DIR; }; 04526B181CF3A2690090C5A3 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 04526B191CF3A2690090C5A3 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 04526B1C1CF3A2690090C5A3 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 04526B1E1CF3A2690090C5A3 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 04526B1F1CF3A2690090C5A3 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 04526B211CF3A2690090C5A3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 04526B241CF3A2690090C5A3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 04526B261CF3A2690090C5A3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 04526B2B1CF3A2690090C5A3 /* JWTDesktopTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JWTDesktopTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 04526B2F1CF3A2690090C5A3 /* JWTDesktopTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JWTDesktopTests.m; sourceTree = ""; }; 04526B311CF3A2690090C5A3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 04701E601D97F001007A0A86 /* JWTDecriptedViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTDecriptedViewController.h; sourceTree = ""; }; 04701E611D97F001007A0A86 /* JWTDecriptedViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JWTDecriptedViewController.m; sourceTree = ""; }; 04701E621D97F001007A0A86 /* JWTDecriptedViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = JWTDecriptedViewController.xib; sourceTree = ""; }; 04701E651D97F0E5007A0A86 /* JWTDecriptedCollectionViewItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTDecriptedCollectionViewItem.h; sourceTree = ""; }; 04701E661D97F0E5007A0A86 /* JWTDecriptedCollectionViewItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JWTDecriptedCollectionViewItem.m; sourceTree = ""; }; 04701E671D97F0E5007A0A86 /* JWTDecriptedCollectionViewItem.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = JWTDecriptedCollectionViewItem.xib; sourceTree = ""; }; 04701E6A1D981F8C007A0A86 /* JWTTokenTextTypeDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JWTTokenTextTypeDescription.h; sourceTree = ""; }; 04701E6B1D981F8C007A0A86 /* JWTTokenTextTypeDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JWTTokenTextTypeDescription.m; sourceTree = ""; }; 0A5BC6EB1FA77232000BDAB4 /* SignatureValidationDescription.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SignatureValidationDescription.h; sourceTree = ""; }; 0A5BC6EC1FA77232000BDAB4 /* SignatureValidationDescription.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SignatureValidationDescription.m; sourceTree = ""; }; 0A5BC6EE1FA773A8000BDAB4 /* ViewController+Model.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ViewController+Model.h"; sourceTree = ""; }; 0A5BC6EF1FA773A8000BDAB4 /* ViewController+Model.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "ViewController+Model.m"; sourceTree = ""; }; 0A5BC6F11FA77809000BDAB4 /* NSArrayExtension.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSArrayExtension.h; sourceTree = ""; }; 0A5BC6F21FA77809000BDAB4 /* NSArrayExtension.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NSArrayExtension.m; sourceTree = ""; }; 0A5BC6F41FA77D9D000BDAB4 /* JWTTokenDecoder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JWTTokenDecoder.h; sourceTree = ""; }; 0A5BC6F51FA77D9D000BDAB4 /* JWTTokenDecoder.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JWTTokenDecoder.m; sourceTree = ""; }; 0AC0027C27865ACA002167AD /* JWT */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = JWT; path = ../..; sourceTree = ""; }; 447DF4A5AF64E7BE744EEE2F /* libPods-JWTDesktopTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-JWTDesktopTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; B0EC4FDC2D76F5A1074A63D2 /* libPods-JWTDesktop.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-JWTDesktop.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 04526B121CF3A2690090C5A3 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 0AC0027F27865AEB002167AD /* JWT in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 04526B281CF3A2690090C5A3 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( DB17256DE61643E08ADC47F5 /* libPods-JWTDesktopTests.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 04526B0C1CF3A2690090C5A3 = { isa = PBXGroup; children = ( 0AC0027C27865ACA002167AD /* JWT */, 04526B171CF3A2690090C5A3 /* JWTDesktop */, 04526B2E1CF3A2690090C5A3 /* JWTDesktopTests */, 04526B161CF3A2690090C5A3 /* Products */, 2756B542175862D629E8ADEC /* Frameworks */, ); sourceTree = ""; }; 04526B161CF3A2690090C5A3 /* Products */ = { isa = PBXGroup; children = ( 04526B151CF3A2690090C5A3 /* JWTDesktop.app */, 04526B2B1CF3A2690090C5A3 /* JWTDesktopTests.xctest */, ); name = Products; sourceTree = ""; }; 04526B171CF3A2690090C5A3 /* JWTDesktop */ = { isa = PBXGroup; children = ( 04526B181CF3A2690090C5A3 /* AppDelegate.h */, 04526B191CF3A2690090C5A3 /* AppDelegate.m */, 04526B1E1CF3A2690090C5A3 /* ViewController.h */, 04526B1F1CF3A2690090C5A3 /* ViewController.m */, 04526B211CF3A2690090C5A3 /* Assets.xcassets */, 04526B231CF3A2690090C5A3 /* Main.storyboard */, 04526B261CF3A2690090C5A3 /* Info.plist */, 04526B1B1CF3A2690090C5A3 /* Supporting Files */, 04701E601D97F001007A0A86 /* JWTDecriptedViewController.h */, 04701E611D97F001007A0A86 /* JWTDecriptedViewController.m */, 04701E621D97F001007A0A86 /* JWTDecriptedViewController.xib */, 04701E651D97F0E5007A0A86 /* JWTDecriptedCollectionViewItem.h */, 04701E661D97F0E5007A0A86 /* JWTDecriptedCollectionViewItem.m */, 04701E671D97F0E5007A0A86 /* JWTDecriptedCollectionViewItem.xib */, 04701E6A1D981F8C007A0A86 /* JWTTokenTextTypeDescription.h */, 04701E6B1D981F8C007A0A86 /* JWTTokenTextTypeDescription.m */, 0A5BC6EB1FA77232000BDAB4 /* SignatureValidationDescription.h */, 0A5BC6EC1FA77232000BDAB4 /* SignatureValidationDescription.m */, 0A5BC6EE1FA773A8000BDAB4 /* ViewController+Model.h */, 0A5BC6EF1FA773A8000BDAB4 /* ViewController+Model.m */, 0A5BC6F11FA77809000BDAB4 /* NSArrayExtension.h */, 0A5BC6F21FA77809000BDAB4 /* NSArrayExtension.m */, 0A5BC6F41FA77D9D000BDAB4 /* JWTTokenDecoder.h */, 0A5BC6F51FA77D9D000BDAB4 /* JWTTokenDecoder.m */, ); path = JWTDesktop; sourceTree = ""; }; 04526B1B1CF3A2690090C5A3 /* Supporting Files */ = { isa = PBXGroup; children = ( 04526B1C1CF3A2690090C5A3 /* main.m */, ); name = "Supporting Files"; sourceTree = ""; }; 04526B2E1CF3A2690090C5A3 /* JWTDesktopTests */ = { isa = PBXGroup; children = ( 04526B2F1CF3A2690090C5A3 /* JWTDesktopTests.m */, 04526B311CF3A2690090C5A3 /* Info.plist */, ); path = JWTDesktopTests; sourceTree = ""; }; 2756B542175862D629E8ADEC /* Frameworks */ = { isa = PBXGroup; children = ( B0EC4FDC2D76F5A1074A63D2 /* libPods-JWTDesktop.a */, 447DF4A5AF64E7BE744EEE2F /* libPods-JWTDesktopTests.a */, ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 04526B141CF3A2690090C5A3 /* JWTDesktop */ = { isa = PBXNativeTarget; buildConfigurationList = 04526B341CF3A2690090C5A3 /* Build configuration list for PBXNativeTarget "JWTDesktop" */; buildPhases = ( 04526B111CF3A2690090C5A3 /* Sources */, 04526B121CF3A2690090C5A3 /* Frameworks */, 04526B131CF3A2690090C5A3 /* Resources */, 0A2D85FD22B53D4800BB4760 /* Embed Frameworks */, ); buildRules = ( ); dependencies = ( ); name = JWTDesktop; packageProductDependencies = ( 0AC0027E27865AEB002167AD /* JWT */, ); productName = JWTDesktop; productReference = 04526B151CF3A2690090C5A3 /* JWTDesktop.app */; productType = "com.apple.product-type.application"; }; 04526B2A1CF3A2690090C5A3 /* JWTDesktopTests */ = { isa = PBXNativeTarget; buildConfigurationList = 04526B371CF3A2690090C5A3 /* Build configuration list for PBXNativeTarget "JWTDesktopTests" */; buildPhases = ( E3FC1258955CF36F4AD3F07E /* [CP] Check Pods Manifest.lock */, 04526B271CF3A2690090C5A3 /* Sources */, 04526B281CF3A2690090C5A3 /* Frameworks */, 04526B291CF3A2690090C5A3 /* Resources */, ); buildRules = ( ); dependencies = ( 04526B2D1CF3A2690090C5A3 /* PBXTargetDependency */, ); name = JWTDesktopTests; productName = JWTDesktopTests; productReference = 04526B2B1CF3A2690090C5A3 /* JWTDesktopTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 04526B0D1CF3A2690090C5A3 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 1250; ORGANIZATIONNAME = JWT; TargetAttributes = { 04526B141CF3A2690090C5A3 = { CreatedOnToolsVersion = 7.3.1; }; 04526B2A1CF3A2690090C5A3 = { CreatedOnToolsVersion = 7.3.1; TestTargetID = 04526B141CF3A2690090C5A3; }; }; }; buildConfigurationList = 04526B101CF3A2690090C5A3 /* Build configuration list for PBXProject "JWTDesktop" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 04526B0C1CF3A2690090C5A3; productRefGroup = 04526B161CF3A2690090C5A3 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 04526B141CF3A2690090C5A3 /* JWTDesktop */, 04526B2A1CF3A2690090C5A3 /* JWTDesktopTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 04526B131CF3A2690090C5A3 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 04526B221CF3A2690090C5A3 /* Assets.xcassets in Resources */, 04701E641D97F001007A0A86 /* JWTDecriptedViewController.xib in Resources */, 04701E691D97F0E5007A0A86 /* JWTDecriptedCollectionViewItem.xib in Resources */, 04526B251CF3A2690090C5A3 /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; 04526B291CF3A2690090C5A3 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ E3FC1258955CF36F4AD3F07E /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-JWTDesktopTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 04526B111CF3A2690090C5A3 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 04526B201CF3A2690090C5A3 /* ViewController.m in Sources */, 0A5BC6ED1FA77232000BDAB4 /* SignatureValidationDescription.m in Sources */, 0A5BC6F61FA77D9D000BDAB4 /* JWTTokenDecoder.m in Sources */, 04526B1D1CF3A2690090C5A3 /* main.m in Sources */, 0A5BC6F31FA77809000BDAB4 /* NSArrayExtension.m in Sources */, 04526B1A1CF3A2690090C5A3 /* AppDelegate.m in Sources */, 0A5BC6F01FA773A8000BDAB4 /* ViewController+Model.m in Sources */, 04701E6C1D981F8C007A0A86 /* JWTTokenTextTypeDescription.m in Sources */, 04701E631D97F001007A0A86 /* JWTDecriptedViewController.m in Sources */, 04701E681D97F0E5007A0A86 /* JWTDecriptedCollectionViewItem.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 04526B271CF3A2690090C5A3 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 04526B301CF3A2690090C5A3 /* JWTDesktopTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 04526B2D1CF3A2690090C5A3 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 04526B141CF3A2690090C5A3 /* JWTDesktop */; targetProxy = 04526B2C1CF3A2690090C5A3 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ 04526B231CF3A2690090C5A3 /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 04526B241CF3A2690090C5A3 /* Base */, ); name = Main.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 04526B321CF3A2690090C5A3 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; }; name = Debug; }; 04526B331CF3A2690090C5A3 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; }; name = Release; }; 04526B351CF3A2690090C5A3 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "-"; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = JWTDesktop/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.io.jwt.JWTDesktop; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 04526B361CF3A2690090C5A3 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "-"; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = JWTDesktop/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.io.jwt.JWTDesktop; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; 04526B381CF3A2690090C5A3 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = JWTDesktopTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.io.jwt.JWTDesktopTests; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/JWTDesktop.app/Contents/MacOS/JWTDesktop"; }; name = Debug; }; 04526B391CF3A2690090C5A3 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = JWTDesktopTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.io.jwt.JWTDesktopTests; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/JWTDesktop.app/Contents/MacOS/JWTDesktop"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 04526B101CF3A2690090C5A3 /* Build configuration list for PBXProject "JWTDesktop" */ = { isa = XCConfigurationList; buildConfigurations = ( 04526B321CF3A2690090C5A3 /* Debug */, 04526B331CF3A2690090C5A3 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 04526B341CF3A2690090C5A3 /* Build configuration list for PBXNativeTarget "JWTDesktop" */ = { isa = XCConfigurationList; buildConfigurations = ( 04526B351CF3A2690090C5A3 /* Debug */, 04526B361CF3A2690090C5A3 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 04526B371CF3A2690090C5A3 /* Build configuration list for PBXNativeTarget "JWTDesktopTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 04526B381CF3A2690090C5A3 /* Debug */, 04526B391CF3A2690090C5A3 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ 0AC0027E27865AEB002167AD /* JWT */ = { isa = XCSwiftPackageProductDependency; productName = JWT; }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 04526B0D1CF3A2690090C5A3 /* Project object */; } ================================================ FILE: Example/JWTDesktop/JWTDesktop.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Example/JWTDesktop/JWTDesktop.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: Example/JWTDesktop/JWTDesktopTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Example/JWTDesktop/JWTDesktopTests/JWTDesktopTests.m ================================================ // // JWTDesktopTests.m // JWTDesktopTests // // Created by Lobanov Dmitry on 23.05.16. // Copyright © 2016 JWT. All rights reserved. // #import @interface JWTDesktopTests : XCTestCase @end @implementation JWTDesktopTests - (void)setUp { [super setUp]; // Put setup code here. This method is called before the invocation of each test method in the class. } - (void)tearDown { // Put teardown code here. This method is called after the invocation of each test method in the class. [super tearDown]; } - (void)testExample { // This is an example of a functional test case. // Use XCTAssert and related functions to verify your tests produce the correct results. } - (void)testPerformanceExample { // This is an example of a performance test case. [self measureBlock:^{ // Put the code you want to measure the time of here. }]; } @end ================================================ FILE: Example/JWTDesktopSwift/JWTDesktopSwift/AppDelegate.swift ================================================ // // AppDelegate.swift // JWTDesktopSwift // // Created by Lobanov Dmitry on 01.10.16. // Copyright © 2016 JWTIO. All rights reserved. // import Cocoa @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ aNotification: Notification) { // Insert code here to initialize your application } func applicationWillTerminate(_ aNotification: Notification) { // Insert code here to tear down your application } } ================================================ FILE: Example/JWTDesktopSwift/JWTDesktopSwift/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "size" : "16x16", "idiom" : "mac", "filename" : "swift_jwt_icon_16x16.png", "scale" : "1x" }, { "idiom" : "mac", "size" : "16x16", "filename" : "swift_jwt_icon_32x32.png", "scale" : "2x" }, { "size" : "32x32", "idiom" : "mac", "filename" : "swift_jwt_icon_32x32.png", "scale" : "1x" }, { "idiom" : "mac", "size" : "32x32", "filename" : "swift_jwt_icon_64x64.png", "scale" : "2x" }, { "size" : "128x128", "idiom" : "mac", "filename" : "swift_jwt_icon_128x128.png", "scale" : "1x" }, { "idiom" : "mac", "size" : "128x128", "filename" : "swift_jwt_icon_256x256.png", "scale" : "2x" }, { "size" : "256x256", "idiom" : "mac", "filename" : "swift_jwt_icon_256x256.png", "scale" : "1x" }, { "size" : "256x256", "idiom" : "mac", "filename" : "swift_jwt_icon_512x512.png", "scale" : "2x" }, { "size" : "512x512", "idiom" : "mac", "filename" : "swift_jwt_icon_512x512.png", "scale" : "1x" }, { "size" : "512x512", "idiom" : "mac", "filename" : "swift_jwt_icon_1024x1024.png", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/JWTDesktopSwift/JWTDesktopSwift/Base.lproj/Main.storyboard ================================================ Default Left to Right Right to Left Default Left to Right Right to Left ================================================ FILE: Example/JWTDesktopSwift/JWTDesktopSwift/DecriptedCollectionViewItem.swift ================================================ // // DecriptedCollectionViewItem.swift // JWTDesktopSwift // // Created by Lobanov Dmitry on 01.10.16. // Copyright © 2016 JWTIO. All rights reserved. // import Cocoa class DecriptedCollectionViewItem: NSCollectionViewItem { @IBOutlet var textView: NSTextView! override func viewDidLoad() { super.viewDidLoad() // Do view setup here. } func update(text: String) { self.textView.string = text } func update(textColor: NSColor) { self.textView.textColor = textColor } } ================================================ FILE: Example/JWTDesktopSwift/JWTDesktopSwift/DecriptedCollectionViewItem.xib ================================================ ================================================ FILE: Example/JWTDesktopSwift/JWTDesktopSwift/DecriptedViewController.swift ================================================ // // DecriptedViewController.swift // JWTDesktopSwift // // Created by Lobanov Dmitry on 01.10.16. // Copyright © 2016 JWTIO. All rights reserved. // import Cocoa import JWT import JWTDesktopSwiftToolkit //import JW class DecriptedViewController: NSViewController { // MARK: - Outlets @IBOutlet weak var collectionView: NSCollectionView! // MARK: - CollectionView Convenients let collectionViewItemIdentifier = NSUserInterfaceItemIdentifier(NSStringFromClass(DecriptedCollectionViewItem.self)) // MARK: - Builder var builder : JWTBuilder? { didSet { self.reloadData() self.reloadCollectionView() } } // MARK: - ResultType var resultType: JWTCodingResultType? { didSet { self.reloadData() self.reloadCollectionView() } } // MARK: - Cached vars var cachedResultArray : [[String: Any]]? var cachedErrorDictionary : [String: String]? // MARK: - Texts vars var errorText: String { return String.json(cachedErrorDictionary) } var headerText: String { return String.json(cachedResultArray?[0]) } var payloadText: String { return String.json(cachedResultArray?[1]) } // MARK: - Setup func setupUIElements() { self.collectionView.delegate = self self.collectionView.dataSource = self self.collectionView.minItemSize = NSZeroSize self.collectionView.maxItemSize = NSZeroSize self.collectionView.register(DecriptedCollectionViewItem.self, forItemWithIdentifier: self.collectionViewItemIdentifier) } override func viewDidLoad() { super.viewDidLoad() self.setupUIElements() NotificationCenter.default.addObserver(self, selector: #selector(DecriptedViewController.reload), name: NSWindow.didResizeNotification, object: nil) } // MARK: - Reload @objc func reload() { reloadCollectionView() } func reloadCollectionView() { self.collectionView.reloadData() } func reloadData() { self.cachedResultArray = nil self.cachedErrorDictionary = nil if let resultType = self.resultType { if let successResult = resultType.successResult, let dictionary = successResult.headerAndPayloadDictionary { let serializer = JWTClaimsSetSerializerBase.init() serializer.skipClaimsProviderLookupCheck = true let value = successResult.claimsSetStorage.flatMap(serializer.dictionary) self.cachedResultArray = [ ["header" : dictionary[JWTCodingResultComponents.headers!] ?? ""], ["payload": dictionary[JWTCodingResultComponents.payload!] ?? ""], ["claims": value ?? ""] ] } else { let errorDescription = resultType.errorResult?.error?.localizedDescription ?? "UnknownError! Report about it!" self.cachedErrorDictionary = [ "error" : errorDescription ] } } else { let result = self.builder?.decode if let error = self.builder?.jwtError { self.cachedErrorDictionary = [ "Error" : error.localizedDescription ] } else if let dictionary = result { self.cachedResultArray = [ ["header" : dictionary["header"] ?? ""], ["payload" : dictionary["payload"] ?? ""] ] } } } // MARK: - Collection Helpers. func textForItem(indexPath: IndexPath) -> String { var text : String = "" if self.cachedErrorDictionary != nil { text = self.errorText } else if self.cachedResultArray != nil { text = String.json(cachedResultArray?[indexPath.item]) } return text } func color(indexPath: IndexPath) -> NSColor { var color = NSColor.black if self.cachedErrorDictionary != nil { color = TokenTextType.header.color } else if (self.cachedResultArray != nil) { color = (indexPath.item == 0 ? TokenTextType.header : TokenTextType.payload).color } return color } } extension DecriptedViewController { func countOfItems() -> Int { if self.cachedErrorDictionary != nil { return 1 } else if let array = self.cachedResultArray { return array.count } else { return 0 } } } extension DecriptedViewController : NSCollectionViewDelegateFlowLayout { func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize { let stringToDisplay = self.textForItem(indexPath: indexPath) let width = collectionView.frame.size.width let estimatedSize = (stringToDisplay as NSString).boundingRect(with: CGSize(width:width, height: 10000), options: [NSString.DrawingOptions.usesLineFragmentOrigin, NSString.DrawingOptions.usesFontLeading], attributes: nil) let height = estimatedSize.size.height let size = CGSize(width:width, height:height) return size } } extension DecriptedViewController : NSCollectionViewDataSource { func numberOfSections(in collectionView: NSCollectionView) -> Int { return 1 } func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int { return self.countOfItems() } func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem { let item = collectionView.makeItem(withIdentifier: self.collectionViewItemIdentifier, for: indexPath) let decriptedItem = item as! DecriptedCollectionViewItem; decriptedItem.update(text: self.textForItem(indexPath: indexPath)) decriptedItem.update(textColor: self.color(indexPath: indexPath)) return item; } } ================================================ FILE: Example/JWTDesktopSwift/JWTDesktopSwift/DecriptedViewController.xib ================================================ ================================================ FILE: Example/JWTDesktopSwift/JWTDesktopSwift/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIconFile CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleVersion 1 LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright Copyright © 2016 JWTIO. All rights reserved. NSMainStoryboardFile Main NSPrincipalClass NSApplication DEPLOYMENT_RUNTIME_SWIFT $(DEPLOYMENT_RUNTIME_SWIFT) ================================================ FILE: Example/JWTDesktopSwift/JWTDesktopSwift/ViewController+Model.swift ================================================ // // ViewController+Model.swift // JWTDesktopSwift // // Created by Lobanov Dmitry on 30.10.2017. // Copyright © 2017 JWTIO. All rights reserved. // import Foundation import JWT import JWTDesktopSwiftToolkit extension ViewController { class Model { var appearance: TokenTextAppearance = .init() var decoder: TokenDecoder = .init() var signatureValidation: SignatureValidationType = .unknown } enum DataSeedType { case hs256 case rs256 struct DataSeed { var algorithmName: String var secret: String var token: String } var dataSeed: DataSeed { switch self { case .hs256: let algorithmName = JWTAlgorithmNameHS256 let secret = "secret" let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ" return .init(algorithmName: algorithmName, secret: secret, token: token) case .rs256: let algorithmName = JWTAlgorithmNameRS256 let secret = "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoPryo3IisfK3a028bwgso/CW5kB84mk6Y7rO76FxJRTWnOAla0Uf0OpIID7go4Qck66yT4/uPpiOQIR0oW0plTekkDP75EG3d/2mtzhiCtELV4F1r9b/InCN5dYYK8USNkKXgjbeVyatdUvCtokz10/ibNZ9qikgKf58qXnn2anGvpE6ded5FOUEukOjr7KSAfD0KDNYWgZcG7HZBxn/3N7ND9D0ATu2vxlJsNGOkH6WL1EmObo/QygBXzuZm5o0N0W15EXpWVbl4Ye7xqPnvc1i2DTKxNUcyhXfDbLw1ee2d9T/WU5895Ko2bQ/O/zPwUSobM3m+fPMW8kp5914kwIDAQAB-----END PUBLIC KEY-----" let token = "eyJraWQiOiJqd3RfdWF0X2tleXMiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI1MDAxIiwiaXNzIjoiQ0xNIiwiZXhwIjoxNTA4MjQ5NTU3LCJqdGkiOiI2MjcyM2E4Yi0zOTZmLTQxYmYtOTljMi02NWRkMzk2MDNiNjQifQ.Cej8RJ6e2HEU27rh_TyHZBoMI1jErmhOfSFY4SRzRoijSP628hM82XxjDX24HsKqIsK1xeeGI1yg1bed4RPhnmDGt4jAY73nqguZ1oqZ2DTcfZ5olxCXyLLaytl2XH7-62M_mFUcGj7I2mwts1DQkHWnFky2i4uJXlksHFkUg2xZoGEjVHo0bxCxgQ5yQiOpxC5VodN5rAPM3A5yMG6EijOp-dvUThjoJ4RFTGKozw_x_Qg6RLGDusNcmLIMbHasTsyZAZle6RFkwO0Sij1k6z6_xssbOl-Q57m7CeYgVHMORdzy4Smkmh-0gzeiLsGbCL4fhgdHydpIFajW-eOXMw" return .init(algorithmName: algorithmName, secret: secret, token: token) } } } } // JWT extension ViewController.Model { var availableAlgorithms: [JWTAlgorithm] { JWTAlgorithmFactory.algorithms } var availableAlgorithmsNames: [String] { self.availableAlgorithms.map(\.name) } } ================================================ FILE: Example/JWTDesktopSwift/JWTDesktopSwift/ViewController.swift ================================================ // // ViewController.swift // JWTDesktopSwift // // Created by Lobanov Dmitry on 01.10.16. // Copyright © 2016 JWTIO. All rights reserved. // import Cocoa import JWT import JWTDesktopSwiftToolkit // MARK: - Supply JWT Methods extension ViewController { func tokenDataTransferObject() -> TokenDecoder.DataTransferObject { let algorithmName = self.algorithmPopUpButton.selectedItem?.title ?? "" let secret = self.secretTextField.stringValue let secretData: Data? = self.getSecretData let isBase64EncodedSecret = self.secretIsBase64EncodedCheckButton.integerValue == 1 let shouldSkipSignatureVerification = self.signatureVerificationCheckButton.integerValue == 1 return .init(algorithmName: algorithmName, secret: secret, secretData: secretData, isBase64EncodedSecret: isBase64EncodedSecret, shouldSkipSignatureVerification: shouldSkipSignatureVerification) } func tokenDataTransferObjectShouldCheckSignature() -> TokenDecoder.DataTransferObject { var result = self.tokenDataTransferObject() result.shouldSkipSignatureVerification = false return result } var getSecretData: Data? { let secret = self.secretTextField.stringValue let isBase64Encoded = self.secretIsBase64EncodedCheckButton.integerValue == 1 guard let result = Data(base64Encoded: secret), isBase64Encoded else { self.secretIsBase64EncodedCheckButton.integerValue = 0 return nil } return result } } // Refresh UI extension ViewController { // MARK: - Encoded Text View func encodedTextAttributes(_ enumerate: (NSRange, [NSAttributedString.Key : Any]) -> ()) { let textStorage = self.encodedTextView.textStorage! let string = textStorage.string let range = NSMakeRange(0, string.count) if let attributedString = self.model.appearance.encodedAttributedString(text: string) { attributedString.enumerateAttributes(in: range, options: []) { (attributes, range, bool) in enumerate(range, attributes) } } } // MARK: - Refresh UI func refreshUI() { let textStorage = self.encodedTextView.textStorage!; let string = textStorage.string self.encodedTextAttributes { (range, attributes) in textStorage.setAttributes(attributes, range: range) } // We should add an option to skip verification in decoding section. // invalid signature doesn't mean that you can't decode JWT. if let jwtVerified = self.model.decoder.decode(token: string, object: self.tokenDataTransferObjectShouldCheckSignature()) { let notVerified = jwtVerified.successResult?.headerAndPayloadDictionary?.isEmpty == true self.signatureReactOnVerifiedToken(verified: !notVerified) } else { self.signatureReactOnVerifiedToken(verified: false) } let result = self.model.decoder.decode(token: string, object: self.tokenDataTransferObject()) self.decriptedViewController.resultType = result } func refreshSignature() { self.signatureStatusLabel.backgroundColor = self.model.signatureValidation.color self.signatureStatusLabel.stringValue = self.model.signatureValidation.title } } // MARK: - Actions extension ViewController { @objc func popUpButtonValueChanged(sender : AnyClass) { self.refreshUI() } @objc func checkBoxState(sender : AnyClass) { self.refreshUI() } func signatureReactOnVerifiedToken(verified: Bool) { self.model.signatureValidation = verified ? .valid : .invalid self.refreshSignature() } } extension ViewController: NSTextFieldDelegate { func controlTextDidChange(_ obj: Notification) { if (obj.name == NSControl.textDidChangeNotification) { let textField = obj.object as! NSTextField if textField == self.secretTextField { self.refreshUI() } } } } extension ViewController: NSTextViewDelegate { func textDidChange(_ notification: Notification) { self.refreshUI() } // func textViewDidChangeTypingAttributes(_ notification: Notification) { // self.updateEncodedTextAttributes() // } // func textView(_ textView: NSTextView, shouldChangeTypingAttributes oldTypingAttributes: [String : Any] = [:], toAttributes newTypingAttributes: [NSAttributedString.Key : Any] = [:]) -> [NSAttributedString.Key : Any] { // return newTypingAttributes // } // func textView(_ textView: NSTextView, shouldChangeTextIn affectedCharRange: NSRange, replacementString: String?) -> Bool { // if (textView == self.encodedTextView) { //// if let textStore = textView.textStorage { //// textView.undoManager?.beginUndoGrouping() //// textStore.replaceCharacters(in: affectedCharRange, with: replacementString!) //// self.encodedTextAttributes { (range, attributes) in //// textStore.setAttributes(attributes, range: range) //// } //// textView.undoManager?.endUndoGrouping() //// } //// self.refreshUI() // return true // } // return false // } } // MARK: - EncodingTextViewDelegate //extension ViewController : NSTextViewDelegate { // func textView(_ textView: NSTextView, shouldChangeTextIn affectedCharRange: NSRange, replacementString: String?) -> Bool { // if (textView == self.encodedTextView) { // if let textStore = textView.textStorage { // textStore.replaceCharacters(in: affectedCharRange, with: replacementString!) // } // self.refreshUI() // return false // } // return false // } //} class ViewController: NSViewController { override init(nibName nibNameOrNil: NSNib.Name?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) } required init?(coder: NSCoder) { super.init(coder: coder) } // MARK: - Properties - Outlets @IBOutlet weak var algorithmLabel : NSTextField! @IBOutlet weak var algorithmPopUpButton : NSPopUpButton! @IBOutlet weak var secretLabel : NSTextField! @IBOutlet weak var secretTextField : NSTextField! @IBOutlet weak var secretIsBase64EncodedCheckButton : NSButton! @IBOutlet weak var signatureLabel : NSTextField! @IBOutlet weak var signatureVerificationCheckButton : NSButton! @IBOutlet weak var encodedTextView : NSTextView! @IBOutlet weak var decriptedView : NSView! var decriptedViewController : DecriptedViewController! @IBOutlet weak var signatureStatusLabel : NSTextField! // MARK: - Model var model: Model! // MARK: - Setup func setupModel() { self.model = Model() } func setupTop() { // top label. self.algorithmLabel.stringValue = "Algorithm"; // pop up button. self.algorithmPopUpButton.removeAllItems() self.algorithmPopUpButton.addItems(withTitles: self.model.availableAlgorithmsNames) self.algorithmPopUpButton.target = self self.algorithmPopUpButton.action = #selector(ViewController.popUpButtonValueChanged(sender:)) // secretLabel self.secretLabel.stringValue = "Secret" // secretTextField self.secretTextField.placeholderString = "Secret" self.secretTextField.delegate = self // check button self.secretIsBase64EncodedCheckButton.title = "is Base64Encoded Secret" self.secretIsBase64EncodedCheckButton.integerValue = 0 self.secretIsBase64EncodedCheckButton.target = self self.secretIsBase64EncodedCheckButton.action = #selector(ViewController.checkBoxState(sender:)) // signatureLabel self.signatureLabel.stringValue = "Signature" // signatureVerificationCheckButton self.signatureVerificationCheckButton.title = "Skip signature verification" self.signatureVerificationCheckButton.integerValue = 0 self.signatureVerificationCheckButton.target = self self.signatureVerificationCheckButton.action = #selector(ViewController.checkBoxState(sender:)) } func setupBottom() { self.signatureStatusLabel.alignment = .center self.signatureStatusLabel.textColor = NSColor.white self.signatureStatusLabel.drawsBackground = true self.refreshSignature() } func setupEncodingDecodingViews() { self.encodedTextView.delegate = self; } func setupDecorations() { self.setupTop() self.setupBottom() } func setupDecriptedViews() { let view = self.decriptedView self.decriptedViewController = DecriptedViewController() view?.addSubview(self.decriptedViewController.view) } override func viewDidLoad() { super.viewDidLoad() self.setupModel() self.setupDecorations() self.setupEncodingDecodingViews() self.setupDecriptedViews() self.defaultDataSetup() } func defaultDataSetup(algorithmName: String, secret: String, token: String) { // algorithm HS256 if let index = self.model.availableAlgorithmsNames.firstIndex(where: { $0 == algorithmName }) { self.algorithmPopUpButton.selectItem(at: index) } // secret self.secretTextField.stringValue = secret // token var range = NSRange() range.location = 0 range.length = token.count self.encodedTextView.insertText(token, replacementRange: range) } func defaultDataSetup() { let seed: DataSeedType = .hs256 let seedValue = seed.dataSeed self.defaultDataSetup(algorithmName: seedValue.algorithmName, secret: seedValue.secret, token: seedValue.token) } override func viewWillAppear() { super.viewWillAppear() guard let view = self.decriptedView else { return } let subview = self.decriptedViewController.view view.translatesAutoresizingMaskIntoConstraints = false subview.translatesAutoresizingMaskIntoConstraints = false let constraints = [ subview.leftAnchor.constraint(equalTo: view.leftAnchor), subview.rightAnchor.constraint(equalTo: view.rightAnchor), subview.topAnchor.constraint(equalTo: view.topAnchor), subview.bottomAnchor.constraint(equalTo: view.bottomAnchor) ] NSLayoutConstraint.activate(constraints) } } ================================================ FILE: Example/JWTDesktopSwift/JWTDesktopSwift.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 52; objects = { /* Begin PBXBuildFile section */ 044CFDC31DA1735B005B1D7A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 044CFDC21DA1735B005B1D7A /* Assets.xcassets */; }; 04A74B711DA00D840030DDE6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04A74B701DA00D830030DDE6 /* AppDelegate.swift */; }; 04A74B731DA00D840030DDE6 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04A74B721DA00D840030DDE6 /* ViewController.swift */; }; 04A74B781DA00D840030DDE6 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 04A74B761DA00D840030DDE6 /* Main.storyboard */; }; 04A74B801DA00F340030DDE6 /* DecriptedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04A74B7F1DA00F340030DDE6 /* DecriptedViewController.swift */; }; 04A74B831DA00F4F0030DDE6 /* DecriptedCollectionViewItem.xib in Resources */ = {isa = PBXBuildFile; fileRef = 04A74B811DA00F4F0030DDE6 /* DecriptedCollectionViewItem.xib */; }; 04A74B841DA00F4F0030DDE6 /* DecriptedViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 04A74B821DA00F4F0030DDE6 /* DecriptedViewController.xib */; }; 04A74B881DA0195B0030DDE6 /* DecriptedCollectionViewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04A74B871DA0195B0030DDE6 /* DecriptedCollectionViewItem.swift */; }; 0A5BC6FE1FA7B214000BDAB4 /* ViewController+Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A5BC6FD1FA7B214000BDAB4 /* ViewController+Model.swift */; }; 0AC0027A27865A64002167AD /* JWTDesktopSwiftToolkit in Frameworks */ = {isa = PBXBuildFile; productRef = 0AC0027927865A64002167AD /* JWTDesktopSwiftToolkit */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 044CFDC21DA1735B005B1D7A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 04A74B6D1DA00D830030DDE6 /* JWTDesktopSwift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JWTDesktopSwift.app; sourceTree = BUILT_PRODUCTS_DIR; }; 04A74B701DA00D830030DDE6 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 04A74B721DA00D840030DDE6 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 04A74B771DA00D840030DDE6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 04A74B791DA00D840030DDE6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 04A74B7F1DA00F340030DDE6 /* DecriptedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DecriptedViewController.swift; sourceTree = ""; }; 04A74B811DA00F4F0030DDE6 /* DecriptedCollectionViewItem.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DecriptedCollectionViewItem.xib; sourceTree = ""; }; 04A74B821DA00F4F0030DDE6 /* DecriptedViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DecriptedViewController.xib; sourceTree = ""; }; 04A74B871DA0195B0030DDE6 /* DecriptedCollectionViewItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DecriptedCollectionViewItem.swift; sourceTree = ""; }; 0A5BC6FD1FA7B214000BDAB4 /* ViewController+Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ViewController+Model.swift"; sourceTree = ""; }; 0ABC6F15266A79DF00089885 /* JWT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = JWT.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 0AC0027827865A49002167AD /* JWTDesktopSwiftToolkit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = JWTDesktopSwiftToolkit; path = ../JWTDesktopSwiftToolkit; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 04A74B6A1DA00D830030DDE6 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 0AC0027A27865A64002167AD /* JWTDesktopSwiftToolkit in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 04A74B641DA00D830030DDE6 = { isa = PBXGroup; children = ( 0AC0027827865A49002167AD /* JWTDesktopSwiftToolkit */, 04A74B6F1DA00D830030DDE6 /* JWTDesktopSwift */, 04A74B6E1DA00D830030DDE6 /* Products */, 0A2D860C22B53E5C00BB4760 /* Frameworks */, ); sourceTree = ""; }; 04A74B6E1DA00D830030DDE6 /* Products */ = { isa = PBXGroup; children = ( 04A74B6D1DA00D830030DDE6 /* JWTDesktopSwift.app */, ); name = Products; sourceTree = ""; }; 04A74B6F1DA00D830030DDE6 /* JWTDesktopSwift */ = { isa = PBXGroup; children = ( 044CFDC21DA1735B005B1D7A /* Assets.xcassets */, 04A74B811DA00F4F0030DDE6 /* DecriptedCollectionViewItem.xib */, 04A74B821DA00F4F0030DDE6 /* DecriptedViewController.xib */, 04A74B761DA00D840030DDE6 /* Main.storyboard */, 04A74B791DA00D840030DDE6 /* Info.plist */, 04A74B701DA00D830030DDE6 /* AppDelegate.swift */, 04A74B721DA00D840030DDE6 /* ViewController.swift */, 04A74B7F1DA00F340030DDE6 /* DecriptedViewController.swift */, 04A74B871DA0195B0030DDE6 /* DecriptedCollectionViewItem.swift */, 0A5BC6FD1FA7B214000BDAB4 /* ViewController+Model.swift */, ); path = JWTDesktopSwift; sourceTree = ""; }; 0A2D860C22B53E5C00BB4760 /* Frameworks */ = { isa = PBXGroup; children = ( 0ABC6F15266A79DF00089885 /* JWT.framework */, ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 04A74B6C1DA00D830030DDE6 /* JWTDesktopSwift */ = { isa = PBXNativeTarget; buildConfigurationList = 04A74B7C1DA00D840030DDE6 /* Build configuration list for PBXNativeTarget "JWTDesktopSwift" */; buildPhases = ( 04A74B691DA00D830030DDE6 /* Sources */, 04A74B6A1DA00D830030DDE6 /* Frameworks */, 04A74B6B1DA00D830030DDE6 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = JWTDesktopSwift; packageProductDependencies = ( 0AC0027927865A64002167AD /* JWTDesktopSwiftToolkit */, ); productName = JWTDesktopSwift; productReference = 04A74B6D1DA00D830030DDE6 /* JWTDesktopSwift.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 04A74B651DA00D830030DDE6 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1020; LastUpgradeCheck = 1250; ORGANIZATIONNAME = JWTIO; TargetAttributes = { 04A74B6C1DA00D830030DDE6 = { CreatedOnToolsVersion = 8.0; LastSwiftMigration = 0920; ProvisioningStyle = Automatic; }; }; }; buildConfigurationList = 04A74B681DA00D830030DDE6 /* Build configuration list for PBXProject "JWTDesktopSwift" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 04A74B641DA00D830030DDE6; productRefGroup = 04A74B6E1DA00D830030DDE6 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 04A74B6C1DA00D830030DDE6 /* JWTDesktopSwift */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 04A74B6B1DA00D830030DDE6 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 04A74B781DA00D840030DDE6 /* Main.storyboard in Resources */, 04A74B831DA00F4F0030DDE6 /* DecriptedCollectionViewItem.xib in Resources */, 044CFDC31DA1735B005B1D7A /* Assets.xcassets in Resources */, 04A74B841DA00F4F0030DDE6 /* DecriptedViewController.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 04A74B691DA00D830030DDE6 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 0A5BC6FE1FA7B214000BDAB4 /* ViewController+Model.swift in Sources */, 04A74B731DA00D840030DDE6 /* ViewController.swift in Sources */, 04A74B881DA0195B0030DDE6 /* DecriptedCollectionViewItem.swift in Sources */, 04A74B711DA00D840030DDE6 /* AppDelegate.swift in Sources */, 04A74B801DA00F340030DDE6 /* DecriptedViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 04A74B761DA00D840030DDE6 /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 04A74B771DA00D840030DDE6 /* Base */, ); name = Main.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 04A74B7A1DA00D840030DDE6 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 04A74B7B1DA00D840030DDE6 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; }; name = Release; }; 04A74B7D1DA00D840030DDE6 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "-"; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = JWTDesktopSwift/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.jwtio.JWTDesktopSwift; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; }; name = Debug; }; 04A74B7E1DA00D840030DDE6 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "-"; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = JWTDesktopSwift/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.jwtio.JWTDesktopSwift; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 04A74B681DA00D830030DDE6 /* Build configuration list for PBXProject "JWTDesktopSwift" */ = { isa = XCConfigurationList; buildConfigurations = ( 04A74B7A1DA00D840030DDE6 /* Debug */, 04A74B7B1DA00D840030DDE6 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 04A74B7C1DA00D840030DDE6 /* Build configuration list for PBXNativeTarget "JWTDesktopSwift" */ = { isa = XCConfigurationList; buildConfigurations = ( 04A74B7D1DA00D840030DDE6 /* Debug */, 04A74B7E1DA00D840030DDE6 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ 0AC0027927865A64002167AD /* JWTDesktopSwiftToolkit */ = { isa = XCSwiftPackageProductDependency; productName = JWTDesktopSwiftToolkit; }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 04A74B651DA00D830030DDE6 /* Project object */; } ================================================ FILE: Example/JWTDesktopSwift/JWTDesktopSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Example/JWTDesktopSwift/JWTDesktopSwift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: Example/JWTDesktopSwiftToolkit/.gitignore ================================================ .DS_Store /.build /Packages /*.xcodeproj xcuserdata/ DerivedData/ .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata ================================================ FILE: Example/JWTDesktopSwiftToolkit/Package.swift ================================================ // swift-tools-version:5.5 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "JWTDesktopSwiftToolkit", products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. .library( name: "JWTDesktopSwiftToolkit", targets: ["JWTDesktopSwiftToolkit"]), ], dependencies: [ // Dependencies declare other packages that this package depends on. // .package(url: /* package url */, from: "1.0.0"), .package(name: "JWT", path: "../../") ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "JWTDesktopSwiftToolkit", dependencies: [ .product(name: "JWT", package: "JWT") ] ), .testTarget( name: "JWTDesktopSwiftToolkitTests", dependencies: ["JWTDesktopSwiftToolkit"]), ] ) ================================================ FILE: Example/JWTDesktopSwiftToolkit/README.md ================================================ # JWTDesktopSwiftToolkit A description of this package. ================================================ FILE: Example/JWTDesktopSwiftToolkit/Sources/JWTDesktopSwiftToolkit/Array+Extension.swift ================================================ // // Array+Extension.swift // JWTDesktopSwift // // Created by Lobanov Dmitry on 30.10.2017. // Copyright © 2017 JWTIO. All rights reserved. // import Foundation public extension Array { func safeObject(index: Array.Index) -> Element? { self.indices.contains(index) ? self[index] : nil } } ================================================ FILE: Example/JWTDesktopSwiftToolkit/Sources/JWTDesktopSwiftToolkit/ColorBridge+Platforms.swift ================================================ // // ColorBridge+Platforms.swift // JWTDesktopSwiftToolkit // // Created by Dmitry Lobanov on 04.06.2021. // import Foundation #if canImport(UIKit) import UIKit public typealias ColorBridge = UIColor #elseif canImport(AppKit) import AppKit public typealias ColorBridge = NSColor #endif public extension SignatureValidationType { var color: ColorBridge { switch self { case .unknown: return .darkGray case .valid: return .init(red: 0, green: 185/255.0, blue: 241/255.0, alpha: 1.0) case .invalid: return .red } } } public extension TokenTextType { var color: ColorBridge { switch self { case .unknown: return .black case .header: return .red case .payload: return .magenta case .signature: return .init(red: 0, green: 185/255.0, blue: 241/255.0, alpha: 1.0) case .dot: return .blue } } } ================================================ FILE: Example/JWTDesktopSwiftToolkit/Sources/JWTDesktopSwiftToolkit/FontBridge+Platforms.swift ================================================ // // FontBridge+Platforms.swift // JWTDesktopSwiftToolkit // // Created by Dmitry Lobanov on 04.06.2021. // import Foundation #if canImport(UIKit) import UIKit public typealias FontBridge = UIFont #elseif canImport(AppKit) import AppKit public typealias FontBridge = NSFont #endif public extension TokenTextType { func defaultEncodedTextAttributes() -> [NSAttributedString.Key: Any] { [.font: FontBridge.boldSystemFont(ofSize: 22)] } var font: FontBridge { .boldSystemFont(ofSize: 22) } } public extension TokenTextAppearance { struct Attributes { public let color: ColorBridge public let font: FontBridge } } ================================================ FILE: Example/JWTDesktopSwiftToolkit/Sources/JWTDesktopSwiftToolkit/SignatureValidationType.swift ================================================ // // SignatureValidationType.swift // JWTDesktopSwift // // Created by Lobanov Dmitry on 30.10.2017. // Copyright © 2017 JWTIO. All rights reserved. // public enum SignatureValidationType: Int { case unknown case valid case invalid public var title: String { switch self { case .unknown: return "Signature unknown" case .valid: return "Signature valid" case .invalid: return "Signature invalid" } } } ================================================ FILE: Example/JWTDesktopSwiftToolkit/Sources/JWTDesktopSwiftToolkit/String+Extension.swift ================================================ // // String+Extension.swift // JWTDesktopSwift // // Created by Lobanov Dmitry on 30.10.2017. // Copyright © 2017 JWTIO. All rights reserved. // import Foundation public extension String { static func json(_ object: Any?) -> String { guard let jsonObject = object else { return "" } if !JSONSerialization.isValidJSONObject(jsonObject) { print("object is not valid JSONObject: \(jsonObject)") return "" } guard let data = try? JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted) else { return "" } guard let string = String(data: data, encoding: .utf8) else { return "" } return string } } ================================================ FILE: Example/JWTDesktopSwiftToolkit/Sources/JWTDesktopSwiftToolkit/TokenDecoder.swift ================================================ // // JWTTokenDecoder.swift // JWTDesktopSwift // // Created by Lobanov Dmitry on 30.10.2017. // Copyright © 2017 JWTIO. All rights reserved. // import Foundation import JWT public protocol TokenDecoderDataTransferObjectProtocol { var algorithmName: String {get} var secret: String? {get} var secretData: Data? {get} var isBase64EncodedSecret: Bool {get} var shouldSkipSignatureVerification: Bool {get} } private protocol TokenDecoderProtocol { func decode(token: String?, object: TokenDecoderDataTransferObjectProtocol) -> JWTCodingResultType? } public struct TokenDecoder: TokenDecoderProtocol { private let theDecoder: TokenDecoderProtocol = JWTTokenDecoder__V3() public func decode(token: String?, object: TokenDecoderDataTransferObjectProtocol?) -> JWTCodingResultType? { guard let object = object else { return nil } return self.theDecoder.decode(token: token, object: object) } func decode(token: String?, object: TokenDecoderDataTransferObjectProtocol) -> JWTCodingResultType? { self.theDecoder.decode(token: token, object: object) } public init() {} } public extension TokenDecoder { struct DataTransferObject: TokenDecoderDataTransferObjectProtocol { public init(algorithmName: String, secret: String? = nil, secretData: Data? = nil, isBase64EncodedSecret: Bool, shouldSkipSignatureVerification: Bool) { self.algorithmName = algorithmName self.secret = secret self.secretData = secretData self.isBase64EncodedSecret = isBase64EncodedSecret self.shouldSkipSignatureVerification = shouldSkipSignatureVerification } public var algorithmName: String public var secret: String? public var secretData: Data? public var isBase64EncodedSecret: Bool public var shouldSkipSignatureVerification: Bool } } private struct JWTTokenDecoder__V2: TokenDecoderProtocol { func decode(token: String?, object: TokenDecoderDataTransferObjectProtocol) -> JWTCodingResultType? { // do work here. print("JWT ENCODED TOKEN \(String(describing: token))") let algorithmName = object.algorithmName let skipVerification = object.shouldSkipSignatureVerification print("JWT Algorithm NAME \(algorithmName)") let builder = JWTBuilder.decodeMessage(token).algorithmName(algorithmName)?.options(skipVerification as NSNumber) if (algorithmName != JWTAlgorithmNameNone) { if let secretData = object.secretData, object.isBase64EncodedSecret { _ = builder?.secretData(secretData) } else { _ = builder?.secret(object.secret) } } guard let decoded = builder?.decode else { print("JWT ERROR \(String(describing: builder?.jwtError))") if let error = builder?.jwtError { return .init(errorResult: .init(error: error)) } else { return nil } } print("JWT DICTIONARY \(decoded)") return .init(successResult: .init(headersAndPayload: decoded)) } } private struct JWTTokenDecoder__V3: TokenDecoderProtocol { func decode(token: String?, object: TokenDecoderDataTransferObjectProtocol) -> JWTCodingResultType? { print("JWT ENCODED TOKEN \(String(describing: token))") let algorithmName = object.algorithmName let skipVerification = object.shouldSkipSignatureVerification print("JWT Algorithm NAME \(algorithmName)") let secretData = object.secretData let secret = object.secret let isBase64EncodedSecret = object.isBase64EncodedSecret guard let algorithm = JWTAlgorithmFactory.algorithm(byName: algorithmName) else { return nil } var holder: JWTAlgorithmDataHolderProtocol? = nil switch algorithm { case is JWTAlgorithmRSBase, is JWTAlgorithmAsymmetricBase: var key: JWTCryptoKeyProtocol? do { key = try JWTCryptoKeyPublic(pemEncoded: secret, parameters: nil) } catch let error { // throw if needed print("JWT internalError: \(error.localizedDescription)") return .init(errorResult: .init(error: error)) } // TODO: remove dependency. // Aware of last part. // DataHolder MUST have a secretData ( empty data is perfect, if you use verifyKey ) holder = JWTAlgorithmRSFamilyDataHolder().verifyKey(key).algorithmName(algorithmName) case is JWTAlgorithmHSBase: let aHolder = JWTAlgorithmHSFamilyDataHolder() if let theSecretData = secretData, isBase64EncodedSecret { _ = aHolder.secretData(theSecretData) } else { _ = aHolder.secret(secret) } holder = aHolder.algorithmName(algorithmName) case is JWTAlgorithmNone: holder = JWTAlgorithmNoneDataHolder() default: break } let builder = JWTDecodingBuilder.decodeMessage(token).claimsSetCoordinator(JWTClaimsSetCoordinatorBase.init()).addHolder(holder)?.options(skipVerification as NSNumber) guard let result = builder?.result else { return nil } if let success = result.successResult { print("JWT RESULT: \(String(describing: success.debugDescription)) -> \(String(describing: success.headerAndPayloadDictionary?.debugDescription))") return result } else if let error = result.errorResult { print("JWT ERROR: \(String(describing: error.debugDescription)) -> \(String(describing: error.error?.localizedDescription))") return result } else { return nil } } } ================================================ FILE: Example/JWTDesktopSwiftToolkit/Sources/JWTDesktopSwiftToolkit/TokenTextTypeDescription.swift ================================================ // // TokenTextTypeDescription.swift // JWTDesktopSwift // // Created by Lobanov Dmitry on 01.10.16. // Copyright © 2016 JWTIO. All rights reserved. // import SwiftUI // MARK: Token text type. public enum TokenTextType: Int { case unknown = 0 case header case payload case signature case dot static var typicalSchemeComponents: [Self] { [.header, .dot, .payload, .dot, .signature] } } // MARK: NSAttributes. extension TokenTextType { fileprivate var encodedTextAttributes: [NSAttributedString.Key: Any] { encodedTextAttributes(type: self) } fileprivate func encodedTextAttributes(type: TokenTextType) -> [NSAttributedString.Key: Any] { var attributes = self.defaultEncodedTextAttributes() attributes[NSAttributedString.Key.foregroundColor] = type.color return attributes } } // MARK: Serialization fileprivate class TokenTextSerialization { fileprivate func textPart(parts: [String], type: TokenTextType) -> String? { switch type { case .unknown: return nil case .header: return parts.first case .payload where parts.count > 1: return parts[1] case .signature where parts.count > 2: return parts[2.. [(String, Attributes)] { let parts = text.components(separatedBy: ".") return TokenTextType.typicalSchemeComponents.flatMap { (type) -> [(String, Attributes)] in if let part = tokenSerialization.textPart(parts: parts, type: type) { let color = type.color let font = type.font return [(part, Attributes(color: color, font: font))] } return [] } } public init() {} } // MARK: Appearance.Public. public extension TokenTextAppearance { func encodedAttributes(text: String) -> [(string: String, attributes: Attributes)] { self.encodedAttributes(text: text, tokenSerialization: self.serialization) } func encodedAttributedString(text: String) -> NSAttributedString? { self.encodedAttributes(text: text, tokenSerialization: self.serialization).reduce(NSMutableAttributedString()) { (result, pair) in let (part, attributes) = pair let string = NSAttributedString(string: part, attributes: [ .foregroundColor: attributes.color, .font: attributes.font ]) result.append(string) return result } } } ================================================ FILE: Example/JWTDesktopSwiftToolkit/Tests/JWTDesktopSwiftToolkitTests/JWTDesktopSwiftToolkitTests.swift ================================================ import XCTest @testable import JWTDesktopSwiftToolkit final class JWTDesktopSwiftToolkitTests: XCTestCase { func testExample() throws { // This is an example of a functional test case. // Use XCTAssert and related functions to verify your tests produce the correct // results. } } ================================================ FILE: Example/JWTSwiftUI/JWTSwiftUI/AppDelegate.swift ================================================ // // AppDelegate.swift // JWTSwiftUI // // Created by Dmitry Lobanov on 08/06/2019. // Copyright © 2019 Dmitry Lobanov. All rights reserved. // import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true } func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } // MARK: UISceneSession Lifecycle func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { // Called when a new scene session is being created. // Use this method to select a configuration to create the new scene with. return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) } func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { // Called when the user discards a scene session. // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. // Use this method to release any resources that were specific to the discarded scenes, as they will not return. } } ================================================ FILE: Example/JWTSwiftUI/JWTSwiftUI/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "20x20", "scale" : "2x" }, { "idiom" : "iphone", "size" : "20x20", "scale" : "3x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "3x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "3x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" }, { "idiom" : "ipad", "size" : "20x20", "scale" : "1x" }, { "idiom" : "ipad", "size" : "20x20", "scale" : "2x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "1x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "2x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "1x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "2x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "1x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "2x" }, { "idiom" : "ipad", "size" : "83.5x83.5", "scale" : "2x" }, { "idiom" : "ios-marketing", "size" : "1024x1024", "scale" : "1x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/JWTSwiftUI/JWTSwiftUI/Assets.xcassets/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/JWTSwiftUI/JWTSwiftUI/Base.lproj/LaunchScreen.storyboard ================================================ ================================================ FILE: Example/JWTSwiftUI/JWTSwiftUI/BottomView.swift ================================================ // // BottomView.swift // JWTSwiftUI // // Created by Dmitry Lobanov on 08/06/2019. // Copyright © 2019 Dmitry Lobanov. All rights reserved. // import SwiftUI import JWTDesktopSwiftToolkit extension BottomView { struct EncryptedView: View { @Binding var textValue: String var appearance: TokenTextAppearance = .init() var body1: some View { TextField("Input secret", text: $textValue).lineLimit(10).multilineTextAlignment(.center) } var body2: some View { Text(textValue).lineLimit(10).padding() } var body3: some View { Text("Abc") // List { // ForEach(self.appearance.encodedAttributes(text: textValue)) { value in // Text(part) // } // } } var currentBody: some View { TextEditor(text: self.$textValue).redacted(reason: .placeholder) } var body: some View { self.currentBody } } } extension BottomView { struct DecodedView: View { var decodedInformation: JWTModel.Storage.DecodedData.DecodedInfoType var currentBody: some View { Form { ForEach(self.decodedInformation, id: \.0) { value in Section(header: Text(value.0.rawValue)) { Text(String(describing: value.1)).bold().foregroundColor(value.0.color) } } } } var oldBody: some View { VStack { ForEach(self.decodedInformation, id: \.0) { value in Text("\(value.0.rawValue): \(String(describing: value.1))").lineLimit(10).multilineTextAlignment(.center) } } } var body: some View { self.currentBody } } } extension BottomView { struct SignatureView: View { var validation: SignatureValidationType var body: some View { Text(validation.title).bold().foregroundColor(.white).padding(8) .background(Color.init(validation.color)).cornerRadius(20) } } } struct QqView: View { // @State var width: Length = 1 static var bigText = "This is a test of the emergency broadcast system. This is only a test. If this were a real emergency, then you'd be up the creek without a paddle. But it's not so you're safe for the time being." @State var text: String = QqView.bigText var body: some View { GeometryReader { geometry in // ScrollView(isScrollEnabled: true, alwaysBounceHorizontal: false, alwaysBounceVertical: true, showsHorizontalIndicator: false, showsVerticalIndicator: true) { VStack { TextField("", text: self.$text).background(Color.red) .lineLimit(nil) .frame( minWidth: geometry.size.width, idealWidth: geometry.size.width, maxWidth: geometry.size.width, minHeight: geometry.size.height, idealHeight: geometry.size.height, maxHeight: .infinity, alignment: .topLeading) } // } } } } struct BottomView: View { @Binding var encodedData: JWTModel.Storage.EncodedData var decodedData: JWTModel.Storage.DecodedData var body: some View { VStack { EncryptedView(textValue: $encodedData.token) DecodedView(decodedInformation: decodedData.decodedInformation) SignatureView(validation: decodedData.verified) } } } ================================================ FILE: Example/JWTSwiftUI/JWTSwiftUI/ContentView.swift ================================================ // // ContentView.swift // JWTSwiftUI // // Created by Dmitry Lobanov on 08/06/2019. // Copyright © 2019 Dmitry Lobanov. All rights reserved. // import SwiftUI struct ContentView: View { @ObservedObject var model: JWTModel func getBottomView() -> some View { BottomView(encodedData: self.$model.data.encodedData, decodedData: model.decodedData) } func getHeaderView() -> some View { HeaderView(settings: self.$model.data.settings, encodedData: self.$model.data.encodedData, storage: self.model.data) } var headerBody: some View { TabView { self.getHeaderView().tabItem { Text("Settings") } self.getHeaderView().tabItem { Text("Settings") } } } var bottomBody: some View { self.getBottomView().tabItem { Text("Decoding") } } var body1: some View { TabView { getBottomView().tabItem { Text("Decoding") } getHeaderView().tabItem { Text("Settings") } } } var body2: some View { VStack { getHeaderView() getBottomView() } } var body3: some View { NavigationView { getBottomView() getHeaderView() } } var body4: some View { NavigationView { VStack { getBottomView() getHeaderView() } } } var body5: some View { #if os(macOS) HSplitView { getBottomView() getHeaderView() } #else body4 #endif } var body: some View { body5 } } ================================================ FILE: Example/JWTSwiftUI/JWTSwiftUI/HeaderView.swift ================================================ // // HeaderView.swift // JWTSwiftUI // // Created by Dmitry Lobanov on 08/06/2019. // Copyright © 2019 Dmitry Lobanov. All rights reserved. // import Foundation import SwiftUI extension HeaderView { struct AlgorithmView: View { @Binding var chosenAlgorithm: String var values: [String] = [] var currentBody: some View { Picker(selection: $chosenAlgorithm, label: Text("Choose algorithm")) { ForEach(self.values, id: \.self) { value in Text(value).tag(value) } } } var body: some View { HStack { self.currentBody } } } } extension HeaderView { struct SecretView: View { @Binding var textValue: String @Binding var isToogled: Bool var settings: JWTModel.Storage var body: some View { VStack { // Text("Secret") TextField("secret", text: $textValue) Toggle(isOn: $isToogled, label: { Text("Secret is base64") })//.disabled(!settings.isBase64Available) } } } } extension HeaderView { struct SignatureView: View { @Binding var isToogled: Bool var body: some View { HStack { // Text("Signature") Toggle(isOn: $isToogled, label: { Text("Skip signature verification") }) } } } } struct HeaderView: View { @Binding var settings: JWTModel.Storage.Settings @Binding var encodedData: JWTModel.Storage.EncodedData var storage: JWTModel.Storage var body: some View { Form { Section(header: Text("Algorithm")) { AlgorithmView(chosenAlgorithm: $encodedData.algorithmName, values: $encodedData.wrappedValue.availableAlgorithmsNames) } Section(header: Text("Input secret")) { SecretView(textValue: $encodedData.secret, isToogled: $settings.isBase64, settings: storage) } Section(header: Text("Signature")) { SignatureView(isToogled: $settings.skipSignatureVerification) } } } } ================================================ FILE: Example/JWTSwiftUI/JWTSwiftUI/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 LSRequiresIPhoneOS UIApplicationSceneManifest UIApplicationSupportsMultipleScenes UISceneConfigurations UIWindowSceneSessionRoleApplication UILaunchStoryboardName LaunchScreen UISceneConfigurationName Default Configuration UISceneDelegateClassName $(PRODUCT_MODULE_NAME).SceneDelegate UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Example/JWTSwiftUI/JWTSwiftUI/JWTModel.swift ================================================ // // JWTData.swift // JWTSwiftUI // // Created by Dmitry Lobanov on 11/06/2019. // Copyright © 2019 Dmitry Lobanov. All rights reserved. // import SwiftUI import Combine import JWT import JWTDesktopSwiftToolkit class JWTModel: ObservableObject { @Published var data: Storage { didSet { self.computeDecoding() } } @Published var decodedData: Storage.DecodedData = .init() var decoder: TokenDecoder = .init() var appearance: TokenTextAppearance = .init() public init(data: Storage) { self.data = data // update data right after init or in stored property setter? // we need somehow look after values of storage. self.computeDecoding() } func getObject() -> TokenDecoder.DataTransferObject { let settings = self.data.settings let encodedData = self.data.encodedData let algorithmName = encodedData.algorithmName let secret = encodedData.secret let secretData: Data? = self.data.getSecretData() let isBase64EncodedSecret = settings.isBase64 let shouldSkipSignatureVerification = settings.skipSignatureVerification return .init(algorithmName: algorithmName, secret: secret, secretData: secretData, isBase64EncodedSecret: isBase64EncodedSecret, shouldSkipSignatureVerification: shouldSkipSignatureVerification) } func computeEncoding() { // let object = self.getObject() } func computeDecoding() { let object = self.getObject() let token = self.data.encodedData.token // and we should also populate data after decoding. // check it in another JWT project. // where you should update data. var forSignatureObject = object forSignatureObject.shouldSkipSignatureVerification = false self.decodedData.verified = (self.decoder.decode(token: token, object: forSignatureObject)?.errorResult != nil) ? .invalid : .valid if let decoded = self.decoder.decode(token: token, object: object) { if let successResult = decoded.successResult { self.decodedData.result = .success(successResult.headerAndPayloadDictionary as! [String: Any]) } else if let errorResult = decoded.errorResult { self.decodedData.result = .failure(errorResult.error) } } } } // MARK: Data. extension JWTModel { struct Storage { var settings: Settings = .init() var encodedData: EncodedData = .init() var isBase64Available: Bool { self.settings.isBase64 && self.getSecretData() != nil } fileprivate func getSecretData() -> Data? { let secret = encodedData.secret let isBase64Encoded = settings.isBase64 guard let result = Data(base64Encoded: secret), isBase64Encoded else { return nil } return result } } } // MARK: Settings structure. extension JWTModel.Storage { struct Settings { var isBase64 = false // HeaderView.SecretView var skipSignatureVerification = false // HeaderView.SignatureView } } // MARK: EncodedData structure. extension JWTModel.Storage { struct EncodedData { var algorithmName = "" // HeaderView.AlgorithmView var secret = "" // HeaderView.SecretView var token = "" // BottomView.EncryptedTextView } } // MARK: DecodedData structure. extension JWTModel.Storage { struct DecodedData { var result: Result<[String: Any], Error> = .success([:]) var verified: SignatureValidationType = .unknown var decoded: [String: Any] { guard case let .success(value) = self.result else { return [:] } return value } var error: Error? { guard case let .failure(value) = self.result else { return nil } return value } } } // MARK: decodedInformation extension JWTModel.Storage.DecodedData { typealias DecodedInfoType = [(DecodedInformation, String)] private func decodedInfo() -> DecodedInfoType { if let error = self.error { return [ (.error, String.json(["error": error.localizedDescription])) ] } else if let headers = decoded[JWTCodingResultComponents.headers!] as? [String: Any], let payload = decoded[JWTCodingResultComponents.payload!] as? [String: Any] { return [ (.header, String.json(headers)), (.payload, String.json(payload)) ] } else { return [ (.unknown, String.json(["unknown": "unknown"])) ] } } var decodedInformation: DecodedInfoType { self.decodedInfo() } } // MARK: Algorithms. extension JWTModel.Storage.EncodedData { var availableAlgorithms: [JWTAlgorithm] { JWTAlgorithmFactory.algorithms } var availableAlgorithmsNames: [String] { self.availableAlgorithms.map(\.name) } } // MARK: DecodedInformation extension JWTModel.Storage.DecodedData { enum DecodedInformation: String { case error case header case payload case unknown var uiColor: ColorBridge { switch self { case .error: return SignatureValidationType.invalid.color case .header: return TokenTextType.header.color case .payload: return TokenTextType.payload.color case .unknown: return TokenTextType.unknown.color } } var color: Color { .init(self.uiColor) } } } //MARK: Data Seed extension JWTModel.Storage { static func create(algorithmName: String, secret: String, token: String) -> Self { let encodedData: EncodedData = .init(algorithmName: algorithmName, secret: secret, token: token) let settings: Settings = .init(isBase64: true, skipSignatureVerification: false) return .init(settings: settings, encodedData: encodedData) } static func HS256() -> Self { let algorithmName = JWTAlgorithmNameHS256 let secret = "c2VjcmV0" let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ" return self.create(algorithmName: algorithmName, secret: secret, token: token) } static func RS256() -> Self { let algorithmName = JWTAlgorithmNameRS256 let secret = "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoPryo3IisfK3a028bwgso/CW5kB84mk6Y7rO76FxJRTWnOAla0Uf0OpIID7go4Qck66yT4/uPpiOQIR0oW0plTekkDP75EG3d/2mtzhiCtELV4F1r9b/InCN5dYYK8USNkKXgjbeVyatdUvCtokz10/ibNZ9qikgKf58qXnn2anGvpE6ded5FOUEukOjr7KSAfD0KDNYWgZcG7HZBxn/3N7ND9D0ATu2vxlJsNGOkH6WL1EmObo/QygBXzuZm5o0N0W15EXpWVbl4Ye7xqPnvc1i2DTKxNUcyhXfDbLw1ee2d9T/WU5895Ko2bQ/O/zPwUSobM3m+fPMW8kp5914kwIDAQAB-----END PUBLIC KEY-----" let token = "eyJraWQiOiJqd3RfdWF0X2tleXMiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI1MDAxIiwiaXNzIjoiQ0xNIiwiZXhwIjoxNTA4MjQ5NTU3LCJqdGkiOiI2MjcyM2E4Yi0zOTZmLTQxYmYtOTljMi02NWRkMzk2MDNiNjQifQ.Cej8RJ6e2HEU27rh_TyHZBoMI1jErmhOfSFY4SRzRoijSP628hM82XxjDX24HsKqIsK1xeeGI1yg1bed4RPhnmDGt4jAY73nqguZ1oqZ2DTcfZ5olxCXyLLaytl2XH7-62M_mFUcGj7I2mwts1DQkHWnFky2i4uJXlksHFkUg2xZoGEjVHo0bxCxgQ5yQiOpxC5VodN5rAPM3A5yMG6EijOp-dvUThjoJ4RFTGKozw_x_Qg6RLGDusNcmLIMbHasTsyZAZle6RFkwO0Sij1k6z6_xssbOl-Q57m7CeYgVHMORdzy4Smkmh-0gzeiLsGbCL4fhgdHydpIFajW-eOXMw" return self.create(algorithmName: algorithmName, secret: secret, token: token) } } ================================================ FILE: Example/JWTSwiftUI/JWTSwiftUI/Preview Content/Preview Assets.xcassets/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/JWTSwiftUI/JWTSwiftUI/SceneDelegate.swift ================================================ // // SceneDelegate.swift // JWTSwiftUI // // Created by Dmitry Lobanov on 08/06/2019. // Copyright © 2019 Dmitry Lobanov. All rights reserved. // import UIKit import SwiftUI class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? var model: JWTModel = .init(data: JWTModel.Storage.HS256()) func createController() -> UIViewController { UIHostingController(rootView: ContentView(model: self.model)) } func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). // Use a UIHostingController as window root view controller if let windowScene = scene as? UIWindowScene { let window = UIWindow(windowScene: windowScene) window.rootViewController = self.createController() self.window = window window.makeKeyAndVisible() } } func sceneDidDisconnect(_ scene: UIScene) { // Called as the scene is being released by the system. // This occurs shortly after the scene enters the background, or when its session is discarded. // Release any resources associated with this scene that can be re-created the next time the scene connects. // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). } func sceneDidBecomeActive(_ scene: UIScene) { // Called when the scene has moved from an inactive state to an active state. // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. } func sceneWillResignActive(_ scene: UIScene) { // Called when the scene will move from an active state to an inactive state. // This may occur due to temporary interruptions (ex. an incoming phone call). } func sceneWillEnterForeground(_ scene: UIScene) { // Called as the scene transitions from the background to the foreground. // Use this method to undo the changes made on entering the background. } func sceneDidEnterBackground(_ scene: UIScene) { // Called as the scene transitions from the foreground to the background. // Use this method to save data, release shared resources, and store enough scene-specific state information // to restore the scene back to its current state. } } ================================================ FILE: Example/JWTSwiftUI/JWTSwiftUI.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 52; objects = { /* Begin PBXBuildFile section */ 0A60395422B22BA700256661 /* JWTModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A60395322B22BA700256661 /* JWTModel.swift */; }; 0A76C87022ABD2AF00B8A43A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A76C86F22ABD2AF00B8A43A /* AppDelegate.swift */; }; 0A76C87222ABD2AF00B8A43A /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A76C87122ABD2AF00B8A43A /* SceneDelegate.swift */; }; 0A76C87422ABD2AF00B8A43A /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A76C87322ABD2AF00B8A43A /* ContentView.swift */; }; 0A76C87622ABD2B100B8A43A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0A76C87522ABD2B100B8A43A /* Assets.xcassets */; }; 0A76C87922ABD2B100B8A43A /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0A76C87822ABD2B100B8A43A /* Preview Assets.xcassets */; }; 0A76C87C22ABD2B100B8A43A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0A76C87A22ABD2B100B8A43A /* LaunchScreen.storyboard */; }; 0A76C88422ABD2F200B8A43A /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A76C88322ABD2F200B8A43A /* HeaderView.swift */; }; 0A76C88822ABE51800B8A43A /* BottomView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A76C88722ABE51800B8A43A /* BottomView.swift */; }; 0A883AB8266E166600DAF016 /* iOSJWTSwiftUIApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A883AB7266E166600DAF016 /* iOSJWTSwiftUIApp.swift */; }; 0A883ABC266E166900DAF016 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0A883ABB266E166900DAF016 /* Assets.xcassets */; }; 0A883ABF266E166900DAF016 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0A883ABE266E166900DAF016 /* Preview Assets.xcassets */; }; 0A883AC4266E169900DAF016 /* BottomView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A76C88722ABE51800B8A43A /* BottomView.swift */; }; 0A883AC5266E169900DAF016 /* JWTModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A60395322B22BA700256661 /* JWTModel.swift */; }; 0A883AC6266E169900DAF016 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A76C87322ABD2AF00B8A43A /* ContentView.swift */; }; 0A883AC7266E169900DAF016 /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A76C88322ABD2F200B8A43A /* HeaderView.swift */; }; 0A883ACF266E191700DAF016 /* MacJWTSwiftUIApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A883ACE266E191700DAF016 /* MacJWTSwiftUIApp.swift */; }; 0A883AD3266E191A00DAF016 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0A883AD2266E191A00DAF016 /* Assets.xcassets */; }; 0A883AD6266E191A00DAF016 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0A883AD5266E191A00DAF016 /* Preview Assets.xcassets */; }; 0A883ADC266E192500DAF016 /* JWTModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A60395322B22BA700256661 /* JWTModel.swift */; }; 0A883ADD266E192500DAF016 /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A76C88322ABD2F200B8A43A /* HeaderView.swift */; }; 0A883ADE266E192500DAF016 /* BottomView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A76C88722ABE51800B8A43A /* BottomView.swift */; }; 0A883ADF266E192500DAF016 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A76C87322ABD2AF00B8A43A /* ContentView.swift */; }; 0AABB95827A6A3C0006718A0 /* JWTDesktopSwiftToolkit in Frameworks */ = {isa = PBXBuildFile; productRef = 0AABB95727A6A3C0006718A0 /* JWTDesktopSwiftToolkit */; }; 0AABB95A27A6A3C4006718A0 /* JWTDesktopSwiftToolkit in Frameworks */ = {isa = PBXBuildFile; productRef = 0AABB95927A6A3C4006718A0 /* JWTDesktopSwiftToolkit */; }; 0AC002762786598E002167AD /* JWTDesktopSwiftToolkit in Frameworks */ = {isa = PBXBuildFile; productRef = 0AC002752786598E002167AD /* JWTDesktopSwiftToolkit */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ 0AEEA8BB22B5400E00B67217 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 0A60395322B22BA700256661 /* JWTModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JWTModel.swift; sourceTree = ""; }; 0A76C86C22ABD2AF00B8A43A /* JWTSwiftUI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JWTSwiftUI.app; sourceTree = BUILT_PRODUCTS_DIR; }; 0A76C86F22ABD2AF00B8A43A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 0A76C87122ABD2AF00B8A43A /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 0A76C87322ABD2AF00B8A43A /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 0A76C87522ABD2B100B8A43A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 0A76C87822ABD2B100B8A43A /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 0A76C87B22ABD2B100B8A43A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 0A76C87D22ABD2B100B8A43A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 0A76C88322ABD2F200B8A43A /* HeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderView.swift; sourceTree = ""; }; 0A76C88722ABE51800B8A43A /* BottomView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomView.swift; sourceTree = ""; }; 0A883AB5266E166600DAF016 /* iOSJWTSwiftUI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iOSJWTSwiftUI.app; sourceTree = BUILT_PRODUCTS_DIR; }; 0A883AB7266E166600DAF016 /* iOSJWTSwiftUIApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSJWTSwiftUIApp.swift; sourceTree = ""; }; 0A883AB9266E166600DAF016 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 0A883ABB266E166900DAF016 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 0A883ABE266E166900DAF016 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 0A883AC0266E166900DAF016 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 0A883ACC266E191700DAF016 /* MacJWTSwiftUI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MacJWTSwiftUI.app; sourceTree = BUILT_PRODUCTS_DIR; }; 0A883ACE266E191700DAF016 /* MacJWTSwiftUIApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacJWTSwiftUIApp.swift; sourceTree = ""; }; 0A883AD0266E191700DAF016 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 0A883AD2266E191A00DAF016 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 0A883AD5266E191A00DAF016 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 0A883AD7266E191A00DAF016 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 0A883AD8266E191A00DAF016 /* MacJWTSwiftUI.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MacJWTSwiftUI.entitlements; sourceTree = ""; }; 0ABC6F5A266A908000089885 /* JWT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = JWT.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 0ABC6F62266A918000089885 /* JWT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = JWT.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 0AC00271278658F8002167AD /* JWTDesktopSwiftToolkit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = JWTDesktopSwiftToolkit; path = ../JWTDesktopSwiftToolkit; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 0A76C86922ABD2AF00B8A43A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 0AC002762786598E002167AD /* JWTDesktopSwiftToolkit in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 0A883AB2266E166600DAF016 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 0AABB95A27A6A3C4006718A0 /* JWTDesktopSwiftToolkit in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 0A883AC9266E191700DAF016 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 0AABB95827A6A3C0006718A0 /* JWTDesktopSwiftToolkit in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 0A76C86322ABD2AF00B8A43A = { isa = PBXGroup; children = ( 0AC00271278658F8002167AD /* JWTDesktopSwiftToolkit */, 0A76C86E22ABD2AF00B8A43A /* JWTSwiftUI */, 0A883AB6266E166600DAF016 /* iOSJWTSwiftUI */, 0A883ACD266E191700DAF016 /* MacJWTSwiftUI */, 0A76C86D22ABD2AF00B8A43A /* Products */, 0ABC6F59266A908000089885 /* Frameworks */, ); sourceTree = ""; }; 0A76C86D22ABD2AF00B8A43A /* Products */ = { isa = PBXGroup; children = ( 0A76C86C22ABD2AF00B8A43A /* JWTSwiftUI.app */, 0A883AB5266E166600DAF016 /* iOSJWTSwiftUI.app */, 0A883ACC266E191700DAF016 /* MacJWTSwiftUI.app */, ); name = Products; sourceTree = ""; }; 0A76C86E22ABD2AF00B8A43A /* JWTSwiftUI */ = { isa = PBXGroup; children = ( 0A60395322B22BA700256661 /* JWTModel.swift */, 0A76C86F22ABD2AF00B8A43A /* AppDelegate.swift */, 0A76C87122ABD2AF00B8A43A /* SceneDelegate.swift */, 0A76C87322ABD2AF00B8A43A /* ContentView.swift */, 0A76C88322ABD2F200B8A43A /* HeaderView.swift */, 0A76C88722ABE51800B8A43A /* BottomView.swift */, 0A76C87522ABD2B100B8A43A /* Assets.xcassets */, 0A76C87A22ABD2B100B8A43A /* LaunchScreen.storyboard */, 0A76C87D22ABD2B100B8A43A /* Info.plist */, 0A76C87722ABD2B100B8A43A /* Preview Content */, ); path = JWTSwiftUI; sourceTree = ""; }; 0A76C87722ABD2B100B8A43A /* Preview Content */ = { isa = PBXGroup; children = ( 0A76C87822ABD2B100B8A43A /* Preview Assets.xcassets */, ); path = "Preview Content"; sourceTree = ""; }; 0A883AB6266E166600DAF016 /* iOSJWTSwiftUI */ = { isa = PBXGroup; children = ( 0A883AB7266E166600DAF016 /* iOSJWTSwiftUIApp.swift */, 0A883AB9266E166600DAF016 /* ContentView.swift */, 0A883ABB266E166900DAF016 /* Assets.xcassets */, 0A883AC0266E166900DAF016 /* Info.plist */, 0A883ABD266E166900DAF016 /* Preview Content */, ); path = iOSJWTSwiftUI; sourceTree = ""; }; 0A883ABD266E166900DAF016 /* Preview Content */ = { isa = PBXGroup; children = ( 0A883ABE266E166900DAF016 /* Preview Assets.xcassets */, ); path = "Preview Content"; sourceTree = ""; }; 0A883ACD266E191700DAF016 /* MacJWTSwiftUI */ = { isa = PBXGroup; children = ( 0A883ACE266E191700DAF016 /* MacJWTSwiftUIApp.swift */, 0A883AD0266E191700DAF016 /* ContentView.swift */, 0A883AD2266E191A00DAF016 /* Assets.xcassets */, 0A883AD7266E191A00DAF016 /* Info.plist */, 0A883AD8266E191A00DAF016 /* MacJWTSwiftUI.entitlements */, 0A883AD4266E191A00DAF016 /* Preview Content */, ); path = MacJWTSwiftUI; sourceTree = ""; }; 0A883AD4266E191A00DAF016 /* Preview Content */ = { isa = PBXGroup; children = ( 0A883AD5266E191A00DAF016 /* Preview Assets.xcassets */, ); path = "Preview Content"; sourceTree = ""; }; 0ABC6F59266A908000089885 /* Frameworks */ = { isa = PBXGroup; children = ( 0ABC6F62266A918000089885 /* JWT.framework */, 0ABC6F5A266A908000089885 /* JWT.framework */, ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 0A76C86B22ABD2AF00B8A43A /* JWTSwiftUI */ = { isa = PBXNativeTarget; buildConfigurationList = 0A76C88022ABD2B100B8A43A /* Build configuration list for PBXNativeTarget "JWTSwiftUI" */; buildPhases = ( 0A76C86822ABD2AF00B8A43A /* Sources */, 0A76C86922ABD2AF00B8A43A /* Frameworks */, 0A76C86A22ABD2AF00B8A43A /* Resources */, 0AEEA8BB22B5400E00B67217 /* Embed Frameworks */, ); buildRules = ( ); dependencies = ( ); name = JWTSwiftUI; packageProductDependencies = ( 0AC002752786598E002167AD /* JWTDesktopSwiftToolkit */, ); productName = JWTSwiftUI; productReference = 0A76C86C22ABD2AF00B8A43A /* JWTSwiftUI.app */; productType = "com.apple.product-type.application"; }; 0A883AB4266E166600DAF016 /* iOSJWTSwiftUI */ = { isa = PBXNativeTarget; buildConfigurationList = 0A883AC1266E166900DAF016 /* Build configuration list for PBXNativeTarget "iOSJWTSwiftUI" */; buildPhases = ( 0A883AB1266E166600DAF016 /* Sources */, 0A883AB2266E166600DAF016 /* Frameworks */, 0A883AB3266E166600DAF016 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = iOSJWTSwiftUI; packageProductDependencies = ( 0AABB95927A6A3C4006718A0 /* JWTDesktopSwiftToolkit */, ); productName = iOSJWTSwiftUI; productReference = 0A883AB5266E166600DAF016 /* iOSJWTSwiftUI.app */; productType = "com.apple.product-type.application"; }; 0A883ACB266E191700DAF016 /* MacJWTSwiftUI */ = { isa = PBXNativeTarget; buildConfigurationList = 0A883AD9266E191A00DAF016 /* Build configuration list for PBXNativeTarget "MacJWTSwiftUI" */; buildPhases = ( 0A883AC8266E191700DAF016 /* Sources */, 0A883AC9266E191700DAF016 /* Frameworks */, 0A883ACA266E191700DAF016 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = MacJWTSwiftUI; packageProductDependencies = ( 0AABB95727A6A3C0006718A0 /* JWTDesktopSwiftToolkit */, ); productName = MacJWTSwiftUI; productReference = 0A883ACC266E191700DAF016 /* MacJWTSwiftUI.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 0A76C86422ABD2AF00B8A43A /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1250; LastUpgradeCheck = 1250; ORGANIZATIONNAME = "Dmitry Lobanov"; TargetAttributes = { 0A76C86B22ABD2AF00B8A43A = { CreatedOnToolsVersion = 11.0; }; 0A883AB4266E166600DAF016 = { CreatedOnToolsVersion = 12.5; }; 0A883ACB266E191700DAF016 = { CreatedOnToolsVersion = 12.5; }; }; }; buildConfigurationList = 0A76C86722ABD2AF00B8A43A /* Build configuration list for PBXProject "JWTSwiftUI" */; compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 0A76C86322ABD2AF00B8A43A; productRefGroup = 0A76C86D22ABD2AF00B8A43A /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 0A76C86B22ABD2AF00B8A43A /* JWTSwiftUI */, 0A883AB4266E166600DAF016 /* iOSJWTSwiftUI */, 0A883ACB266E191700DAF016 /* MacJWTSwiftUI */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 0A76C86A22ABD2AF00B8A43A /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 0A76C87C22ABD2B100B8A43A /* LaunchScreen.storyboard in Resources */, 0A76C87922ABD2B100B8A43A /* Preview Assets.xcassets in Resources */, 0A76C87622ABD2B100B8A43A /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; 0A883AB3266E166600DAF016 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 0A883ABF266E166900DAF016 /* Preview Assets.xcassets in Resources */, 0A883ABC266E166900DAF016 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; 0A883ACA266E191700DAF016 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 0A883AD6266E191A00DAF016 /* Preview Assets.xcassets in Resources */, 0A883AD3266E191A00DAF016 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 0A76C86822ABD2AF00B8A43A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 0A60395422B22BA700256661 /* JWTModel.swift in Sources */, 0A76C87022ABD2AF00B8A43A /* AppDelegate.swift in Sources */, 0A76C87222ABD2AF00B8A43A /* SceneDelegate.swift in Sources */, 0A76C87422ABD2AF00B8A43A /* ContentView.swift in Sources */, 0A76C88822ABE51800B8A43A /* BottomView.swift in Sources */, 0A76C88422ABD2F200B8A43A /* HeaderView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 0A883AB1266E166600DAF016 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 0A883AC4266E169900DAF016 /* BottomView.swift in Sources */, 0A883AC7266E169900DAF016 /* HeaderView.swift in Sources */, 0A883AC6266E169900DAF016 /* ContentView.swift in Sources */, 0A883AB8266E166600DAF016 /* iOSJWTSwiftUIApp.swift in Sources */, 0A883AC5266E169900DAF016 /* JWTModel.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 0A883AC8266E191700DAF016 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 0A883ACF266E191700DAF016 /* MacJWTSwiftUIApp.swift in Sources */, 0A883ADF266E192500DAF016 /* ContentView.swift in Sources */, 0A883ADD266E192500DAF016 /* HeaderView.swift in Sources */, 0A883ADC266E192500DAF016 /* JWTModel.swift in Sources */, 0A883ADE266E192500DAF016 /* BottomView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 0A76C87A22ABD2B100B8A43A /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( 0A76C87B22ABD2B100B8A43A /* Base */, ); name = LaunchScreen.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 0A76C87E22ABD2B100B8A43A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.5; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 0A76C87F22ABD2B100B8A43A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.5; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; VALIDATE_PRODUCT = YES; }; name = Release; }; 0A76C88122ABD2B100B8A43A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "JWTSwiftUI/Preview\\ Content"; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = JWTSwiftUI/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = org.example.JWTSwiftUI; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 0A76C88222ABD2B100B8A43A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "JWTSwiftUI/Preview\\ Content"; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = JWTSwiftUI/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = org.example.JWTSwiftUI; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; 0A883AC2266E166900DAF016 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"iOSJWTSwiftUI/Preview Content\""; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = iOSJWTSwiftUI/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = org.opensource.iOSJWTSwiftUI; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 0A883AC3266E166900DAF016 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"iOSJWTSwiftUI/Preview Content\""; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = iOSJWTSwiftUI/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = org.opensource.iOSJWTSwiftUI; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; 0A883ADA266E191A00DAF016 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = MacJWTSwiftUI/MacJWTSwiftUI.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_ASSET_PATHS = "\"MacJWTSwiftUI/Preview Content\""; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = MacJWTSwiftUI/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 11.3; PRODUCT_BUNDLE_IDENTIFIER = org.opensource.MacJWTSwiftUI; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; SWIFT_VERSION = 5.0; }; name = Debug; }; 0A883ADB266E191A00DAF016 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = MacJWTSwiftUI/MacJWTSwiftUI.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_ASSET_PATHS = "\"MacJWTSwiftUI/Preview Content\""; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = MacJWTSwiftUI/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 11.3; PRODUCT_BUNDLE_IDENTIFIER = org.opensource.MacJWTSwiftUI; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; SWIFT_VERSION = 5.0; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 0A76C86722ABD2AF00B8A43A /* Build configuration list for PBXProject "JWTSwiftUI" */ = { isa = XCConfigurationList; buildConfigurations = ( 0A76C87E22ABD2B100B8A43A /* Debug */, 0A76C87F22ABD2B100B8A43A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 0A76C88022ABD2B100B8A43A /* Build configuration list for PBXNativeTarget "JWTSwiftUI" */ = { isa = XCConfigurationList; buildConfigurations = ( 0A76C88122ABD2B100B8A43A /* Debug */, 0A76C88222ABD2B100B8A43A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 0A883AC1266E166900DAF016 /* Build configuration list for PBXNativeTarget "iOSJWTSwiftUI" */ = { isa = XCConfigurationList; buildConfigurations = ( 0A883AC2266E166900DAF016 /* Debug */, 0A883AC3266E166900DAF016 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 0A883AD9266E191A00DAF016 /* Build configuration list for PBXNativeTarget "MacJWTSwiftUI" */ = { isa = XCConfigurationList; buildConfigurations = ( 0A883ADA266E191A00DAF016 /* Debug */, 0A883ADB266E191A00DAF016 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ 0AABB95727A6A3C0006718A0 /* JWTDesktopSwiftToolkit */ = { isa = XCSwiftPackageProductDependency; productName = JWTDesktopSwiftToolkit; }; 0AABB95927A6A3C4006718A0 /* JWTDesktopSwiftToolkit */ = { isa = XCSwiftPackageProductDependency; productName = JWTDesktopSwiftToolkit; }; 0AC002752786598E002167AD /* JWTDesktopSwiftToolkit */ = { isa = XCSwiftPackageProductDependency; productName = JWTDesktopSwiftToolkit; }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 0A76C86422ABD2AF00B8A43A /* Project object */; } ================================================ FILE: Example/JWTSwiftUI/JWTSwiftUI.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Example/JWTSwiftUI/JWTSwiftUI.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: Example/JWTSwiftUI/MacJWTSwiftUI/Assets.xcassets/AccentColor.colorset/Contents.json ================================================ { "colors" : [ { "idiom" : "universal" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Example/JWTSwiftUI/MacJWTSwiftUI/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "mac", "scale" : "1x", "size" : "16x16" }, { "idiom" : "mac", "scale" : "2x", "size" : "16x16" }, { "idiom" : "mac", "scale" : "1x", "size" : "32x32" }, { "idiom" : "mac", "scale" : "2x", "size" : "32x32" }, { "idiom" : "mac", "scale" : "1x", "size" : "128x128" }, { "idiom" : "mac", "scale" : "2x", "size" : "128x128" }, { "idiom" : "mac", "scale" : "1x", "size" : "256x256" }, { "idiom" : "mac", "scale" : "2x", "size" : "256x256" }, { "idiom" : "mac", "scale" : "1x", "size" : "512x512" }, { "idiom" : "mac", "scale" : "2x", "size" : "512x512" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Example/JWTSwiftUI/MacJWTSwiftUI/Assets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Example/JWTSwiftUI/MacJWTSwiftUI/ContentView.swift ================================================ // // ContentView.swift // MacJWTSwiftUI // // Created by Dmitry Lobanov on 07.06.2021. // Copyright © 2021 Dmitry Lobanov. All rights reserved. // import SwiftUI struct ContentView: View { var body: some View { Text("Hello, world!") .padding() } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } ================================================ FILE: Example/JWTSwiftUI/MacJWTSwiftUI/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright Copyright © 2021 Dmitry Lobanov. All rights reserved. ================================================ FILE: Example/JWTSwiftUI/MacJWTSwiftUI/MacJWTSwiftUI.entitlements ================================================ com.apple.security.app-sandbox com.apple.security.files.user-selected.read-only ================================================ FILE: Example/JWTSwiftUI/MacJWTSwiftUI/MacJWTSwiftUIApp.swift ================================================ // // MacJWTSwiftUIApp.swift // MacJWTSwiftUI // // Created by Dmitry Lobanov on 07.06.2021. // Copyright © 2021 Dmitry Lobanov. All rights reserved. // import SwiftUI @main struct MacJWTSwiftUIApp: App { @StateObject private var model: JWTModel = .init(data: .RS256()) var body: some Scene { WindowGroup { ContentView.init(model: self.model) } } } ================================================ FILE: Example/JWTSwiftUI/MacJWTSwiftUI/Preview Content/Preview Assets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Example/JWTSwiftUI/iOSJWTSwiftUI/Assets.xcassets/AccentColor.colorset/Contents.json ================================================ { "colors" : [ { "idiom" : "universal" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Example/JWTSwiftUI/iOSJWTSwiftUI/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "scale" : "2x", "size" : "20x20" }, { "idiom" : "iphone", "scale" : "3x", "size" : "20x20" }, { "idiom" : "iphone", "scale" : "2x", "size" : "29x29" }, { "idiom" : "iphone", "scale" : "3x", "size" : "29x29" }, { "idiom" : "iphone", "scale" : "2x", "size" : "40x40" }, { "idiom" : "iphone", "scale" : "3x", "size" : "40x40" }, { "idiom" : "iphone", "scale" : "2x", "size" : "60x60" }, { "idiom" : "iphone", "scale" : "3x", "size" : "60x60" }, { "idiom" : "ipad", "scale" : "1x", "size" : "20x20" }, { "idiom" : "ipad", "scale" : "2x", "size" : "20x20" }, { "idiom" : "ipad", "scale" : "1x", "size" : "29x29" }, { "idiom" : "ipad", "scale" : "2x", "size" : "29x29" }, { "idiom" : "ipad", "scale" : "1x", "size" : "40x40" }, { "idiom" : "ipad", "scale" : "2x", "size" : "40x40" }, { "idiom" : "ipad", "scale" : "1x", "size" : "76x76" }, { "idiom" : "ipad", "scale" : "2x", "size" : "76x76" }, { "idiom" : "ipad", "scale" : "2x", "size" : "83.5x83.5" }, { "idiom" : "ios-marketing", "scale" : "1x", "size" : "1024x1024" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Example/JWTSwiftUI/iOSJWTSwiftUI/Assets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Example/JWTSwiftUI/iOSJWTSwiftUI/ContentView.swift ================================================ // // ContentView.swift // iOSJWTSwiftUI // // Created by Dmitry Lobanov on 07.06.2021. // Copyright © 2021 Dmitry Lobanov. All rights reserved. // import SwiftUI struct ContentView: View { var body: some View { Text("Hello, world!") .padding() } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } ================================================ FILE: Example/JWTSwiftUI/iOSJWTSwiftUI/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 LSRequiresIPhoneOS UIApplicationSceneManifest UIApplicationSupportsMultipleScenes UIApplicationSupportsIndirectInputEvents UILaunchScreen UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Example/JWTSwiftUI/iOSJWTSwiftUI/Preview Content/Preview Assets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Example/JWTSwiftUI/iOSJWTSwiftUI/iOSJWTSwiftUIApp.swift ================================================ // // iOSJWTSwiftUIApp.swift // iOSJWTSwiftUI // // Created by Dmitry Lobanov on 07.06.2021. // Copyright © 2021 Dmitry Lobanov. All rights reserved. // import SwiftUI @main struct iOSJWTSwiftUIApp: App { @StateObject private var model: JWTModel = .init(data: .RS256()) var body: some Scene { WindowGroup { ContentView.init(model: self.model) } } } ================================================ FILE: JWT.podspec ================================================ class VersionFile class << self def version File.new(self.filepath).gets.rstrip end def filepath './VERSION' end end end Pod::Spec.new do |s| s.name = 'JWT' s.version = "#{VersionFile.version}" s.summary = 'A JSON Web Token implementation in Objective-C.' s.homepage = "https://github.com/yourkarma/#{s.name}" s.license = { :type => 'MIT', :file => 'LICENSE' } s.author = { 'Klaas Pieter Annema' => 'klaaspieter@annema.me' } s.source = { :git => "https://github.com/yourkarma/#{s.name}.git", :tag => s.version.to_s } s.ios.deployment_target = '6.0' s.osx.deployment_target = '10.8' s.tvos.deployment_target = '9.0' s.watchos.deployment_target = '7.4' s.source_files = 'Sources/**/*.{h,m}' s.private_header_files = 'Sources/**/*Subclass.{hm}' s.module_name = s.name s.requires_arc = true s.framework = 'Security' s.dependency 'Base64', '~> 1.1.2' end ================================================ FILE: LICENSE ================================================ Copyright (c) 2013 Karma Mobility, Inc. 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. ================================================ FILE: Package.resolved ================================================ { "object": { "pins": [ { "package": "Base64", "repositoryURL": "https://github.com/lolgear/Base64", "state": { "branch": "distribution/swift_package_manager_support", "revision": "015ce993db89e0212c1ea0d5aa845abb478d4313", "version": null } } ] }, "version": 1 } ================================================ FILE: Package.swift ================================================ // swift-tools-version:5.4 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "JWT", platforms: [ .iOS(.v9), .macOS(.v10_10), .watchOS(.v3), .tvOS(.v9), ], products: [ // Products define the executables and libraries produced by a package, and make them visible to other packages. .library( name: "JWT", targets: ["JWT"] ) ], dependencies: [.package(url: "https://github.com/lolgear/Base64", .branchItem("distribution/swift_package_manager_support"))], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages which this package depends on. .target( name: "JWT", dependencies: ["Base64"] ), .testTarget( name: "JWTTests", dependencies: ["JWT"] ), ] ) ================================================ FILE: README.md ================================================ [![JWT](http://jwt.io/assets/logo.svg)](https://jwt.io/) [![Build Status](https://travis-ci.org/yourkarma/JWT.svg?branch=master)](https://travis-ci.org/yourkarma/JWT) [![Pod Version](http://img.shields.io/cocoapods/v/JWT.svg?style=flat)](http://cocoadocs.org/docsets/JWT) [![Pod Platform](http://img.shields.io/cocoapods/p/JWT.svg?style=flat)](http://cocoadocs.org/docsets/JWT) [![Gitter](https://badges.gitter.im/ObjectiveC-JWT/community.svg)](https://gitter.im/ObjectiveC-JWT/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) # JWT A [JSON Web Token][] implementation in Objective-C. [JSON Web Token]: http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html # What's new in master and bleeding edge. * Version Three release (?) * [Custom Claims](Documentation/Prerelease/custom_claims.md). * EC algorithms support. * Keys extraction from Pem files has been updated. ## Custom Claims. ### Deprecation. Old ClaimsSet API has been deprecated and will be removed in API version 3.0. ### Process. 1. Define custom serializer for a claim. 2. Define custom verifier for a claim. 3. Register new claim with serializer and verifier at claims set coordinator. ### [Example](Documentation/Prerelease/custom_claims.md). ```objective-c - (void)test { /// Setup ClaimsSetCoordinator __auto_type claim = JWTClaimVariations.intersectionOfIntervals; __auto_type claimSerializer = JWTClaimSerializerVariations.interval; __auto_type claimVerifier = JWTClaimVerifierVariations.intersection; id claimsSetCoordinator = [JWTClaimsSetCoordinatorBase new]; [claimsSetCoordinator registerClaim:claim serializer:claimSerializer verifier:claimVerifier forClaimName:JWTClaimsNames.intersectionOfIntervals]; __auto_type deserialized = ({ claimsSetCoordinator.configureClaimsSet(^JWTClaimsSetDSLBase *(JWTClaimsSetDSLBase *claimsSetDSL) { claimsSetDSL.intersection = @[@(2), @(5)]; return claimsSetDSL; }); self.claimsSetCoordinator.claimsSetStorage; }); __auto_type serialized = ({ __auto_type dictionary = [self.claimsSetCoordinator.claimsSetSerializer dictionaryFromClaimsSet:deserialized]; dictionary; }); __auto_type result = @{ JWTClaimsNames.intersectionOfIntervals : @"2,5" }; XCTAssertEqual(serialized.count, 1); XCTAssertEqualObjects(serialized, result); } ``` ## EC algorithms support. ### Prerequisites. * Certificate and P12 for Public and Private keys accordingly. * Pem files with keys in *ANSI X9.63* format. ### Example. ```objective-c NSString *privateKeyString = @""; NSString *publicKeyString = @""; // Note: We should pass type of key. Default type is RSA. NSDictionary *parameters = @{JWTCryptoKey.parametersKeyBuilder : JWTCryptoKeyBuilder.new.keyTypeEC}; id privateKey = [[JWTCryptoKeyPrivate alloc] initWithPemEncoded:privateKeyString parameters:parameters error:nil]; id publicKey = [[JWTCryptoKeyPublic alloc] initWithPemEncoded:publicKeyString parameters:parameters error:nil]; // Note: JWTAlgorithmRSFamilyDataHolder will be renamed to something more appropriate. It can holds any asymmetric keys pair (private and public). id holder = [JWTAlgorithmRSFamilyDataHolder new].signKey(privateKey).verifyKey(publicKey).algorithmName(JWTAlgorithmNameES256); ``` # What's new in Version 3.0 * Fluent style expanded. * Coding result types added. * Algorithms and data holders. * Algorithms and data holders chain. * Keys loaded from Pem files. ## Introduction to Algorithms data holders and chain. You have an algorithm, a secret data and an unknown jwt token. Let's try to decode it. ```objective-c // create token NSString *token = @"..."; // possible that algorithm could return error. // you could try use algorithm and data chain. NSString *firstSecret = @"first"; NSString *firstAlgorithmName = JWTAlgorithmNameHS384; id firstHolder = [JWTAlgorithmHSFamilyDataHolder new].algorithmName(firstAlgorithmName).secret(firstSecret); id errorHolder = [JWTAlgorithmNoneDataHolder new]; // chain together. JWTAlgorithmDataHolderChain *chain = [[JWTAlgorithmDataHolderChain alloc] initWithHolders:@[firstHolder, errorHolder]]; // or add them in builder [JWTDecodingBuilder decodeMessage:token].addHolder(firstHolder).addHolder(errorHolder); // or add them as chain [JWTDecodingBuilder decodeMessage:token].chain(chain); ``` Maybe you would like to try different secrets. ```objective-c // possible that your algorithm has several secrets. // you don't know which secret to use. // but you want to decode it. NSString *firstSecret = @"first"; NSArray *manySecrets = @[@"second", @"third", @"forty two"]; // translate to data NSArray *manySecretsData = @[]; for (NSString *secret in manySecrets) { NSData *secretData = [JWTBase64Coder dataWithBase64UrlEncodedString:secret]; if (secret) { manySecretsData = [manySecretsData arrayByAddingObject:secretData]; } } NSString *algorithmName = JWTAlgorithmNameHS384; id firstHolder = [JWTAlgorithmHSFamilyDataHolder new].algorithmName(algorithmName).secret(firstSecret); // lets create chain JWTAlgorithmDataHolderChain *chain = [JWTAlgorithmDataHolderChain chainWithHolder:firstHolder]; // and lets populate chain with secrets. NSLog(@"chain has: %@", chain.debugDescription); JWTAlgorithmDataHolderChain *expandedChain = [chain chainByPopulatingAlgorithm:firstHolder.currentAlgorithm withManySecretData:manySecretsData]; // now we have expanded chain with many secrets and one algorithm. NSLog(@"expanded chain has: %@", expandedChain.debugDescription); ``` ## Decode and encode with chain. ```objective-c JWTClaimsSet *claimsSet = [[JWTClaimsSet alloc] init]; // fill it claimsSet.issuer = @"Facebook"; claimsSet.subject = @"Token"; claimsSet.audience = @"https://jwt.io"; // encode it NSString *secret = @"secret"; NSString *algorithmName = @"HS384"; NSDictionary *headers = @{@"custom":@"value"}; idholder = [JWTAlgorithmHSFamilyDataHolder new].algorithmName(algorithmName).secret(secret); JWTCodingResultType *result = [JWTEncodingBuilder encodeClaimsSet:claimsSet].headers(headers).addHolder(holder).result; NSString *encodedToken = result.successResult.encoded; if (result.successResult) { // handle encoded result NSLog(@"encoded result: %@", result.successResult.encoded); } else { // handle error NSLog(@"encode failed, error: %@", result.errorResult.error); } // decode it // you can set any property that you want, all properties are optional JWTClaimsSet *trustedClaimsSet = [claimsSet copy]; NSNumber *options = @(JWTCodingDecodingOptionsNone); NSString *yourJwt = encodedToken; // from previous example JWTCodingResultType *decodedResult = [JWTDecodingBuilder decodeMessage:yourJwt].claimsSet(claimsSet).addHolder(holder).options(options).and.result; if (decodedResult.successResult) { // handle decoded result NSLog(@"decoded result: %@", decodedResult.successResult.headerAndPayloadDictionary); NSLog(@"headers: %@", decodedResult.successResult.headers); NSLog(@"payload: %@", decodedResult.successResult.payload); } else { // handle error NSLog(@"decode failed, error: %@", decodedResult.errorResult.error); } ``` ## Keys loaded from Pem files. You have a key in pem file. And you want to use it directly for sign/verify. Suppose, that "public_rsa.pem" and "private_rsa.pem" are public and private keys in pem format. ```objective-c // Load keys - (NSString *)pemKeyStringFromFileWithName:(NSString *)string inBundle:(NSBundle *)bundle { NSURL *fileURL = [bundle URLForResource:name withExtension:@"pem"]; NSError *error = nil; NSString *fileContent = [NSString stringWithContentsOfURL:fileURL encoding:NSUTF8StringEncoding error:&error]; if (error) { NSLog(@"%@ error: %@", self.debugDescription, error); return nil; } } // Sign and verify - (void)signAndVerifyWithPrivateKeyPemString:(NSString *)privateKey publicKeyPemString:(NSString *)publicKey privateKeyPassphrase:(NSString *)passphrase { NSString *algorithmName = @"RS256"; id signDataHolder = [JWTAlgorithmRSFamilyDataHolder new].keyExtractorType([JWTCryptoKeyExtractor privateKeyWithPEMBase64].type).privateKeyCertificatePassphrase(passphrase).algorithmName(algorithmName).secret(privateKey); id verifyDataHolder = [JWTAlgorithmRSFamilyDataHolder new].keyExtractorType([JWTCryptoKeyExtractor publicKeyWithPEMBase64].type).algorithmName(algorithmName).secret(publicKey); // sign NSDictionary *payloadDictionary = @{@"hello": @"world"}; JWTCodingBuilder *signBuilder = [JWTEncodingBuilder encodePayload:payloadDictionary].addHolder(signDataHolder); JWTCodingResultType *signResult = signBuilder.result; NSString *token = nil; if (signResult.successResult) { // success NSLog(@"%@ success: %@", self.debugDescription, signResult.successResult.encoded); token = signResult.successResult.encoded; } else { // error NSLog(@"%@ error: %@", self.debugDescription, signResult.errorResult.error); } // verify if (token == nil) { NSLog(@"something wrong"); } JWTCodingBuilder *verifyBuilder = [JWTDecodingBuilder decodeMessage:token].addHolder(verifyDataHolder); JWTCodingResultType *verifyResult = verifyBuilder.result; if (verifyResult.successResult) { // success NSLog(@"%@ success: %@", self.debugDescription, verifyResult.successResult.payload); token = verifyResult.successResult.encoded; } else { // error NSLog(@"%@ error: %@", self.debugDescription, verifyResult.errorResult.error); } } ``` # Experiments in Version 2.0 ## Whitelists possible algorithms. When you need to decode jwt by several algorithms you could specify their names in whitelist. Later this feature possible will migrate to options. For example, someone returns result or error. ### Limitations Restricted to pair (algorithm or none) due to limitations of unique `secret`. ```objective-c NSString *jwtResultOrError = /*...*/; NSString *secret = @"secret"; JWTBuilder *builder = [JWT decodeMessage:jwtResultOrError].secret(@"secret").whitelist(@[@"HS256", @"none"]); NSDictionary *decoded = builder.decode; if (builder.jwtError) { // oh! } else { NSDictionary *payload = decoded[@"payload"]; NSDictionary *header = decoded[@"header"]; NSArray *tries = decoded[@"tries"]; // will be evolded into something appropriate later. } ``` # What's new in Version 2.0 * Old plain style deprecated. * Use modern fluent style instead. ```objective-c NSDictionary *payload = @{@"foo" : @"bar"}; NSString *secret = @"secret"; id algorithm = [JWTAlgorithmFactory algorithmByName:@"HS256"]; // Deprecated [JWT encodePayload:payload withSecret:secret algorithm:algorithm]; // Modern [JWTBuilder encodePayload:payload].secret(secret).algorithm(algorithm).encode; ``` # Installation Add the following to your [CocoaPods][] Podfile: pod "JWT" [CocoaPods]: http://cocoapods.org Install via Cartfile: github "yourkarma/JWT" "master" and `import JWT` # Documentation # Usage ## JWTBuilder To encode & decode JWTs, use fluent style with the `JWTBuilder` interface ```objective-c + (JWTBuilder *)encodePayload:(NSDictionary *)payload; + (JWTBuilder *)encodeClaimsSet:(JWTClaimsSet *)claimsSet; + (JWTBuilder *)decodeMessage:(NSString *)message; ``` As you can see, JWTBuilder has interface from both decoding and encoding. Note: some attributes are encode-only or decode-only. #pragma mark - Encode only *payload; *headers; *algorithm; #pragma mark - Decode only *message *options // as forcedOption from jwt decode functions interface. *whitelist //optional array of algorithm names to whitelist for decoding You can inspect JWTBuilder by `jwt`-prefixed attributes. You can set JWTBuilder attributes by fluent style (block interface). You can encode arbitrary payloads like so: ```objective-c NSDictionary *payload = @{@"foo" : @"bar"}; NSString *secret = @"secret"; id algorithm = [JWTAlgorithmFactory algorithmByName:@"HS256"]; [JWTBuilder encodePayload:payload].secret(@"secret").algorithm(algorithm).encode; ``` If you're using reserved claim names you can encode your claim set like so (all properties are optional): ```objective-c JWTClaimsSet *claimsSet = [[JWTClaimsSet alloc] init]; claimsSet.issuer = @"Facebook"; claimsSet.subject = @"Token"; claimsSet.audience = @"http://yourkarma.com"; claimsSet.expirationDate = [NSDate distantFuture]; claimsSet.notBeforeDate = [NSDate distantPast]; claimsSet.issuedAt = [NSDate date]; claimsSet.identifier = @"thisisunique"; claimsSet.type = @"test"; NSString *secret = @"secret"; id algorithm = [JWTAlgorithmFactory algorithmByName:@"HS256"]; [JWTBuilder encodeClaimsSet:claimsSet].secret(secret).algorithm(algorithm).encode; ``` You can decode a JWT like so: ```objective-c NSString *jwtToken = @"header.payload.signature"; NSString *secret = @"secret"; NSString *algorithmName = @"HS256"; //Must specify an algorithm to use NSDictionary *payload = [JWTBuilder decodeMessage:jwtToken].secret(secret).algorithmName(algorithmName).decode; ``` If you want to check claims while decoding, you could use next sample of code (all properties are optional): ```objective-c // Trusted Claims Set JWTClaimsSet *trustedClaimsSet = [[JWTClaimsSet alloc] init]; trustedClaimsSet.issuer = @"Facebook"; trustedClaimsSet.subject = @"Token"; trustedClaimsSet.audience = @"http://yourkarma.com"; trustedClaimsSet.expirationDate = [NSDate date]; trustedClaimsSet.notBeforeDate = [NSDate date]; trustedClaimsSet.issuedAt = [NSDate date]; trustedClaimsSet.identifier = @"thisisunique"; trustedClaimsSet.type = @"test"; NSString *message = @"encodedJwt"; NSString *secret = @"secret"; NSString *algorithmName = @"chosenAlgorithm" JWTBuilder *builder = [JWTBuilder decodeMessage:jwt].secret(secret).algorithmName(algorithmName).claimsSet(trustedClaimsSet); NSDictionary *payload = builder.decode; if (builder.jwtError == nil) { // do your work here } else { // handle error } ``` If you want to enforce a whitelist of valid algorithms: ```objective-c NSArray *whitelist = @[@"HS256", @"HS512"]; NSString *jwtToken = @"header.payload.signature"; NSString *secret = @"secret"; NSString *algorithmName = @"HS256"; //Returns nil NSDictionary *payload = [JWTBuilder decodeMessage:jwtToken].secret(secret).algorithmName(algorithmName).whitelist(@[]).decode; //Returns the decoded payload NSDictionary *payload = [JWTBuilder decodeMessage:jwtToken].secret(secret).algorithmName(algorithmName).whitelist(whitelist).decode; ``` ### Encode / Decode Example ```objective-c // suppose, that you create ClaimsSet JWTClaimsSet *claimsSet = [[JWTClaimsSet alloc] init]; // fill it claimsSet.issuer = @"Facebook"; claimsSet.subject = @"Token"; claimsSet.audience = @"http://yourkarma.com"; // encode it NSString *secret = @"secret"; NSString *algorithmName = @"HS384"; NSDictionary *headers = @{@"custom":@"value"}; id algorithm = [JWTAlgorithmFactory algorithmByName:algorithmName]; JWTBuilder *encodeBuilder = [JWT encodeClaimsSet:claimsSet]; NSString *encodedResult = encodeBuilder.secret(secret).algorithm(algorithm).headers(headers).encode; if (encodeBuilder.jwtError == nil) { // handle encoded result NSLog(@"encoded result: %@", encodedResult); } else { // handle error NSLog(@"encode failed, error: %@", encodeBuilder.jwtError); } // decode it // you can set any property that you want, all properties are optional JWTClaimsSet *trustedClaimsSet = [claimsSet copy]; // decode forced ? try YES BOOL decodeForced = NO; NSNumber *options = @(decodeForced); NSString *yourJwt = encodedResult; // from previous example NSString *yourSecret = secret; // from previous example NSString *yourAlgorithm = algorithmName; // from previous example JWTBuilder *decodeBuilder = [JWT decodeMessage:yourJwt]; NSDictionary *decodedResult = decodeBuilder.message(yourJwt).secret(yourSecret).algorithmName(yourAlgorithm).claimsSet(trustedClaimsSet).options(options).decode; if (decodeBuilder.jwtError == nil) { // handle decoded result NSLog(@"decoded result: %@", decodedResult); } else { // handle error NSLog(@"decode failed, error: %@", decodeBuilder.jwtError); } ``` #### NSData You can also encode/decode using a secret that is represented as an NSData object ```objective-c //Encode NSData *secretData = ""; NSString *algorithmName = @"HS384"; NSDictionary *headers = @{@"custom":@"value"}; id algorithm = [JWTAlgorithmFactory algorithmByName:algorithmName]; JWTBuilder *encodeBuilder = [JWT encodeClaimsSet:claimsSet]; NSString *encodedResult = encodeBuilder.secretData(secretData).algorithm(algorithm).headers(headers).encode; //Decode NSString *jwtToken = @"header.payload.signature"; NSData *secretData = "" NSString *algorithmName = @"HS256"; //Must specify an algorithm to use NSDictionary *payload = [JWTBuilder decodeMessage:jwtToken].secretData(secretData).algorithmName(algorithmName).decode; ``` # Algorithms The following algorithms are supported: * RS256 * HS512 - HMAC using SHA-512. * HS256 / HS384 / HS512 * None ## RS256 usage. For example, you have your file with privateKey: `file.p12`. And you have a secret passphrase for that file: `secret`. ```objective-c // Encode NSDictionary *payload = @{@"payload" : @"hidden_information"}; NSString *algorithmName = @"RS256"; NSString *filePath = [[NSBundle mainBundle] pathForResource:@"secret_key" ofType:@"p12"]; NSData *privateKeySecretData = [NSData dataWithContentsOfFile:filePath]; NSString *passphraseForPrivateKey = @"secret"; JWTBuilder *builder = [JWTBuilder encodePayload:payload].secretData(privateKeySecretData).privateKeyCertificatePassphrase(passphraseForPrivateKey).algorithmName(algorithmName); NSString *token = builder.encode; // check error if (builder.jwtError == nil) { // handle result } else { // error occurred. } // Decode // Suppose, that you get token from previous example. You need a valid public key for a private key in previous example. // Private key stored in @"secret_key.p12". So, you need public key for that private key. NSString *publicKey = @"..."; // load public key. Or use it as raw string. algorithmName = @"RS256"; JWTBuilder *decodeBuilder = [JWTBuilder decodeMessage:token].secret(publicKey).algorithmName(algorithmName); NSDictionary *envelopedPayload = decodeBuilder.decode; // check error if (decodeBuilder.jwtError == nil) { // handle result } else { // error occurred. } ``` Additional algorithms can be added by implementing the `JWTAlgorithm` protocol. ## Before pull request Please, read [Contribution notes](https://github.com/yourkarma/JWT/blob/master/.github/CONTRIBUTING.md) before make pull request. ## Powered by [![JetBrains](https://www.jetbrains.com/apple-touch-icon-180x180.png)](https://www.jetbrains.com) ================================================ FILE: Scripts/Test certificate and public key 1.pem ================================================ -----BEGIN CERTIFICATE----- MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQsFADBKMR0wGwYDVQQDDBREaWdp dGFsIFNpZ25pbmcgVGVzdDELMAkGA1UEBhMCQVUxHDAaBgkqhkiG9w0BCQEWDXRl c3RAdGVzdC5jb20wHhcNMTYwMzEwMjM0ODQ2WhcNMTcwMzEwMjM0ODQ2WjBKMR0w GwYDVQQDDBREaWdpdGFsIFNpZ25pbmcgVGVzdDELMAkGA1UEBhMCQVUxHDAaBgkq hkiG9w0BCQEWDXRlc3RAdGVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQD2G4yWiZX9H4CsbWWpHT/bfRid7yU569j9f2gSB6kYv9wMsd/Crx2p HwIT5uK9gTJ4+5PYaeweB3Tu7uo9ob4EG83k2VF26ruRflzBaSzE4TotxuNoE83B VKFoR1oPdg3BmT7qPCRshz6b36zXfxVQgBYU2F2nUQKbjqCiFEs6w2VrbG5RQwHL EwmLwDu3WPFOwuO2aPP0dRh1E25DeZlzqNFcYaoAf5wEmwWn79oOmzETWh0uTHTg dCrZSp48ZvXf9iFZgqd5HIt0Ub5x5ZYuSZz5FJ8GRRp/0s4q4FG2T0XHsUkvnoMO KGkPUmkpFk4CKZa5BnnKIDGQMr2ndjaNAgMBAAGjRDBCMA4GA1UdDwEB/wQEAwIH gDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDBDAYBgNVHREEETAPgQ10ZXN0QHRlc3Qu Y29tMA0GCSqGSIb3DQEBCwUAA4IBAQDcOYflkAlubGJlv5T1G7PdcHzMzu6doah/ 9RmRyHS8wehc0GljYIyBkhbBG/iRumi6nnnU3BARv+JdSHbpIVsRaXmImWv5I/GO OfUO6UY7jlsw1mCjQyIIZoOFyUKnbcvrb0bCryD3rcbAflYg8feq3AiQv3CacxOy IbYh3khqbs1jKSAzxEdcsuHRB+by5gpwMfF5ByGdMmMl81mFMUuGlcWsfZp2N4Vz 7MWVRl38OWkwZ0yw/Jpd1kcVwKIrXF3rjA71AN41rzyMvvPaEfdgCyFolixEOoJH Fdidq1Bf0liKxf+MFJOaxSWKGqrvzPoBfmwCFoPahuaUlVZ4lGvr -----END CERTIFICATE----- -----BEGIN RSA PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9huMlomV/R+ArG1lqR0/ 230Yne8lOevY/X9oEgepGL/cDLHfwq8dqR8CE+bivYEyePuT2GnsHgd07u7qPaG+ BBvN5NlRduq7kX5cwWksxOE6LcbjaBPNwVShaEdaD3YNwZk+6jwkbIc+m9+s138V UIAWFNhdp1ECm46gohRLOsNla2xuUUMByxMJi8A7t1jxTsLjtmjz9HUYdRNuQ3mZ c6jRXGGqAH+cBJsFp+/aDpsxE1odLkx04HQq2UqePGb13/YhWYKneRyLdFG+ceWW Lkmc+RSfBkUaf9LOKuBRtk9Fx7FJL56DDihpD1JpKRZOAimWuQZ5yiAxkDK9p3Y2 jQIDAQAB -----END RSA PUBLIC KEY----- ================================================ FILE: Scripts/Test certificate and public key 2.pem ================================================ -----BEGIN CERTIFICATE----- MIIDVzCCAj+gAwIBAgIBATANBgkqhkiG9w0BAQsFADBMMR8wHQYDVQQDDBZEaWdp dGFsIFNpZ25pbmcgVGVzdCAyMQswCQYDVQQGEwJBVTEcMBoGCSqGSIb3DQEJARYN dGVzdEB0ZXN0LmNvbTAeFw0xNjAzMTIwMDUzMDJaFw0xNzAzMTIwMDUzMDJaMEwx HzAdBgNVBAMMFkRpZ2l0YWwgU2lnbmluZyBUZXN0IDIxCzAJBgNVBAYTAkFVMRww GgYJKoZIhvcNAQkBFg10ZXN0QHRlc3QuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAtQ57lsgAE5eWahnJ4e9InudO6rtJ12qE/qaeBrU8qcmJ0ku7 8Ih2gnShRtdmJGaDgGH1hM6J+ucQvl87foNqJPeAN+s5GeiGw4yoaHTnibJ9/v8r zz+PzMwXn6EGykaL6eDAIIOKNcMXvjWZEXtwr/roOFbaEIe6JeqNeSb2mXS+1XI5 NGCL4jp8y0WmNCp/0LUMGQyj2ilmIgaV74cB2xdxPozZZJnWDASkgbGzi4ijZCpO P/yksEvJ7JSNBmmAQoFNslMymOO3XYJs3yvR9thwRl/uHbY4gHRPGHramCdJ6s+L w+gzCjslB87HsIy4pp6PeDiOe/tyc79LWcsLbQIDAQABo0QwQjAOBgNVHQ8BAf8E BAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwQwGAYDVR0RBBEwD4ENdGVzdEB0 ZXN0LmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAmlDHOKSdE8sRbUHNWZtyghm7FUBc rEEB/mM/dtRbq7aUFEPtHpXdKGf/fC0TZxdLoKfIFvgEuPlvzwgFhHTW3qzY4dES 0n2krALVkfT0IR72vR98AGEE2gchSqGtwr1KkvYE8A4IwU+mlrDzVZoE0OjRg73K lpaxc77ln34CB+yAIlL1uunIZj+zmCuhsK4i6QAjzJ1PaNXo5P9F4zfJDW4B0ej6 /2V9nxBvWW8hdba/eVbDltkvw0dZZay6YgBmVz9mXbAGZ6pk2XOjTlS3XLFgLUVe 8WTXbktQw0cCcf3xfn6HB/Y+5l/0srZ3i5Su5qtdDDbZ3epBjB3K5kiP8g== -----END CERTIFICATE----- -----BEGIN RSA PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtQ57lsgAE5eWahnJ4e9I nudO6rtJ12qE/qaeBrU8qcmJ0ku78Ih2gnShRtdmJGaDgGH1hM6J+ucQvl87foNq JPeAN+s5GeiGw4yoaHTnibJ9/v8rzz+PzMwXn6EGykaL6eDAIIOKNcMXvjWZEXtw r/roOFbaEIe6JeqNeSb2mXS+1XI5NGCL4jp8y0WmNCp/0LUMGQyj2ilmIgaV74cB 2xdxPozZZJnWDASkgbGzi4ijZCpOP/yksEvJ7JSNBmmAQoFNslMymOO3XYJs3yvR 9thwRl/uHbY4gHRPGHramCdJ6s+Lw+gzCjslB87HsIy4pp6PeDiOe/tyc79LWcsL bQIDAQAB -----END RSA PUBLIC KEY----- ================================================ FILE: Scripts/cert_1.cer ================================================ -----BEGIN CERTIFICATE----- MIIB5DCCAY4CCQCShy5E2kz5+jANBgkqhkiG9w0BAQUFADB5MQswCQYDVQQGEwJS VTEPMA0GA1UECBMGTW9zY293MQ8wDQYDVQQHEwZNb3Njb3cxDzANBgNVBAoTBk1v c2NvdzEPMA0GA1UECxMGTW9zY293MQ8wDQYDVQQDEwZNb3Njb3cxFTATBgkqhkiG 9w0BCQEWBk1vc2NvdzAeFw0xNzAxMjgxNTIxMzVaFw0xNzAyMjcxNTIxMzVaMHkx CzAJBgNVBAYTAlJVMQ8wDQYDVQQIEwZNb3Njb3cxDzANBgNVBAcTBk1vc2NvdzEP MA0GA1UEChMGTW9zY293MQ8wDQYDVQQLEwZNb3Njb3cxDzANBgNVBAMTBk1vc2Nv dzEVMBMGCSqGSIb3DQEJARYGTW9zY293MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB ANY7AQ5MmRhLWrnj3Awbtq3FDMEW9IhNxYuHPtCChpNX505L06NMN2GbtrDFvkMW EQpnvblFxme9KPEt3bEMg+8CAwEAATANBgkqhkiG9w0BAQUFAANBAEwYPzEOfqcg BbwuparrzcvwGBNS7RCQZnw/3+WfbGtS1TlNukNBK9apnpax5z1vsnBVcO+yDN5y VLuautgkfKY= -----END CERTIFICATE----- ================================================ FILE: Scripts/cert_1.crt ================================================ -----BEGIN CERTIFICATE----- MIIB5DCCAY4CCQD1AAN2e7b6+jANBgkqhkiG9w0BAQUFADB5MQswCQYDVQQGEwJS VTEPMA0GA1UECBMGTW9zY293MQ8wDQYDVQQHEwZNb3Njb3cxDzANBgNVBAoTBk1v c2NvdzEPMA0GA1UECxMGTW9zY293MQ8wDQYDVQQDEwZNb3Njb3cxFTATBgkqhkiG 9w0BCQEWBk1vc2NvdzAeFw0xNzAxMjgxNTIyMTlaFw0xNzAyMjcxNTIyMTlaMHkx CzAJBgNVBAYTAlJVMQ8wDQYDVQQIEwZNb3Njb3cxDzANBgNVBAcTBk1vc2NvdzEP MA0GA1UEChMGTW9zY293MQ8wDQYDVQQLEwZNb3Njb3cxDzANBgNVBAMTBk1vc2Nv dzEVMBMGCSqGSIb3DQEJARYGTW9zY293MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB ANY7AQ5MmRhLWrnj3Awbtq3FDMEW9IhNxYuHPtCChpNX505L06NMN2GbtrDFvkMW EQpnvblFxme9KPEt3bEMg+8CAwEAATANBgkqhkiG9w0BAQUFAANBAEiI7mohwYCV FV1LPDJxKd95QdWpy/GA9BjytaG89jHdt0jxJztjYColM057I+9zkTSsgvlzifw8 4V/JcNzei80= -----END CERTIFICATE----- ================================================ FILE: Scripts/cert_1.csr ================================================ -----BEGIN CERTIFICATE REQUEST----- MIIBYjCCAQwCAQAweTELMAkGA1UEBhMCUlUxDzANBgNVBAgTBk1vc2NvdzEPMA0G A1UEBxMGTW9zY293MQ8wDQYDVQQKEwZNb3Njb3cxDzANBgNVBAsTBk1vc2NvdzEP MA0GA1UEAxMGTW9zY293MRUwEwYJKoZIhvcNAQkBFgZNb3Njb3cwXDANBgkqhkiG 9w0BAQEFAANLADBIAkEA1jsBDkyZGEtauePcDBu2rcUMwRb0iE3Fi4c+0IKGk1fn TkvTo0w3YZu2sMW+QxYRCme9uUXGZ70o8S3dsQyD7wIDAQABoC4wFQYJKoZIhvcN AQkCMQgTBk1vc2NvdzAVBgkqhkiG9w0BCQcxCBMGc2VjcmV0MA0GCSqGSIb3DQEB BQUAA0EAxWLEcXTTN180TaopGkXGNi7i1TasmeCDawbrBRXpvXZcterzpgGLO2qM KbdMi4EjByhZujSqYzbhGztw+pYEAA== -----END CERTIFICATE REQUEST----- ================================================ FILE: Scripts/ci-xcode-select.sh ================================================ #!/bin/bash sudo xcode-select -s /Applications/Xcode_13.2.1.app/Contents/Developer ================================================ FILE: Scripts/generate_ec_curved_keys.rb ================================================ require 'optparse' require 'shellwords' require 'pathname' class ShellExecutor @@dry_run = false class << self # setup def setup (dry_run = false) @@dry_run = dry_run end def dry? puts "Condition statement is #{@@dry_run.to_s}" @@dry_run end def run_command_line(line) puts "I will perform \n <#{line}>" if dry? puts "I am on dry run!" else # if run result = %x(#{line}) puts "result is:" + result.to_s if $? != 0 puts "I fall down on < #{result} >\n! because of < #{$?} >" exit($?) end result end end end end class KeysGenerator module FileFormatsModule def only_name(name) # remove extension Pathname.new(name).basename end def to_plain_text(name) self.only_name(name).sub_ext('.txt') end def to_p12(name) # remove extension # add .p12 self.only_name(name).sub_ext('.p12') end def to_certificate_request(name) # remove extension # add .csr self.only_name(name).sub_ext('.csr') end def to_certificate(name, format = '.cer') # remove extension # add .cer self.only_name(name).sub_ext(format) end def to_pem(name) # remove extension # add .pem self.only_name(name).sub_ext('.pem') end end class FileFormats class << self include FileFormatsModule end attr_accessor :name def initialize(name) self.name = @name end def valid? !self.name.nil? end def to_p12 self.class.to_p12(self.name) end def to_certificate_requets self.class.to_certificate_request(self.name) end def to_certificate self.class.to_certificate(self.name) end def to_pem self.class.to_pem(self.name) end end class << self def available_ec_curves # secp256r1 - alias? %w(prime256v1 secp384r1 secp512r1) end def available_rsa_sizes [ 2048, 3072, 4096 ] end end attr_accessor :type, :curve_name, :rsa_size, :secret def initialize(secret = 'secret') self.secret = secret end TYPES = [:ec, :rsa] def type=(value) @type = value.downcase.to_sym end def valid? self.class::TYPES.include?(self.type) end def fix @curve_name ||= self.class.available_ec_curves.first if self.type == :ec @rsa_size ||= self.class.available_rsa_sizes.first if self.type == :rsa end def to_s { key_type: self.type, curve_name: self.curve_name, rsa_size: self.rsa_size, rsa_private_key_passphrase: self.secret } end module Generating def default_subject { "C": "GB", "ST": "London", "L": "London", "O": "Global Security", "OU": "IT Department", "CN": "example.com" } end def key_and_value_or_empty(key, value, delimiter, empty = -> (v){ v.nil? || v.empty?}) the_empty = empty #empty || -> (v){ v.nil? || v.empty?} {key => value}.reject{|k,v| the_empty.call(v)}.collect{|k,v| "#{k}#{delimiter}#{v}"}.join('') end def subject_value_from_subject(subject = {}) value = subject.collect{|k,v| "/#{k}=#{v}"}.join('') value end def subject_key_and_value_from_subject(subject = {}) value = subject_value_from_subject(subject) {'-subj': value}.reject{|k,v| v.empty?}.collect{|k,v| "#{k} \"#{v}\""}.join('') end def tool %q(openssl) end def suppress_prompt(command) %Q(echo '#{secret}' | #{command}) end def generate_key(type, name, parameters) case type when :rsa size = parameters[:size] rsa_private_key_passphrase = parameters[:rsa_private_key_passphrase] #%Q(#{tool} genrsa -des3 -out #{name} #{size} -passin 'password') #%Q(#{tool} genrsa -aes256 -passin pass:#{rsa_private_key_passphrase} -out #{name} #{size}) # ssh-keygen -t rsa -b 4096 -f jwtRS256.key -q -N secret_phrase ( -N - NewPassphrase ) # -q -N #{rsa_private_key_passphrase} %Q(echo "y" | ssh-keygen -t #{type} -b #{size} -f #{name} -q -N '') when :ec curve_name = parameters[:curve_name] %Q(#{tool} ecparam -name #{curve_name} -genkey -noout -out #{name}) end end # def generate_key_rsa(parameter, name) # %Q(#{tool} genrsa -des3 -out #{name} #{size} -passin 'password') # # %Q(#{tool} genrsa -name #{parameter} -genkey -noout -out #{name}) # end # def generate_key_ec(curve_name, name) # %Q(#{tool} ecparam -name #{curve_name} -genkey -noout -out #{name}) # end # output keys def output_key(access, generated_key_name, name) %Q(#{tool} #{access == 'private' ? '' : '-pubout' } -in #{generated_key_name} -out #{name} < echo "#{secret}") end def output_public_key(generated_key_name, name) output_key('public', generated_key_name, name) end def output_private_key(generated_key_name, name) output_key('private', generated_key_name, name) end def export_public_key(type, private_key_pem, public_key_pem) %Q(#{tool} #{type} -in #{private_key_pem} -pubout -out #{public_key_pem}) #openssl ec -in ec256-private.pem -pubout -out ec256-public.pem end # with prompt? def output_certificate_request(private_key_pem, certificate_request, subject = {}) subject_key_value = subject_key_and_value_from_subject(subject) %Q(#{tool} req -new -key #{private_key_pem} -out #{certificate_request} #{subject_key_value}) # openssl req -new -key private_1.pem -out cert_1.csr end def output_certificate(certificate_request, private_key_pem, certificate) %Q(#{tool} x509 -req -in #{certificate_request} -signkey #{private_key_pem} -out #{certificate}) # openssl x509 -req -in cert_1.csr -signkey private_1.pem -out cert_1.cer end def output_p12(certificate, private_key_pem, p12_name, password_file) # replace name's extension by p12 # private_key_pem.pem # certificate.crt or certificate.cer # p12_name.p12 password_file_content = %Q("$(cat #{password_file})") the_password_key_value = key_and_value_or_empty('-passout pass:', password_file_content, '') %Q(#{tool} pkcs12 -export -in #{certificate} -inkey #{private_key_pem} -out #{p12_name} #{the_password_key_value}) end def output_password(file, password = 'password') %Q(echo -n "#{password}" > #{file}) end end class << self include Generating end def generated_by_type(type = self.type) # we need name and parameters? parameters = {} name = nil case self.type when :rsa parameters[:size] = self.rsa_size parameters[:rsa_private_key_passphrase] = self.secret name = "rsa-#{self.rsa_size}" when :ec parameters[:curve_name] = self.curve_name name = "ec-#{self.curve_name}" end self.generated(type, parameters, "#{name}-private", "#{name}-public", "#{name}", "#{name}", "#{name}-private", "#{name}-p12-password") end def generated(type, parameters, private_key_pem, public_key_pem, certificate_request, certificate, p12, p12_password) the_private_key_pem ||= FileFormats.to_pem private_key_pem the_public_key_pem ||= FileFormats.to_pem public_key_pem the_certificate_request ||= FileFormats.to_certificate_request certificate_request the_certificate ||= FileFormats.to_certificate certificate the_p12 ||= FileFormats.to_p12 p12 the_p12_password ||= FileFormats.to_plain_text p12_password [ self.class.generate_key(type, the_private_key_pem, parameters), #self.class.generate_key(curve_name, the_private_key_pem), self.class.export_public_key(type, the_private_key_pem, the_public_key_pem), self.class.output_certificate_request(the_private_key_pem, the_certificate_request, self.class.default_subject), self.class.output_certificate(the_certificate_request, the_private_key_pem, the_certificate), self.class.output_password(the_p12_password), self.class.output_p12(the_certificate, the_private_key_pem, the_p12, the_p12_password) ] end end class MainWork class << self def work(arguments) the_work = new the_work.work(the_work.parse_options(arguments)) end end def fix_options(the_options) options = the_options options[:result_directory] ||= '../Tests/Resources/Certs/' if options[:test] options[:generated_key_name] ||= 'generated' options[:private_key_name] ||= 'private' options[:public_key_name] ||= 'public' end options end def required_keys [:key_type] end def valid_options?(the_options) (required_keys - the_options.keys).empty? end def work(options = {}) options = fix_options(options) if options[:inspection] puts "options are: #{options}" end unless valid_options? options puts "options are not valid!" puts "options are: #{options}" puts "missing options: #{required_keys}" exit(0) end ShellExecutor.setup options[:dry_run] generator = KeysGenerator.new generator.type = options[:key_type] generator.curve_name = options[:curve_name] generator.rsa_size = options[:rsa_size] generator.fix puts "generator fixed arguments: #{generator.to_s}" unless generator.valid? puts "generator types are: #{KeysGenerator::TYPES}. You type is: #{generator.type}" exit(0) end generator.generated_by_type(generator.type).each do |command| ShellExecutor.run_command_line command end #KeyParameters.new(options[:algorithm_type], options[:key_length]) # [ # key_parameters.generate_key(options[:generated_key_name]), # key_parameters.output_private_key(options[:generated_key_name], options[:private_key_name]), # key_parameters.output_public_key(options[:generated_key_name], options[:public_key_name]) # ].map do |command| # key_parameters.suppress_prompt command # end # .each do |command| # ShellExecutor.run_command_line command # end end def help_message(options) # %x[rdoc $0] # not ok puts <<-__HELP__ #{options.help} this script will help you generate keys. First, it takes arguments: [needed] <-f DIRECTORY>: directory where you will gather files [not needed] <-r DIRECTORY>: directory where files will be placed --------------- Usage: --------------- #{$0} -t ../Tests/Resources/Certs/ __HELP__ end def parse_options(arguments) options = {} OptionParser.new do |opts| opts.banner = "Usage: #{$0} [options]" opts.on('-o', '--output_directory DIRECTORY', 'Output Directory') {|v| options[:output_directory] = v} opts.on('-t', '--test', 'Test option') {|v| options[:test] = v} opts.on('-c', '--curve_name CURVE_NAME', 'Curve name') {|v| options[:curve_name] = v} opts.on('-s', '--size SIZE', 'RSA key size') {|v| options[:rsa_size] = v} opts.on('-k', '--key_type KEY_TYPE', 'Key Type (RSA or EC), case insensitive') {|v| options[:key_type] = v} opts.on('-g', '--generated_key_name NAME', 'Generated key name') {|v| options[:generated_key_name] = v} opts.on('-r', '--private_key_name NAME', 'Private Key Name') {|v| options[:private_key_name] = v} opts.on('-u', '--public_key_name NAME', 'Public Key Name') {|v| options[:public_key_name] = v} # opts.on('-l', '--log_level LEVEL', 'Logger level of warning') {|v| options[:log_level] = v} # opts.on('-o', '--output_log OUTPUT', 'Logger output stream') {|v| options[:output_stream] = v} opts.on('-d', '--dry_run', 'Dry run to see all options') {|v| options[:dry_run] = v} opts.on('-i', '--inspection', 'Inspection of all items, like tests'){|v| options[:inspection] = v} # help opts.on('-h', '--help', 'Help option') { self.help_message(opts); exit()} end.parse!(arguments) options end end MainWork.work(ARGV) ================================================ FILE: Scripts/generate_keys.rb ================================================ require 'optparse' require 'shellwords' class ShellExecutor @@dry_run = false class << self def shared_instance unless @@dry_run MyExecutor.setup() @@dry_run end end # setup def setup (dry_run = false) @@dry_run = dry_run end def dry? puts "If statement is #{@@dry_run.to_s}" @@dry_run end def run_command_line(line) puts "I will perform <#{line}>" if dry? puts "I am on dry run!" else # if run result = %x(#{line}) puts "result is:" + result.to_s if $? != 0 puts "I fall down on < #{result} >\n! because of < #{$?} >" exit($?) end result end end end end class KeyParameters TYPES = [:rsa, :ec] SIZES = [256, 384, 512] attr_accessor :type, :size, :secret def initialize(type, size, secret = 'secret') self.type = type self.size = size self.secret = secret end def tool %q(openssl); end def curve_by_size(size) case size when 256 "#{secp256k1}" when 384 "#{secp384k1}" when 512 "#{secp512k1}" end end def suppress_prompt(command) %Q(echo '#{secret}' | #{command}) end def generate_key(name) case type when :rsa %Q(#{tool} genrsa -des3 -out #{name}.pem #{size} -passin 'password') when :ec %Q(#{tool} ecparam -name #{curve_name} -genkey -noout -out #{name}.pem) end end def output_key(type, access, generated_key_name, name) %Q(#{tool} #{type} #{access == 'private' ? '' : '-pubout' } -in #{generated_key_name}.pem -out #{name}.pem < echo "#{secret}") end def output_public_key(generated_key_name, name) output_key(type, 'public', generated_key_name, name) end def output_private_key(generated_key_name, name) output_key(type, 'private', generated_key_name, name) end end class MainWork class << self def work(arguments) the_work = new the_work.work(the_work.parse_options(arguments)) end end def fix_options(the_options) options = the_options options[:result_directory] ||= '../Tests/Resources/Certs/' if options[:test] options[:algorithm_type] ||= KeyParameters::TYPES.first options[:key_length] ||= KeyParameters::SIZES.first options[:generated_key_name] ||= 'generated' options[:private_key_name] ||= 'private' options[:public_key_name] ||= 'public' end options end def work(options = {}) options = fix_options(options) if options[:inspection] puts "options are: #{options}" end ShellExecutor.setup options[:dry_run] key_parameters = KeyParameters.new(options[:algorithm_type], options[:key_length]) [ key_parameters.generate_key(options[:generated_key_name]), key_parameters.output_private_key(options[:generated_key_name], options[:private_key_name]), key_parameters.output_public_key(options[:generated_key_name], options[:public_key_name]) ].map do |command| key_parameters.suppress_prompt command end .each do |command| ShellExecutor.run_command_line command end end def help_message(options) # %x[rdoc $0] # not ok puts <<-__HELP__ #{options.help} this script will help you generate keys. First, it takes arguments: [needed] <-f DIRECTORY>: directory where you will gather files [not needed] <-r DIRECTORY>: directory where files will be placed --------------- Usage: --------------- #{$0} -t ../Tests/Resources/Certs/ __HELP__ end def parse_options(arguments) options = {} OptionParser.new do |opts| opts.banner = "Usage: #{$0} [options]" opts.on('-o', '--output_directory DIRECTORY', 'Output Directory') {|v| options[:output_directory] = v} opts.on('-t', '--test', 'Test option') {|v| options[:test] = v} opts.on('-l', '--length LENGTH', 'Key length') {|v| options[:key_length] = v} opts.on('-a', '--algorithm ALGORITHM', 'Algorithm type') {|v| options[:algorithm_type] = v} opts.on('-g', '--generated_key_name NAME', 'Generated key name') {|v| options[:generated_key_name] = v} opts.on('-r', '--private_key_name NAME', 'Private Key Name') {|v| options[:private_key_name] = v} opts.on('-u', '--public_key_name NAME', 'Public Key Name') {|v| options[:public_key_name] = v} # opts.on('-l', '--log_level LEVEL', 'Logger level of warning') {|v| options[:log_level] = v} # opts.on('-o', '--output_log OUTPUT', 'Logger output stream') {|v| options[:output_stream] = v} opts.on('-d', '--dry_run', 'Dry run to see all options') {|v| options[:dry_run] = v} opts.on('-i', '--inspection', 'Inspection of all items, like tests'){|v| options[:inspection] = v} # help opts.on('-h', '--help', 'Help option') { help_message(opts); exit()} end.parse!(arguments) options end end MainWork.work(ARGV) ================================================ FILE: Scripts/openssl_help.sh ================================================ exit(0) # generate rsa private key. openssl genrsa -out private_1.pem # request certificate with private key in pem format. openssl req -new -key private_1.pem -out cert_1.csr # extract to pem certificate in csr format. openssl pkcs7 -in cert_1.csr -print_certs -out certs.pem # extract to cer certificate from csr with private key in pem. openssl x509 -req -in cert_1.csr -signkey private_1.pem -out cert_1.cer # extract to p12 certificate cert_1.crt with private key in pem. openssl pkcs12 -export -in cert_1.crt -inkey private_1.pem -out cert_1.p12 # extract public key from pem file with cetificate and private key. openssl rsa -in private_256_right.pem -pubout -out public_256_right.pem # extract p12 to pem with all data ( nodes ) openssl pkcs12 -in private_256_right.p12 -out private_256_right.pem -nodes # generate ecdsa private key. openssl ecparam -genkey -name prime256v1 -out ec256-private.pem # generate ecdsa public key. openssl ec -in ec256-private.pem -pubout -out ec256-public.pem ================================================ FILE: Scripts/private_1.pem ================================================ -----BEGIN RSA PRIVATE KEY----- MIIBOwIBAAJBANY7AQ5MmRhLWrnj3Awbtq3FDMEW9IhNxYuHPtCChpNX505L06NM N2GbtrDFvkMWEQpnvblFxme9KPEt3bEMg+8CAwEAAQJBAIUO9tPrzXbibsJgfS7k E62QYyCW4mC6dUT5RpF5UJ64acG5SnoE+ZO39oEjrO9p1yzNG73lod3JTjrCyHvK x+ECIQD5+ENs/luJOfMKBWDY8EQRahwdQxONTuUhTNL5j78v/wIhANtmBp0TMUW+ i3wxK2mXE/FiK1wq8bEHUJ40NO8+5awRAiByfXxcco/4ZVtk7puyITH8C+6+lFdj NIyL2QUUmvtFfwIgUp416Vp72H6regXuCiIZIXHNUDTftMFDa3/PWzR9OnECIQCT rFG5IFGIrmS4cc6ogFPkJyjOylJjkCNRFDlAOyDfJA== -----END RSA PRIVATE KEY----- ================================================ FILE: Scripts/private_256_right.pem ================================================ Bag Attributes friendlyName: Digital Signing Test localKeyID: 6F 37 3B E6 78 85 E0 42 30 AC B7 D1 2F C6 C5 69 20 C4 3C 9E subject=/CN=Digital Signing Test/C=AU/emailAddress=test@test.com issuer=/CN=Digital Signing Test/C=AU/emailAddress=test@test.com -----BEGIN CERTIFICATE----- MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQsFADBKMR0wGwYDVQQDDBREaWdp dGFsIFNpZ25pbmcgVGVzdDELMAkGA1UEBhMCQVUxHDAaBgkqhkiG9w0BCQEWDXRl c3RAdGVzdC5jb20wHhcNMTYwMzEwMjM0ODQ2WhcNMTcwMzEwMjM0ODQ2WjBKMR0w GwYDVQQDDBREaWdpdGFsIFNpZ25pbmcgVGVzdDELMAkGA1UEBhMCQVUxHDAaBgkq hkiG9w0BCQEWDXRlc3RAdGVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQD2G4yWiZX9H4CsbWWpHT/bfRid7yU569j9f2gSB6kYv9wMsd/Crx2p HwIT5uK9gTJ4+5PYaeweB3Tu7uo9ob4EG83k2VF26ruRflzBaSzE4TotxuNoE83B VKFoR1oPdg3BmT7qPCRshz6b36zXfxVQgBYU2F2nUQKbjqCiFEs6w2VrbG5RQwHL EwmLwDu3WPFOwuO2aPP0dRh1E25DeZlzqNFcYaoAf5wEmwWn79oOmzETWh0uTHTg dCrZSp48ZvXf9iFZgqd5HIt0Ub5x5ZYuSZz5FJ8GRRp/0s4q4FG2T0XHsUkvnoMO KGkPUmkpFk4CKZa5BnnKIDGQMr2ndjaNAgMBAAGjRDBCMA4GA1UdDwEB/wQEAwIH gDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDBDAYBgNVHREEETAPgQ10ZXN0QHRlc3Qu Y29tMA0GCSqGSIb3DQEBCwUAA4IBAQDcOYflkAlubGJlv5T1G7PdcHzMzu6doah/ 9RmRyHS8wehc0GljYIyBkhbBG/iRumi6nnnU3BARv+JdSHbpIVsRaXmImWv5I/GO OfUO6UY7jlsw1mCjQyIIZoOFyUKnbcvrb0bCryD3rcbAflYg8feq3AiQv3CacxOy IbYh3khqbs1jKSAzxEdcsuHRB+by5gpwMfF5ByGdMmMl81mFMUuGlcWsfZp2N4Vz 7MWVRl38OWkwZ0yw/Jpd1kcVwKIrXF3rjA71AN41rzyMvvPaEfdgCyFolixEOoJH Fdidq1Bf0liKxf+MFJOaxSWKGqrvzPoBfmwCFoPahuaUlVZ4lGvr -----END CERTIFICATE----- Bag Attributes friendlyName: Digital Signing Test localKeyID: 6F 37 3B E6 78 85 E0 42 30 AC B7 D1 2F C6 C5 69 20 C4 3C 9E Key Attributes: -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA9huMlomV/R+ArG1lqR0/230Yne8lOevY/X9oEgepGL/cDLHf wq8dqR8CE+bivYEyePuT2GnsHgd07u7qPaG+BBvN5NlRduq7kX5cwWksxOE6Lcbj aBPNwVShaEdaD3YNwZk+6jwkbIc+m9+s138VUIAWFNhdp1ECm46gohRLOsNla2xu UUMByxMJi8A7t1jxTsLjtmjz9HUYdRNuQ3mZc6jRXGGqAH+cBJsFp+/aDpsxE1od Lkx04HQq2UqePGb13/YhWYKneRyLdFG+ceWWLkmc+RSfBkUaf9LOKuBRtk9Fx7FJ L56DDihpD1JpKRZOAimWuQZ5yiAxkDK9p3Y2jQIDAQABAoIBAQDEu88Nw5xvxNAS hjz/DE+wwHZ+Qd6LR7qlIkTqLM+C5lQcndBWi6/1MsFxcV8NyAq15b4RANNsSd+y 5K/BZttD44oah5J0sj4Ql2fEgLP2Cml8kIHXAAW5p1KDzo3y0Bc9DKjbjAo963sk FZDQj1lViZ6dOTzcdIjWGxTTm89rf5frVPUJxNFB+VRHWuyRGudXzGw6g0EX0vMx 92PFy3NFFSczgRZS0rx+PEN/kYBThdZoWcBnhfq2YLLW5ID0urs6vs2QqGZK/AQE B3DezX6arlHvyjOtb9oYl9QV5YG1faqgE9YWQvmkxKHvitcTTYA6fgn7KhCqZmno F2WrtkDNAoGBAP5tDiFPGonvZJB4KEmWITqWiYFdlZ9yJ5r1mIRywuJQJ6NCwADd v3qvGnjpI4NUFNHvuPr+PYXGi8wlvKGXO7EkO7DyB5hs7LiKyppUBH/Vb4KopAFo ceG/2B21g0AeF6RuRshWIQwqAzTmz+T4+Kj8WE6e146a3L7TNOM5yOrjAoGBAPeh Ud9hciqlr/8OhnUUIRUC67F3CBjBl7xnDy+00MPe0A1SsKODBQOTQRq/mr75AM8F IwI7wTo0joj4x8LP43YUeOUHUapQoX1AUzAlaZhd5m2wAUOkip15P0mw/GpN9brl s3BRZ7DHNzyIay9htM+8YGzUEPwUdyQmln6js+PPAoGAdx7gKsA6kLJAx1M6qZlc 3W1129fRIeH0oRyz1+9TR1p39HxgIQexiuNI5atiMS7AwLoYRYubinK3KVHRy2Zf UETCncnzvG3jN1PkH/WOVbu8hdQnVXFtQGDt8pr1ZKOyNg5bnZiVyHgzICWg2Hep FJVxUv4TtnTTPZTtgiWf6DkCgYEAsAghp2YiPmbiIbI1quzQR5t36QPw4YhdUTUB +qvS7CpsQ8xQfSwaWFxJn7YtTyy7gm7oYCISTkomOQCBIN+flsUe29DEIQqIgf1E Jamy0vmNYNQJUgiZ8S/L6ZrDFN6unFnFoUZ9K5GylnlzmI8gdbw336UxHcF+oFg+ C3Bb5MkCgYBuPywM9nuF8EbeuHCl/3LRkVaNwRwFjgb7NV47E30+3YoM6qvcDG1q iAi5KixQfk1oW1GGdvMOzOIK+AseKZNxuYwAjynNr6iGyMnPAvaVfv8ZcbmAe1Dx eX8OG0k/j128DnQZd6Be3yl9qH8eOqCv7eZpe0xO0uZjeyA7TFAEhg== -----END RSA PRIVATE KEY----- ================================================ FILE: Scripts/private_256_wrong.pem ================================================ Bag Attributes friendlyName: Digital Signing Test 2 localKeyID: 74 36 2D 52 4A CD E9 18 4E 16 B4 14 20 CF DF DB FE 3C 13 58 subject=/CN=Digital Signing Test 2/C=AU/emailAddress=test@test.com issuer=/CN=Digital Signing Test 2/C=AU/emailAddress=test@test.com -----BEGIN CERTIFICATE----- MIIDVzCCAj+gAwIBAgIBATANBgkqhkiG9w0BAQsFADBMMR8wHQYDVQQDDBZEaWdp dGFsIFNpZ25pbmcgVGVzdCAyMQswCQYDVQQGEwJBVTEcMBoGCSqGSIb3DQEJARYN dGVzdEB0ZXN0LmNvbTAeFw0xNjAzMTIwMDUzMDJaFw0xNzAzMTIwMDUzMDJaMEwx HzAdBgNVBAMMFkRpZ2l0YWwgU2lnbmluZyBUZXN0IDIxCzAJBgNVBAYTAkFVMRww GgYJKoZIhvcNAQkBFg10ZXN0QHRlc3QuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAtQ57lsgAE5eWahnJ4e9InudO6rtJ12qE/qaeBrU8qcmJ0ku7 8Ih2gnShRtdmJGaDgGH1hM6J+ucQvl87foNqJPeAN+s5GeiGw4yoaHTnibJ9/v8r zz+PzMwXn6EGykaL6eDAIIOKNcMXvjWZEXtwr/roOFbaEIe6JeqNeSb2mXS+1XI5 NGCL4jp8y0WmNCp/0LUMGQyj2ilmIgaV74cB2xdxPozZZJnWDASkgbGzi4ijZCpO P/yksEvJ7JSNBmmAQoFNslMymOO3XYJs3yvR9thwRl/uHbY4gHRPGHramCdJ6s+L w+gzCjslB87HsIy4pp6PeDiOe/tyc79LWcsLbQIDAQABo0QwQjAOBgNVHQ8BAf8E BAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwQwGAYDVR0RBBEwD4ENdGVzdEB0 ZXN0LmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAmlDHOKSdE8sRbUHNWZtyghm7FUBc rEEB/mM/dtRbq7aUFEPtHpXdKGf/fC0TZxdLoKfIFvgEuPlvzwgFhHTW3qzY4dES 0n2krALVkfT0IR72vR98AGEE2gchSqGtwr1KkvYE8A4IwU+mlrDzVZoE0OjRg73K lpaxc77ln34CB+yAIlL1uunIZj+zmCuhsK4i6QAjzJ1PaNXo5P9F4zfJDW4B0ej6 /2V9nxBvWW8hdba/eVbDltkvw0dZZay6YgBmVz9mXbAGZ6pk2XOjTlS3XLFgLUVe 8WTXbktQw0cCcf3xfn6HB/Y+5l/0srZ3i5Su5qtdDDbZ3epBjB3K5kiP8g== -----END CERTIFICATE----- Bag Attributes friendlyName: Digital Signing Test 2 localKeyID: 74 36 2D 52 4A CD E9 18 4E 16 B4 14 20 CF DF DB FE 3C 13 58 Key Attributes: -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAtQ57lsgAE5eWahnJ4e9InudO6rtJ12qE/qaeBrU8qcmJ0ku7 8Ih2gnShRtdmJGaDgGH1hM6J+ucQvl87foNqJPeAN+s5GeiGw4yoaHTnibJ9/v8r zz+PzMwXn6EGykaL6eDAIIOKNcMXvjWZEXtwr/roOFbaEIe6JeqNeSb2mXS+1XI5 NGCL4jp8y0WmNCp/0LUMGQyj2ilmIgaV74cB2xdxPozZZJnWDASkgbGzi4ijZCpO P/yksEvJ7JSNBmmAQoFNslMymOO3XYJs3yvR9thwRl/uHbY4gHRPGHramCdJ6s+L w+gzCjslB87HsIy4pp6PeDiOe/tyc79LWcsLbQIDAQABAoIBAGbv0PwswT5iVLYF 6210qYkOYSO7T4QVn39YI0gVCmRNnPne7P8X1qjcvkSUehH/5ou7JedXtcLcU/yo EB8hf9t8i30/UruUI+pRsf2RWYJD5LZxROsTbCI3dsbeugmOikVx7kmN/6oJPRp7 RodV8v9aW2SMnHYBdKfR7pUOve0IKcAphravK6Hf/V7Yt7IGS3l2JN0lSSTLcO7O uj/xTRSCfLCkKS4mriB0yCSiIXG8hnE1eqoSLvmpG0co23hT8eJZ9eM8NyeYwOwM LRD8QVyUKqwK4HlvUUSKT/HtZUa8Fa3JqVmTpCccQAfVXWmk9IaUqgH/nheqUKPv +9vPXoECgYEA4xFRYyeDA+y3XgSoSNYIl8gQ7PXGPNyzJ+iKCui13911ykLp8850 9exLcWigHuW4wdqDcKHVZ0Ak91v/jfukh71h4GqHbyoPqWHnsCBjdq0suwBtKN9O tnVVpA5pzJxLy68qxs5fJ3/rDiQydajBdRV0/Bl974e/koIL9DBe/9kCgYEAzCBW Uy1IJcG1zaC6ueHz3OCkkqbfy1CJokXpM6sxc70pDPMAPheIalbxgdprmWcxeGev FXcmU2zaaiEVmLdkMIOAmoIukwKMNi8ugNpPoxgN4YTKUAdNoNo0J/ku4PBjSBRZ HaaLLUUb5+u8Yk6SoozI1UFBq2iXnATvHc6f/7UCgYA7pS3qzNM2cbTNBo4p68cA D7aaeAjlrdeFsSipqu0za9noEmGgAGhqvPIoTSJaW1+H1F1Ydbo3z/ql202qvyI9 4bpXF8SRp8vLY4NXmXpnDyBD0t3ZsabceL/RQ1P5QkkKrO2goU8PciONaGa0z2pZ 1hQPsKaLB+6DjpOTRi1+KQKBgEDps6oFx2DCZjc6+sZr9WnzQkKksJxuQyaIhu14 bmR47hoBGL2mLCps9aYuuHLzHwdEKahw2I5FGnwPg1eqUkEfQIFiDr+PWtlMTcSK KDMcTiW+XbvvZp9VZKqlkmPT7i6Y0fIc6Tt/M62gCKtWg0kP7jnq46BHxZbG9ueK stTVAoGBAM0dXbhi5OOxu3Eidx8ZLM3Bxx7aGCxc6N3e2vggdoENUqr56aPpUtC4 YDN7OmXMXxZoSDZtSCzHgmkB5TOeE/OJla5ixEe4gcis66NDZm/WB0rtMsXKxH+P k64i5zMRwn4sI2ImdUer5LNej85DBN/AwlLq8nxPoH1rRhXE4iQW -----END RSA PRIVATE KEY----- ================================================ FILE: Scripts/public_256_right.pem ================================================ -----BEGIN CERTIFICATE----- MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQsFADBKMR0wGwYDVQQDDBREaWdp dGFsIFNpZ25pbmcgVGVzdDELMAkGA1UEBhMCQVUxHDAaBgkqhkiG9w0BCQEWDXRl c3RAdGVzdC5jb20wHhcNMTYwMzEwMjM0ODQ2WhcNMTcwMzEwMjM0ODQ2WjBKMR0w GwYDVQQDDBREaWdpdGFsIFNpZ25pbmcgVGVzdDELMAkGA1UEBhMCQVUxHDAaBgkq hkiG9w0BCQEWDXRlc3RAdGVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQD2G4yWiZX9H4CsbWWpHT/bfRid7yU569j9f2gSB6kYv9wMsd/Crx2p HwIT5uK9gTJ4+5PYaeweB3Tu7uo9ob4EG83k2VF26ruRflzBaSzE4TotxuNoE83B VKFoR1oPdg3BmT7qPCRshz6b36zXfxVQgBYU2F2nUQKbjqCiFEs6w2VrbG5RQwHL EwmLwDu3WPFOwuO2aPP0dRh1E25DeZlzqNFcYaoAf5wEmwWn79oOmzETWh0uTHTg dCrZSp48ZvXf9iFZgqd5HIt0Ub5x5ZYuSZz5FJ8GRRp/0s4q4FG2T0XHsUkvnoMO KGkPUmkpFk4CKZa5BnnKIDGQMr2ndjaNAgMBAAGjRDBCMA4GA1UdDwEB/wQEAwIH gDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDBDAYBgNVHREEETAPgQ10ZXN0QHRlc3Qu Y29tMA0GCSqGSIb3DQEBCwUAA4IBAQDcOYflkAlubGJlv5T1G7PdcHzMzu6doah/ 9RmRyHS8wehc0GljYIyBkhbBG/iRumi6nnnU3BARv+JdSHbpIVsRaXmImWv5I/GO OfUO6UY7jlsw1mCjQyIIZoOFyUKnbcvrb0bCryD3rcbAflYg8feq3AiQv3CacxOy IbYh3khqbs1jKSAzxEdcsuHRB+by5gpwMfF5ByGdMmMl81mFMUuGlcWsfZp2N4Vz 7MWVRl38OWkwZ0yw/Jpd1kcVwKIrXF3rjA71AN41rzyMvvPaEfdgCyFolixEOoJH Fdidq1Bf0liKxf+MFJOaxSWKGqrvzPoBfmwCFoPahuaUlVZ4lGvr -----END CERTIFICATE----- -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9huMlomV/R+ArG1lqR0/ 230Yne8lOevY/X9oEgepGL/cDLHfwq8dqR8CE+bivYEyePuT2GnsHgd07u7qPaG+ BBvN5NlRduq7kX5cwWksxOE6LcbjaBPNwVShaEdaD3YNwZk+6jwkbIc+m9+s138V UIAWFNhdp1ECm46gohRLOsNla2xuUUMByxMJi8A7t1jxTsLjtmjz9HUYdRNuQ3mZ c6jRXGGqAH+cBJsFp+/aDpsxE1odLkx04HQq2UqePGb13/YhWYKneRyLdFG+ceWW Lkmc+RSfBkUaf9LOKuBRtk9Fx7FJL56DDihpD1JpKRZOAimWuQZ5yiAxkDK9p3Y2 jQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: Scripts/public_256_wrong.pem ================================================ -----BEGIN CERTIFICATE----- MIIDVzCCAj+gAwIBAgIBATANBgkqhkiG9w0BAQsFADBMMR8wHQYDVQQDDBZEaWdp dGFsIFNpZ25pbmcgVGVzdCAyMQswCQYDVQQGEwJBVTEcMBoGCSqGSIb3DQEJARYN dGVzdEB0ZXN0LmNvbTAeFw0xNjAzMTIwMDUzMDJaFw0xNzAzMTIwMDUzMDJaMEwx HzAdBgNVBAMMFkRpZ2l0YWwgU2lnbmluZyBUZXN0IDIxCzAJBgNVBAYTAkFVMRww GgYJKoZIhvcNAQkBFg10ZXN0QHRlc3QuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAtQ57lsgAE5eWahnJ4e9InudO6rtJ12qE/qaeBrU8qcmJ0ku7 8Ih2gnShRtdmJGaDgGH1hM6J+ucQvl87foNqJPeAN+s5GeiGw4yoaHTnibJ9/v8r zz+PzMwXn6EGykaL6eDAIIOKNcMXvjWZEXtwr/roOFbaEIe6JeqNeSb2mXS+1XI5 NGCL4jp8y0WmNCp/0LUMGQyj2ilmIgaV74cB2xdxPozZZJnWDASkgbGzi4ijZCpO P/yksEvJ7JSNBmmAQoFNslMymOO3XYJs3yvR9thwRl/uHbY4gHRPGHramCdJ6s+L w+gzCjslB87HsIy4pp6PeDiOe/tyc79LWcsLbQIDAQABo0QwQjAOBgNVHQ8BAf8E BAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwQwGAYDVR0RBBEwD4ENdGVzdEB0 ZXN0LmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAmlDHOKSdE8sRbUHNWZtyghm7FUBc rEEB/mM/dtRbq7aUFEPtHpXdKGf/fC0TZxdLoKfIFvgEuPlvzwgFhHTW3qzY4dES 0n2krALVkfT0IR72vR98AGEE2gchSqGtwr1KkvYE8A4IwU+mlrDzVZoE0OjRg73K lpaxc77ln34CB+yAIlL1uunIZj+zmCuhsK4i6QAjzJ1PaNXo5P9F4zfJDW4B0ej6 /2V9nxBvWW8hdba/eVbDltkvw0dZZay6YgBmVz9mXbAGZ6pk2XOjTlS3XLFgLUVe 8WTXbktQw0cCcf3xfn6HB/Y+5l/0srZ3i5Su5qtdDDbZ3epBjB3K5kiP8g== -----END CERTIFICATE----- -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtQ57lsgAE5eWahnJ4e9I nudO6rtJ12qE/qaeBrU8qcmJ0ku78Ih2gnShRtdmJGaDgGH1hM6J+ucQvl87foNq JPeAN+s5GeiGw4yoaHTnibJ9/v8rzz+PzMwXn6EGykaL6eDAIIOKNcMXvjWZEXtw r/roOFbaEIe6JeqNeSb2mXS+1XI5NGCL4jp8y0WmNCp/0LUMGQyj2ilmIgaV74cB 2xdxPozZZJnWDASkgbGzi4ijZCpOP/yksEvJ7JSNBmmAQoFNslMymOO3XYJs3yvR 9thwRl/uHbY4gHRPGHramCdJ6s+Lw+gzCjslB87HsIy4pp6PeDiOe/tyc79LWcsL bQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: Scripts/test_cert_public_256_right.pem ================================================ -----BEGIN CERTIFICATE----- MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQsFADBKMR0wGwYDVQQDDBREaWdp dGFsIFNpZ25pbmcgVGVzdDELMAkGA1UEBhMCQVUxHDAaBgkqhkiG9w0BCQEWDXRl c3RAdGVzdC5jb20wHhcNMTYwMzEwMjM0ODQ2WhcNMTcwMzEwMjM0ODQ2WjBKMR0w GwYDVQQDDBREaWdpdGFsIFNpZ25pbmcgVGVzdDELMAkGA1UEBhMCQVUxHDAaBgkq hkiG9w0BCQEWDXRlc3RAdGVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQD2G4yWiZX9H4CsbWWpHT/bfRid7yU569j9f2gSB6kYv9wMsd/Crx2p HwIT5uK9gTJ4+5PYaeweB3Tu7uo9ob4EG83k2VF26ruRflzBaSzE4TotxuNoE83B VKFoR1oPdg3BmT7qPCRshz6b36zXfxVQgBYU2F2nUQKbjqCiFEs6w2VrbG5RQwHL EwmLwDu3WPFOwuO2aPP0dRh1E25DeZlzqNFcYaoAf5wEmwWn79oOmzETWh0uTHTg dCrZSp48ZvXf9iFZgqd5HIt0Ub5x5ZYuSZz5FJ8GRRp/0s4q4FG2T0XHsUkvnoMO KGkPUmkpFk4CKZa5BnnKIDGQMr2ndjaNAgMBAAGjRDBCMA4GA1UdDwEB/wQEAwIH gDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDBDAYBgNVHREEETAPgQ10ZXN0QHRlc3Qu Y29tMA0GCSqGSIb3DQEBCwUAA4IBAQDcOYflkAlubGJlv5T1G7PdcHzMzu6doah/ 9RmRyHS8wehc0GljYIyBkhbBG/iRumi6nnnU3BARv+JdSHbpIVsRaXmImWv5I/GO OfUO6UY7jlsw1mCjQyIIZoOFyUKnbcvrb0bCryD3rcbAflYg8feq3AiQv3CacxOy IbYh3khqbs1jKSAzxEdcsuHRB+by5gpwMfF5ByGdMmMl81mFMUuGlcWsfZp2N4Vz 7MWVRl38OWkwZ0yw/Jpd1kcVwKIrXF3rjA71AN41rzyMvvPaEfdgCyFolixEOoJH Fdidq1Bf0liKxf+MFJOaxSWKGqrvzPoBfmwCFoPahuaUlVZ4lGvr -----END CERTIFICATE----- -----BEGIN RSA PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9huMlomV/R+ArG1lqR0/ 230Yne8lOevY/X9oEgepGL/cDLHfwq8dqR8CE+bivYEyePuT2GnsHgd07u7qPaG+ BBvN5NlRduq7kX5cwWksxOE6LcbjaBPNwVShaEdaD3YNwZk+6jwkbIc+m9+s138V UIAWFNhdp1ECm46gohRLOsNla2xuUUMByxMJi8A7t1jxTsLjtmjz9HUYdRNuQ3mZ c6jRXGGqAH+cBJsFp+/aDpsxE1odLkx04HQq2UqePGb13/YhWYKneRyLdFG+ceWW Lkmc+RSfBkUaf9LOKuBRtk9Fx7FJL56DDihpD1JpKRZOAimWuQZ5yiAxkDK9p3Y2 jQIDAQAB -----END RSA PUBLIC KEY----- ================================================ FILE: Scripts/test_cert_public_256_wrong.pem ================================================ -----BEGIN CERTIFICATE----- MIIDVzCCAj+gAwIBAgIBATANBgkqhkiG9w0BAQsFADBMMR8wHQYDVQQDDBZEaWdp dGFsIFNpZ25pbmcgVGVzdCAyMQswCQYDVQQGEwJBVTEcMBoGCSqGSIb3DQEJARYN dGVzdEB0ZXN0LmNvbTAeFw0xNjAzMTIwMDUzMDJaFw0xNzAzMTIwMDUzMDJaMEwx HzAdBgNVBAMMFkRpZ2l0YWwgU2lnbmluZyBUZXN0IDIxCzAJBgNVBAYTAkFVMRww GgYJKoZIhvcNAQkBFg10ZXN0QHRlc3QuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAtQ57lsgAE5eWahnJ4e9InudO6rtJ12qE/qaeBrU8qcmJ0ku7 8Ih2gnShRtdmJGaDgGH1hM6J+ucQvl87foNqJPeAN+s5GeiGw4yoaHTnibJ9/v8r zz+PzMwXn6EGykaL6eDAIIOKNcMXvjWZEXtwr/roOFbaEIe6JeqNeSb2mXS+1XI5 NGCL4jp8y0WmNCp/0LUMGQyj2ilmIgaV74cB2xdxPozZZJnWDASkgbGzi4ijZCpO P/yksEvJ7JSNBmmAQoFNslMymOO3XYJs3yvR9thwRl/uHbY4gHRPGHramCdJ6s+L w+gzCjslB87HsIy4pp6PeDiOe/tyc79LWcsLbQIDAQABo0QwQjAOBgNVHQ8BAf8E BAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwQwGAYDVR0RBBEwD4ENdGVzdEB0 ZXN0LmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAmlDHOKSdE8sRbUHNWZtyghm7FUBc rEEB/mM/dtRbq7aUFEPtHpXdKGf/fC0TZxdLoKfIFvgEuPlvzwgFhHTW3qzY4dES 0n2krALVkfT0IR72vR98AGEE2gchSqGtwr1KkvYE8A4IwU+mlrDzVZoE0OjRg73K lpaxc77ln34CB+yAIlL1uunIZj+zmCuhsK4i6QAjzJ1PaNXo5P9F4zfJDW4B0ej6 /2V9nxBvWW8hdba/eVbDltkvw0dZZay6YgBmVz9mXbAGZ6pk2XOjTlS3XLFgLUVe 8WTXbktQw0cCcf3xfn6HB/Y+5l/0srZ3i5Su5qtdDDbZ3epBjB3K5kiP8g== -----END CERTIFICATE----- -----BEGIN RSA PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtQ57lsgAE5eWahnJ4e9I nudO6rtJ12qE/qaeBrU8qcmJ0ku78Ih2gnShRtdmJGaDgGH1hM6J+ucQvl87foNq JPeAN+s5GeiGw4yoaHTnibJ9/v8rzz+PzMwXn6EGykaL6eDAIIOKNcMXvjWZEXtw r/roOFbaEIe6JeqNeSb2mXS+1XI5NGCL4jp8y0WmNCp/0LUMGQyj2ilmIgaV74cB 2xdxPozZZJnWDASkgbGzi4ijZCpOP/yksEvJ7JSNBmmAQoFNslMymOO3XYJs3yvR 9thwRl/uHbY4gHRPGHramCdJ6s+Lw+gzCjslB87HsIy4pp6PeDiOe/tyc79LWcsL bQIDAQAB -----END RSA PUBLIC KEY----- ================================================ FILE: Sources/JWT/Algorithms/Base/JWTAlgorithmErrorDescription+Subclass.m ================================================ // // JWTAlgorithmErrorDescription+Subclass.m // JWT // // Created by Dmitry on 7/29/18. // Copyright © 2018 JWTIO. All rights reserved. // #import "JWTAlgorithmErrorDescription+Subclass.h" @implementation JWTAlgorithmErrorDescription (Subclass) + (NSString *)errorDomain { return nil; } + (NSInteger)defaultErrorCode { return 0; } + (NSInteger)externalCodeForInternalError { return 0; } + (NSDictionary *)codesAndUserDescriptions { return nil; } + (NSDictionary *)codesAndDescriptions { return nil; } @end ================================================ FILE: Sources/JWT/Algorithms/Base/JWTAlgorithmErrorDescription.m ================================================ // // JWTAlgorithmErrorDescription.m // JWT // // Created by Dmitry on 7/29/18. // Copyright © 2018 JWTIO. All rights reserved. // #import "JWTAlgorithmErrorDescription.h" #import "JWTAlgorithmErrorDescription+Subclass.h" @interface JWTAlgorithmErrorDescription (Keys) + (NSString *)currentErrorDescriptionKey; + (NSString *)externalErrorDescriptionKey; @end @implementation JWTAlgorithmErrorDescription (Keys) + (NSString *)currentErrorDescriptionKey { return @"errorDescription"; } + (NSString *)externalErrorDescriptionKey { return @"externalErrorDescription"; } @end @interface JWTAlgorithmErrorDescription () + (NSError *)errorWithCode:(NSInteger)code userDescription:(NSString *)userDescription errorDescription:(NSString *)errorDescription; + (NSError *)errorWithCode:(NSInteger)code userDescription:(NSString *)userDescription errorDescription:(NSString *)errorDescription externalErrorDescription:(NSString *)externalErrorDescription; @end @implementation JWTAlgorithmErrorDescription + (NSString *)userDescriptionForCode:(NSInteger)code { NSString *resultString = [self codesAndUserDescriptions][@(code)]; return resultString ?: [self codesAndUserDescriptions][@([self defaultErrorCode])]; } + (NSString *)errorDescriptionForCode:(NSInteger)code { NSString *resultString = [self codesAndDescriptions][@(code)]; return resultString ?: [self codesAndDescriptions][@([self defaultErrorCode])]; } + (NSError *)errorWithCode:(NSInteger)code userDescription:(NSString *)userDescription errorDescription:(NSString *)errorDescription { return [NSError errorWithDomain:[self errorDomain] code:code userInfo:@{NSLocalizedDescriptionKey: userDescription, [self currentErrorDescriptionKey] : errorDescription}]; } + (NSError *)errorWithCode:(NSInteger)code userDescription:(NSString *)userDescription errorDescription:(NSString *)errorDescription externalErrorDescription:(NSString *)externalErrorDescription { return [NSError errorWithDomain:[self errorDomain] code:code userInfo:@{NSLocalizedDescriptionKey: userDescription, [self currentErrorDescriptionKey] : errorDescription, [self externalErrorDescriptionKey] : externalErrorDescription}]; } + (NSError *)errorWithCode:(NSInteger)code { return [self errorWithCode:code userDescription:[self userDescriptionForCode:code] errorDescription:[self errorDescriptionForCode:code]]; } + (NSError *)errorWithExternalError:(NSError *)error { NSString *externalErrorDescription = [@{@"externalError": error} description]; __auto_type code = [self externalCodeForInternalError]; return [self errorWithCode:code userDescription:[self userDescriptionForCode:code] errorDescription:[self errorDescriptionForCode:code] externalErrorDescription:externalErrorDescription]; } @end ================================================ FILE: Sources/JWT/Algorithms/Base/JWTAlgorithmFactory.m ================================================ // // JWTAlgorithmFactory.m // JWT // // Created by Lobanov Dmitry on 07.10.15. // Copyright © 2015 Karma. All rights reserved. // #import "JWTAlgorithmFactory.h" #import "JWTAlgorithmHSBase.h" #import "JWTAlgorithmRSBase.h" #import "JWTAlgorithmNone.h" #import "JWTAlgorithmAsymmetricBase.h" #import "JWTBase64Coder.h" // not implemented. // ES still not implemented. Look at implementation and readme in future releases. @implementation JWTAlgorithmHolder - (instancetype)initWithAlgorithm:(id)algorithm { if (self = [super init]) { self.algorithm = algorithm; } return self; } - (NSString *)name { return self.algorithm.name; } - (NSData *)signHash:(NSData *)hash key:(NSData *)key error:(NSError *__autoreleasing *)error { return [self.algorithm signHash:hash key:key error:error]; } - (BOOL)verifyHash:(NSData *)hash signature:(NSData *)signature key:(NSData *)key error:(NSError *__autoreleasing *)error { return [self.algorithm verifyHash:hash signature:signature key:key error:error]; } - (NSData *)encodePayload:(NSString *)theString withSecret:(NSString *)theSecret { NSData *inputData = [theString dataUsingEncoding:NSUTF8StringEncoding]; NSData *secretData = [theSecret dataUsingEncoding:NSUTF8StringEncoding]; //[JWTBase64Coder dataWithBase64UrlEncodedString:theSecret]; return [self encodePayloadData:inputData withSecret:secretData]; } - (NSData *)encodePayloadData:(NSData *)theStringData withSecret:(NSData *)theSecretData { return [self signHash:theStringData key:theSecretData error:nil]; } - (BOOL)verifySignedInput:(NSString *)input withSignature:(NSString *)signature verificationKey:(NSString *)verificationKey { NSData *inputData = [input dataUsingEncoding:NSUTF8StringEncoding]; //[JWTBase64Coder dataWithBase64UrlEncodedString:input]; NSData *signatureData = [JWTBase64Coder dataWithBase64UrlEncodedString:signature]; NSData *verificationKeyData = [verificationKey dataUsingEncoding:NSUTF8StringEncoding]; return [self verifyHash:inputData signature:signatureData key:verificationKeyData error:nil]; // return [self verifySignedInput:input withSignature:signature verificationKeyData:verificationKeyData]; } - (BOOL)verifySignedInput:(NSString *)input withSignature:(NSString *)signature verificationKeyData:(NSData *)verificationKeyData { NSData *signatureData = [JWTBase64Coder dataWithBase64UrlEncodedString:signature]; NSData *inputData = [input dataUsingEncoding:NSUTF8StringEncoding]; //[JWTBase64Coder dataWithBase64UrlEncodedString:input]; return [self verifyHash:inputData signature:signatureData key:verificationKeyData error:nil ]; } @end @implementation JWTAlgorithmFactory + (BOOL)checkIfSecurityAPIAvailable { BOOL result = NO; #if TARGET_OS_MAC && TARGET_OS_IPHONE // iOS >= 10 result = [[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){10, 0, 0}]; #elif TARGET_OS_MAC && !TARGET_OS_IPHONE // macOS >= 10.12 result = [[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){10, 12, 0}]; #endif return result; } + (NSArray> *)algorithms { if ([self checkIfSecurityAPIAvailable]) { return @[ [JWTAlgorithmNone new], [JWTAlgorithmHSBase algorithm256], [JWTAlgorithmHSBase algorithm384], [JWTAlgorithmHSBase algorithm512], [JWTAlgorithmAsymmetricBase withRS].with256, [JWTAlgorithmAsymmetricBase withRS].with384, [JWTAlgorithmAsymmetricBase withRS].with512, [JWTAlgorithmAsymmetricBase withES].with256, [JWTAlgorithmAsymmetricBase withES].with384, [JWTAlgorithmAsymmetricBase withES].with512 ]; } return @[ [JWTAlgorithmNone new], [JWTAlgorithmHSBase algorithm256], [JWTAlgorithmHSBase algorithm384], [JWTAlgorithmHSBase algorithm512], [JWTAlgorithmRSBase algorithm256], [JWTAlgorithmRSBase algorithm384], [JWTAlgorithmRSBase algorithm512] ]; } + (id)algorithmByName:(NSString *)name { id algorithm = nil; NSString *algName = [name copy]; NSUInteger index = [[self algorithms] indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { // lowercase comparison return [obj.name isEqualToString:algName]; }]; if (index != NSNotFound) { algorithm = [self algorithms][index]; } return algorithm; } @end ================================================ FILE: Sources/JWT/Algorithms/Base/JWTAlgorithmNone.m ================================================ // // JWTAlgorithmNone.m // JWT // // Created by Lobanov Dmitry on 16.10.15. // Copyright © 2015 Karma. All rights reserved. // #import "JWTAlgorithmNone.h" NSString *const JWTAlgorithmNameNone = @"none"; @implementation JWTAlgorithmNone - (NSString *)name { return JWTAlgorithmNameNone; } - (NSData *)signHash:(NSData *)hash key:(NSData *)key error:(NSError *__autoreleasing *)error { return [NSData data]; } - (BOOL)verifyHash:(NSData *)hash signature:(NSData *)signature key:(NSData *)key error:(NSError *__autoreleasing *)error { //if a secret is provided, this isn't the None algorithm if (key && key.length > 0) { return NO; } //If the signature isn't blank, this isn't the None algorithm if (signature && signature.length > 0) { return NO; } return YES; } @end ================================================ FILE: Sources/JWT/Algorithms/ESFamily/JWTAlgorithmAsymmetricBase.m ================================================ // // JWTAlgorithmAsymmetricBase.m // Base64 // // Created by Lobanov Dmitry on 12.03.2018. // #import "JWTAlgorithmAsymmetricBase.h" #import "JWTBase64Coder.h" #import "JWTCryptoSecurity.h" #import "JWTCryptoKeyExtractor.h" #import "JWTCryptoKey.h" #import "JWTAlgorithmFactory.h" #import #ifndef IPHONE_SDK_VERSION_GREATER_THAN_10 #define IPHONE_SDK_VERSION_GREATER_THAN_10 (__IPHONE_OS_VERSION_MAX_ALLOWED && __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000) #endif #ifndef MAC_OS_SDK_VERSION_GREATER_THAN_10_12 #define MAC_OS_SDK_VERSION_GREATER_THAN_10_12 (__MAC_OS_X_VERSION_MAX_ALLOWED && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101200) #endif // Abilities #ifndef JWT_CRYPTO_MODERN_API_IS_ALLOWED #define JWT_CRYPTO_MODERN_API_IS_ALLOWED ((IPHONE_SDK_VERSION_GREATER_THAN_10) || (MAC_OS_SDK_VERSION_GREATER_THAN_10_12)) #endif // #ifndef IPHONE_OS_VERSION_GREATER_THAN_10 // #define IPHONE_OS_VERSION_GREATER_THAN_10 (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) // #endif // #ifndef MAC_OS_VERSION_GREATER_THAN_10 // #define MAC_OS_VERSION_GREATER_THAN_10 (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200) // #endif // // Requirements // #ifndef JWT_CRYPTO_MODERN_API_IS_REQUIRED // #define JWT_CRYPTO_MODERN_API_IS_REQUIRED ((IPHONE_OS_VERSION_GREATER_THAN_10) || (MAC_OS_VERSION_GREATER_THAN_10)) // #endif // TODO: // Rewrite errors presentation. NSString *const JWTAlgorithmAsymmetricFamilyErrorDomain = @"io.jwt.jwa.asymmetric"; @implementation JWTAlgorithmAsymmetricFamilyErrorDescription // Subclass + (NSString *)errorDomain { return JWTAlgorithmAsymmetricFamilyErrorDomain; } + (NSInteger)defaultErrorCode { return JWTAlgorithmAsymmetricFamilyErrorUnexpected; } + (NSInteger)externalErrorCode { return JWTAlgorithmAsymmetricFamilyErrorInternalSecurityAPI; } + (NSDictionary *)codesAndUserDescriptions { static NSDictionary *dictionary = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ dictionary = @{ @(JWTAlgorithmAsymmetricFamilyErrorAlgorithmIsNotSupported) : @"Algorithm is not supported!", @(JWTAlgorithmAsymmetricFamilyErrorInternalSecurityAPI) : @"algorithm internal security framework error!", @(JWTAlgorithmAsymmetricFamilyErrorUnexpected) : @"Asymmetric algorithm unexpected error!" }; }); return dictionary; } + (NSDictionary *)codesAndDescriptions { static NSDictionary *dictionary = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ dictionary = @{ @(JWTAlgorithmAsymmetricFamilyErrorAlgorithmIsNotSupported) : @"JWTAlgorithmAsymmetricFamilyErrorAlgorithmIsNotSupported", @(JWTAlgorithmAsymmetricFamilyErrorInternalSecurityAPI) : @"JWTAlgorithmAsymmetricFamilyErrorInternalSecurityAPI", @(JWTAlgorithmAsymmetricFamilyErrorUnexpected) : @"JWTAlgorithmAsymmetricFamilyErrorUnexpected" }; }); return dictionary; } @end typedef NS_ENUM(NSInteger, JWTAlgorithmAsymmetricBase__AlgorithmType) { JWTAlgorithmAsymmetricBase__AlgorithmType__RS, JWTAlgorithmAsymmetricBase__AlgorithmType__ES, JWTAlgorithmAsymmetricBase__AlgorithmType__PS }; typedef NS_ENUM(NSInteger, JWTAlgorithmAsymmetricBase__AlgorithmNumber) { JWTAlgorithmAsymmetricBase__AlgorithmNumber__256, JWTAlgorithmAsymmetricBase__AlgorithmNumber__384, JWTAlgorithmAsymmetricBase__AlgorithmNumber__512 }; @interface JWTAlgorithmAsymmetricBase () @property (copy, nonatomic, readwrite) NSNumber *algorithmType; @property (copy, nonatomic, readwrite) NSNumber *algorithmNumber; @property (strong, nonatomic, readonly) id keyExtractor; @property (copy, nonatomic, readwrite) JWTAlgorithmAsymmetricBase *(^setAlgorithmType)(JWTAlgorithmAsymmetricBase__AlgorithmType); @property (copy, nonatomic, readwrite) JWTAlgorithmAsymmetricBase *(^setAlgorithmNumber)(JWTAlgorithmAsymmetricBase__AlgorithmNumber); @end @implementation JWTAlgorithmAsymmetricBase @synthesize keyExtractorType; @synthesize signKey; @synthesize verifyKey; @synthesize privateKeyCertificatePassphrase; - (void)setupFluent { __weak typeof(self) weakSelf = self; self.setAlgorithmType = ^(JWTAlgorithmAsymmetricBase__AlgorithmType type) { weakSelf.algorithmType = @(type); return weakSelf; }; self.setAlgorithmNumber = ^(JWTAlgorithmAsymmetricBase__AlgorithmNumber number) { weakSelf.algorithmNumber = @(number); return weakSelf; }; } - (instancetype)init { self = [super init]; if (self) { [self setupFluent]; } return self; } - (id)keyExtractor { return [JWTCryptoKeyExtractor createWithType:self.keyExtractorType]; } @end @interface JWTAlgorithmAsymmetricBase (SignAndVerify) #pragma mark - Private ( Override-part depends on platform ) - (BOOL)verifyData:(NSData *)plainData signature:(NSData *)signature key:(SecKeyRef)publicKey error:(NSError *__autoreleasing*)error; - (NSData *)signData:(NSData *)plainData key:(SecKeyRef)privateKey error:(NSError *__autoreleasing*)error; @end @implementation JWTAlgorithmAsymmetricBase (SignAndVerify) #pragma mark - Private ( Override-part depends on platform ) - (BOOL)verifyData:(NSData *)plainData signature:(NSData *)signature key:(SecKeyRef)publicKey error:(NSError *__autoreleasing*)error { return NO; } - (NSData *)signData:(NSData *)plainData key:(SecKeyRef)privateKey error:(NSError *__autoreleasing*)error { return nil; } @end @implementation JWTAlgorithmAsymmetricBase (JWTAsymmetricKeysAlgorithm) @dynamic privateKeyCertificatePassphrase; - (NSString *)name { return @"AssymetricBase"; } - (NSData *)signHash:(NSData *)hash key:(NSData *)key error:(NSError *__autoreleasing *)error { return nil; } - (BOOL)verifyHash:(NSData *)hash signature:(NSData *)signature key:(NSData *)key error:(NSError *__autoreleasing *)error { return NO; } #pragma mark - NSCopying - (id)copyWithZone:(NSZone *)zone { // create new. id algorithm = (id)[JWTAlgorithmFactory algorithmByName:[self name]]; algorithm.privateKeyCertificatePassphrase = self.privateKeyCertificatePassphrase; algorithm.keyExtractorType = self.keyExtractorType; algorithm.signKey = self.signKey; algorithm.verifyKey = self.verifyKey; return algorithm; } @end @interface JWTAlgorithmAsymmetricBase__Prior10 : JWTAlgorithmAsymmetricBase @end @implementation JWTAlgorithmAsymmetricBase__Prior10 @end #import #if JWT_CRYPTO_MODERN_API_IS_ALLOWED SecKeyAlgorithm chooseAlgorithm(NSNumber *type, NSNumber *number) { if (@available(macOS 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *)) { switch ((JWTAlgorithmAsymmetricBase__AlgorithmNumber)number.integerValue) { case JWTAlgorithmAsymmetricBase__AlgorithmNumber__256: switch ((JWTAlgorithmAsymmetricBase__AlgorithmType)type.integerValue) { case JWTAlgorithmAsymmetricBase__AlgorithmType__RS: return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256; case JWTAlgorithmAsymmetricBase__AlgorithmType__ES: return kSecKeyAlgorithmECDSASignatureMessageX962SHA256; case JWTAlgorithmAsymmetricBase__AlgorithmType__PS: { if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)) { return kSecKeyAlgorithmRSASignatureMessagePSSSHA256; } break; } } case JWTAlgorithmAsymmetricBase__AlgorithmNumber__384: switch ((JWTAlgorithmAsymmetricBase__AlgorithmType)type.integerValue) { case JWTAlgorithmAsymmetricBase__AlgorithmType__RS: return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384; case JWTAlgorithmAsymmetricBase__AlgorithmType__ES: return kSecKeyAlgorithmECDSASignatureMessageX962SHA384; case JWTAlgorithmAsymmetricBase__AlgorithmType__PS: { if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)) { return kSecKeyAlgorithmRSASignatureMessagePSSSHA384; } break; } } case JWTAlgorithmAsymmetricBase__AlgorithmNumber__512: switch ((JWTAlgorithmAsymmetricBase__AlgorithmType)type.integerValue) { case JWTAlgorithmAsymmetricBase__AlgorithmType__RS: return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512; case JWTAlgorithmAsymmetricBase__AlgorithmType__ES: return kSecKeyAlgorithmECDSASignatureMessageX962SHA512; case JWTAlgorithmAsymmetricBase__AlgorithmType__PS: { if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)) { return kSecKeyAlgorithmRSASignatureMessagePSSSHA512; } break; } } } return NULL; } else { return NULL; } } #ifdef NS_AVAILABLE NS_AVAILABLE(10_12, 10_0) #endif @interface JWTAlgorithmAsymmetricBase__After10 : JWTAlgorithmAsymmetricBase @property (assign, nonatomic, readonly) SecKeyAlgorithm algorithm; @end @implementation JWTAlgorithmAsymmetricBase__After10 - (SecKeyAlgorithm)chooseAlgorithmByType:(NSNumber *)type number:(NSNumber *)number { return chooseAlgorithm(type, number); } - (SecKeyAlgorithm)algorithm { return [self chooseAlgorithmByType:self.algorithmType number:self.algorithmNumber]; } @end @implementation JWTAlgorithmAsymmetricBase__After10 (SignAndVerify) - (NSData *)signData:(NSData *)plainData key:(SecKeyRef)privateKey error:(NSError *__autoreleasing *)error { if (@available(macOS 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *)) { CFErrorRef theError = NULL; NSData *result = (NSData *)CFBridgingRelease(SecKeyCreateSignature(privateKey, self.algorithm, (__bridge CFDataRef)plainData, &theError)); if (error && theError) { *error = (__bridge NSError *)(theError); } return result; } else { if (error) { *error = [JWTAlgorithmAsymmetricFamilyErrorDescription errorWithCode:JWTAlgorithmAsymmetricFamilyErrorAlgorithmIsNotSupported]; } return nil; } } - (BOOL)verifyData:(NSData *)plainData signature:(NSData *)signature key:(SecKeyRef)publicKey error:(NSError *__autoreleasing *)error { if (@available(macOS 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *)) { CFErrorRef theError = NULL; BOOL result = SecKeyVerifySignature(publicKey, self.algorithm, (__bridge CFDataRef)plainData, (__bridge CFDataRef)signature, &theError); if (error && theError) { *error = (__bridge NSError *)(theError); } return result; } else { if (error) { *error = [JWTAlgorithmAsymmetricFamilyErrorDescription errorWithCode:JWTAlgorithmAsymmetricFamilyErrorAlgorithmIsNotSupported]; } return NO; } } @end @implementation JWTAlgorithmAsymmetricBase__After10 (JWTAsymmetricKeysAlgorithm) #pragma mark - JWTAlgorithm - (NSDictionary *)verifyKeyExtractorParameters { switch ((JWTAlgorithmAsymmetricBase__AlgorithmType)self.algorithmType.integerValue) { case JWTAlgorithmAsymmetricBase__AlgorithmType__RS: return @{[JWTCryptoKey parametersKeyBuilder] : [JWTCryptoKeyBuilder new].keyTypeRSA}; case JWTAlgorithmAsymmetricBase__AlgorithmType__ES: return @{[JWTCryptoKey parametersKeyBuilder] : [JWTCryptoKeyBuilder new].keyTypeEC}; default: return nil; } } - (NSDictionary *)signKeyExtractorParameters { NSMutableDictionary *mutableDictionary = [[self verifyKeyExtractorParameters] mutableCopy]; mutableDictionary[[JWTCryptoKeyExtractor parametersKeyCertificatePassphrase]] = self.privateKeyCertificatePassphrase ?: [NSNull null]; return [mutableDictionary copy]; } - (BOOL)removeKeyItem:(id)item error:(NSError *__autoreleasing *)error { NSError *theError = nil; [JWTCryptoSecurity removeKeyByTag:item.tag error:&theError]; if (error) { *error = theError; } return theError == nil; } - (NSData *)signHash:(NSData *)hash key:(NSData *)key error:(NSError *__autoreleasing *)error { id theExtractor = self.keyExtractor ?: [JWTCryptoKeyExtractor privateKeyInP12]; NSError *extractKeyError = nil; id keyItem = self.signKey ?: [theExtractor keyFromData:key parameters:[self signKeyExtractorParameters] error:&extractKeyError]; if (extractKeyError || keyItem == nil) { // tell about error if (extractKeyError && error) { *error = extractKeyError; } NSError *removeError = nil; [self removeKeyItem:keyItem error:&removeError]; return nil; } else { NSError *signError = nil; NSData *result = [self signData:hash key:keyItem.key error:&signError]; if (signError && error) { *error = signError; } return result; } } - (BOOL)verifyHash:(NSData *)hash signature:(NSData *)signature key:(NSData *)key error:(NSError *__autoreleasing *)error { id theExtractor = self.keyExtractor ?: [JWTCryptoKeyExtractor publicKeyWithCertificate]; NSError *extractKeyError = nil; id keyItem = self.verifyKey ?: [theExtractor keyFromData:key parameters:[self verifyKeyExtractorParameters] error:&extractKeyError]; if (extractKeyError || keyItem == nil) { if (extractKeyError && error) { *error = extractKeyError; } NSError *removeError = nil; [self removeKeyItem:keyItem error:&removeError]; return NO; } else { NSError *verifyError = nil; BOOL verified = [self verifyData:hash signature:signature key:keyItem.key error:&verifyError]; if (verifyError && error) { *error = verifyError; } NSError *removeError = nil; [self removeKeyItem:keyItem error:&removeError]; return verified; } } @end #endif //// MacOS OR iOS is Base //#if TARGET_OS_MAC && !TARGET_OS_IPHONE // check that mac version is ok. //@interface JWTAlgorithmRSFamilyMember : JWTAlgorithmRSBaseMac @end //#else // check that iphone version is ok. //@interface JWTAlgorithmRSFamilyMember : JWTAlgorithmRSBaseIOS @end //#endif // (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_10_0) || @interface JWTAlgorithmAsymmetricBase__FamilyMember : #if JWT_CRYPTO_MODERN_API_IS_ALLOWED JWTAlgorithmAsymmetricBase__After10 #else JWTAlgorithmAsymmetricBase__Prior10 #endif @end @implementation JWTAlgorithmAsymmetricBase__FamilyMember - (NSString *)stringForAlgorithmNumber:(JWTAlgorithmAsymmetricBase__AlgorithmNumber)number { switch (number) { case JWTAlgorithmAsymmetricBase__AlgorithmNumber__256: return @"256"; case JWTAlgorithmAsymmetricBase__AlgorithmNumber__384: return @"384"; case JWTAlgorithmAsymmetricBase__AlgorithmNumber__512: return @"512"; default: return nil; } } - (NSString *)stringForAlgorithmType:(JWTAlgorithmAsymmetricBase__AlgorithmType)type { switch (type) { case JWTAlgorithmAsymmetricBase__AlgorithmType__RS: return @"RS"; case JWTAlgorithmAsymmetricBase__AlgorithmType__ES: return @"ES"; case JWTAlgorithmAsymmetricBase__AlgorithmType__PS: return @"PS"; default: return nil; } } - (NSString *)name { return [[self stringForAlgorithmType:(JWTAlgorithmAsymmetricBase__AlgorithmType)self.algorithmType.integerValue] stringByAppendingString:[self stringForAlgorithmNumber:(JWTAlgorithmAsymmetricBase__AlgorithmNumber)self.algorithmNumber.integerValue]]; } @end @interface JWTAlgorithmAsymmetricBase__FamilyMember__RS : JWTAlgorithmAsymmetricBase__FamilyMember @end @implementation JWTAlgorithmAsymmetricBase__FamilyMember__RS - (NSNumber *)algorithmType { return @(JWTAlgorithmAsymmetricBase__AlgorithmType__RS); } @end @interface JWTAlgorithmAsymmetricBase__FamilyMember__ES : JWTAlgorithmAsymmetricBase__FamilyMember @end @implementation JWTAlgorithmAsymmetricBase__FamilyMember__ES - (NSNumber *)algorithmType { return @(JWTAlgorithmAsymmetricBase__AlgorithmType__ES); } @end @interface JWTAlgorithmAsymmetricBase__FamilyMember__PS : JWTAlgorithmAsymmetricBase__FamilyMember @end @implementation JWTAlgorithmAsymmetricBase__FamilyMember__PS - (NSNumber *)algorithmType { return @(JWTAlgorithmAsymmetricBase__AlgorithmType__PS); } @end @implementation JWTAlgorithmAsymmetricBase (Create) + (instancetype)withRS { return [[JWTAlgorithmAsymmetricBase__FamilyMember__RS alloc] init]; } + (instancetype)withES { return [[JWTAlgorithmAsymmetricBase__FamilyMember__ES alloc] init]; } + (instancetype)withPS { return [[JWTAlgorithmAsymmetricBase__FamilyMember__PS alloc] init]; } - (instancetype)with256 { return self.setAlgorithmNumber(JWTAlgorithmAsymmetricBase__AlgorithmNumber__256); } - (instancetype)with384 { return self.setAlgorithmNumber(JWTAlgorithmAsymmetricBase__AlgorithmNumber__384); } - (instancetype)with512 { return self.setAlgorithmNumber(JWTAlgorithmAsymmetricBase__AlgorithmNumber__512); } @end ================================================ FILE: Sources/JWT/Algorithms/ESFamily/JWTAlgorithmESBase.m ================================================ // // JWTAlgorithmESBase.m // Pods // // Created by Lobanov Dmitry on 12.02.17. // // #import "JWTAlgorithmESBase.h" #import NSString *const JWTAlgorithmNameES256 = @"ES256"; NSString *const JWTAlgorithmNameES384 = @"ES384"; NSString *const JWTAlgorithmNameES512 = @"ES512"; @interface JWTAlgorithmESBase () @end @implementation JWTAlgorithmESBase @synthesize keyExtractorType; @synthesize signKey; @synthesize verifyKey; @end // thanks! https://github.com/soyersoyer/SwCrypt @interface JWTAlgorithmESBase (ImportKeys) - (void)importKey; //importKey(publicKey, format: .importKeyBinary, keyType: .keyPublic) @end @implementation JWTAlgorithmESBase (ImportKeys) - (void)importKey { return; } @end @implementation JWTAlgorithmESBase (JWTAsymmetricKeysAlgorithm) - (NSString *)name { return @"ESBase"; } - (NSData *)signHash:(NSData *)hash key:(NSData *)key error:(NSError *__autoreleasing *)error { return nil; } - (BOOL)verifyHash:(NSData *)hash signature:(NSData *)signature key:(NSData *)key error:(NSError *__autoreleasing *)error { return NO; } @end ================================================ FILE: Sources/JWT/Algorithms/HSFamily/JWTAlgorithmHSBase.m ================================================ // // JWTAlgorithmHSBase.m // JWT // // Created by Lobanov Dmitry on 13.03.16. // Copyright © 2016 Karma. All rights reserved. // #import "JWTAlgorithmHSBase.h" #import "JWTBase64Coder.h" #import #import NSString *const JWTAlgorithmNameHS256 = @"HS256"; NSString *const JWTAlgorithmNameHS384 = @"HS384"; NSString *const JWTAlgorithmNameHS512 = @"HS512"; @interface JWTAlgorithmHSBase () @end @implementation JWTAlgorithmHSBase - (size_t)ccSHANumberDigestLength { @throw [[NSException alloc] initWithName:NSInternalInconsistencyException reason:@"ccSHANumberDigestLength property should be overriden" userInfo:nil]; } - (uint32_t)ccHmacAlgSHANumber { @throw [[NSException alloc] initWithName:NSInternalInconsistencyException reason:@"ccHmacAlgSHANumber property should be overriden" userInfo:nil]; } - (NSData *)signHash:(NSData *)hash key:(NSData *)key error:(NSError *__autoreleasing *)error { size_t amount = self.ccSHANumberDigestLength; size_t fullSize = amount * sizeof(unsigned char); unsigned char* cHMAC = malloc(fullSize); CCHmacAlgorithm ccAlg = self.ccHmacAlgSHANumber; CCHmac(ccAlg, key.bytes, key.length, hash.bytes, hash.length, cHMAC); NSData *result = [[NSData alloc] initWithBytes:cHMAC length:fullSize]; free(cHMAC); return result; } - (BOOL)verifyHash:(NSData *)hash signature:(NSData *)signature key:(NSData *)key error:(NSError *__autoreleasing *)error { NSData *expectedSignatureData = [self signHash:hash key:key error:error]; return [expectedSignatureData isEqualToData:signature]; } - (NSString *)name { return @"HSBase"; } @end @interface JWTAlgorithmHSFamilyMember : JWTAlgorithmHSBase @end @implementation JWTAlgorithmHSFamilyMember @end @interface JWTAlgorithmHS256 : JWTAlgorithmHSBase @end @interface JWTAlgorithmHS384 : JWTAlgorithmHSBase @end @interface JWTAlgorithmHS512 : JWTAlgorithmHSBase @end @implementation JWTAlgorithmHS256 - (size_t)ccSHANumberDigestLength { return CC_SHA256_DIGEST_LENGTH; } - (uint32_t)ccHmacAlgSHANumber { return kCCHmacAlgSHA256; } - (NSString *)name { return @"HS256"; } @end @implementation JWTAlgorithmHS384 - (size_t)ccSHANumberDigestLength { return CC_SHA384_DIGEST_LENGTH; } - (uint32_t)ccHmacAlgSHANumber { return kCCHmacAlgSHA384; } - (NSString *)name { return @"HS384"; } @end @implementation JWTAlgorithmHS512 - (size_t)ccSHANumberDigestLength { return CC_SHA512_DIGEST_LENGTH; } - (uint32_t)ccHmacAlgSHANumber { return kCCHmacAlgSHA512; } - (NSString *)name { return @"HS512"; } @end @interface JWTAlgorithmHSFamilyMemberMutable : JWTAlgorithmHSFamilyMember @property (assign, nonatomic, readwrite) size_t ccSHANumberDigestLength; @property (assign, nonatomic, readwrite) uint32_t ccHmacAlgSHANumber; @property (copy, nonatomic, readwrite) NSString *name; @end @implementation JWTAlgorithmHSFamilyMemberMutable @synthesize ccSHANumberDigestLength = _ccSHANumberDigestLength; @synthesize ccHmacAlgSHANumber = _ccHmacAlgSHANumber; @synthesize name = _name; - (size_t)ccSHANumberDigestLength { return _ccSHANumberDigestLength; } - (uint32_t)ccHmacAlgSHANumber { return _ccHmacAlgSHANumber; } @end @implementation JWTAlgorithmHSBase (Create) + (instancetype)algorithm256 { return [JWTAlgorithmHS256 new]; } + (instancetype)algorithm384 { return [JWTAlgorithmHS384 new]; } + (instancetype)algorithm512 { return [JWTAlgorithmHS512 new]; } @end ================================================ FILE: Sources/JWT/Algorithms/Holders/JWTAlgorithmDataHolder+FluentStyle.m ================================================ // // JWTAlgorithmDataHolder+FluentStyle.m // JWT // // Created by Dmitry Lobanov on 07/06/2019. // Copyright © 2019 JWTIO. All rights reserved. // #import "JWTAlgorithmDataHolder+FluentStyle.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wobjc-property-implementation" @implementation JWTAlgorithmBaseDataHolder (FluentStyle) @end @implementation JWTAlgorithmRSFamilyDataHolder (FluentStyle) @end #pragma clang diagnostic pop ================================================ FILE: Sources/JWT/Algorithms/Holders/JWTAlgorithmDataHolder.m ================================================ // // JWTAlgorithmDataHolder.m // JWT // // Created by Lobanov Dmitry on 31.08.16. // Copyright © 2016 Karma. All rights reserved. // #import "JWTAlgorithmDataHolder.h" #import "JWTAlgorithmFactory.h" #import "JWTAlgorithmNone.h" #import "JWTRSAlgorithm.h" #import "JWTAlgorithmHSBase.h" #import "JWTAlgorithmRSBase.h" #import "JWTBase64Coder.h" #import "JWTCryptoKey.h" @interface JWTAlgorithmBaseDataHolder() // not needed by algorithm adoption. // @property (copy, nonatomic, readwrite) NSData *internalSecretData; // @property (strong, nonatomic, readwrite) id internalAlgorithm; #pragma mark - Setters /** Sets jwtSecret and returns the JWTAlgorithmBaseDataHolder to allow for method chaining */ @property (copy, nonatomic, readwrite) JWTAlgorithmBaseDataHolder *(^secret)(NSString *secret); /** Sets jwtSecretData and returns the JWTAlgorithmBaseDataHolder to allow for method chaining */ @property (copy, nonatomic, readwrite) JWTAlgorithmBaseDataHolder *(^secretData)(NSData *secretData); /** Sets jwtAlgorithm and returns the JWTAlgorithmBaseDataHolder to allow for method chaining */ @property (copy, nonatomic, readwrite) JWTAlgorithmBaseDataHolder *(^algorithm)(idalgorithm); /** Sets jwtAlgorithmName and returns the JWTAlgorithmBaseDataHolder to allow for method chaining. See list of names in appropriate headers. */ @property (copy, nonatomic, readwrite) JWTAlgorithmBaseDataHolder *(^algorithmName)(NSString *algorithmName); /** Sets stringCoder and returns the JWTAlgorithmBaseDataHolder to allow for method chaining. See list of names in appropriate headers. */ @property (copy, nonatomic, readwrite) JWTAlgorithmBaseDataHolder *(^stringCoder)(id stringCoder); @end @interface JWTAlgorithmBaseDataHolder (Convertions) - (NSData *)dataFromString:(NSString *)string; - (NSString *)stringFromData:(NSData *)data; @end @implementation JWTAlgorithmBaseDataHolder (Convertions) #pragma mark - Convertions - (NSData *)dataFromString:(NSString *)string { NSData *result = [self.internalStringCoder dataWithString:string]; if (result == nil) { // tell about it?! NSLog(@"%@ %@ something went wrong. Data is not base64encoded! %@", self.debugDescription, NSStringFromSelector(_cmd), string); } return result;// ?: [string dataUsingEncoding:NSUTF8StringEncoding]; } - (NSString *)stringFromData:(NSData *)data { NSString *result = [self.internalStringCoder stringWithData:data]; if (result == nil) { NSLog(@"%@ %@ something went wrong. String is not base64encoded", self.debugDescription, NSStringFromSelector(_cmd)); } return result ?: [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; } @end @interface JWTAlgorithmBaseDataHolder (Fluent) - (void)setupFluent; @end @implementation JWTAlgorithmBaseDataHolder (Fluent) #pragma mark - Fluent - (void)setupFluent { __weak typeof(self) weakSelf = self; self.secret = ^(NSString *secret) { return [weakSelf secret:secret]; }; self.secretData = ^(NSData *secretData) { return [weakSelf secretData:secretData]; }; self.algorithm = ^(id algorithm) { return [weakSelf algorithm:algorithm]; }; self.algorithmName = ^(NSString *algorithmName) { return [weakSelf algorithmName:algorithmName]; }; self.stringCoder = ^(id stringCoder) { return [weakSelf stringCoder:stringCoder]; }; } @end @interface JWTAlgorithmBaseDataHolder (Debug) - (NSDictionary *)debugInformation; @end @implementation JWTAlgorithmBaseDataHolder (Debug) - (NSString *)debugDescription { return [[self debugInformation] debugDescription]; } - (NSDictionary *)debugInformation { return @{ @"algorithmName" : self.internalAlgorithmName ?: @"unknown", @"algorithm" : [self.internalAlgorithm debugDescription] ?: @"unknown", @"secretData" : [self.internalSecretData debugDescription] ?: @"unknown", @"stringCoder" : [self.internalStringCoder debugDescription] ?: @"unknown" }; } @end @implementation JWTAlgorithmBaseDataHolder @synthesize internalAlgorithm; @synthesize internalSecretData; @synthesize internalStringCoder = _internalStringCoder; - (id)internalStringCoder { return _internalStringCoder ?: [JWTBase64Coder new]; } #pragma mark - Custom Getters - (NSString *)internalAlgorithmName { return [self.internalAlgorithm name]; } - (NSString *)internalSecret { return [self stringFromData:self.internalSecretData]; } - (instancetype)init { self = [super init]; if (self) { [self setupFluent]; } return self; } #pragma mark - Copy - (id)copyWithZone:(NSZone *)zone { JWTAlgorithmBaseDataHolder *holder = [self.class new]; holder.internalAlgorithm = self.internalAlgorithm; holder.internalSecretData = self.internalSecretData; holder.internalStringCoder = self.internalStringCoder; return holder; } @end @implementation JWTAlgorithmBaseDataHolder (Setters) - (instancetype)secretData:(NSData *)secretData { self.internalSecretData = secretData; return self; } - (instancetype)secret:(NSString *)secret { self.internalSecretData = [self dataFromString:secret]; return self; } - (instancetype)algorithm:(id)algorithm { self.internalAlgorithm = algorithm; return self; } - (instancetype)algorithmName:(NSString *)algorithmName { self.internalAlgorithm = [JWTAlgorithmFactory algorithmByName:algorithmName]; return self; } - (instancetype)stringCoder:(id)stringCoder { self.internalStringCoder = stringCoder; return self; } @end @interface JWTAlgorithmBaseDataHolder (Create) - (instancetype)initWithAlgorithmName:(NSString *)name; @end @implementation JWTAlgorithmBaseDataHolder (Create) - (instancetype)initWithAlgorithmName:(NSString *)name { return [self init].algorithmName(name); } @end @implementation JWTAlgorithmNoneDataHolder - (instancetype)init { if (self = [super init]) { self.internalAlgorithm = [JWTAlgorithmFactory algorithmByName:JWTAlgorithmNameNone]; self.internalSecretData = nil; } return self; } @end @implementation JWTAlgorithmHSFamilyDataHolder + (instancetype)createWithAlgorithm256 { return [[self alloc] initWithAlgorithmName:JWTAlgorithmNameHS256]; } + (instancetype)createWithAlgorithm384 { return [[self alloc] initWithAlgorithmName:JWTAlgorithmNameHS384]; } + (instancetype)createWithAlgorithm512 { return [[self alloc] initWithAlgorithmName:JWTAlgorithmNameHS512]; } @end @interface JWTAlgorithmRSFamilyDataHolder() #pragma mark - Getters @property (copy, nonatomic, readwrite) NSString *internalPrivateKeyCertificatePassphrase; @property (copy, nonatomic, readwrite) NSString *internalKeyExtractorType; @property (strong, nonatomic, readwrite) id internalSignKey; @property (strong, nonatomic, readwrite) id internalVerifyKey; #pragma mark - Setters @property (copy, nonatomic, readwrite) JWTAlgorithmRSFamilyDataHolder *(^privateKeyCertificatePassphrase)(NSString *privateKeyCertificatePassphrase); @property (copy, nonatomic, readwrite) JWTAlgorithmRSFamilyDataHolder *(^keyExtractorType)(NSString *keyExtractorType); @property (copy, nonatomic, readwrite) JWTAlgorithmRSFamilyDataHolder *(^signKey)(id signKey); @property (copy, nonatomic, readwrite) JWTAlgorithmRSFamilyDataHolder *(^verifyKey)(id verifyKey); @end @implementation JWTAlgorithmRSFamilyDataHolder (Debug) - (NSDictionary *)debugInformation { NSDictionary *add = @{@"privateKeyCertificatePassphrase" : self.internalPrivateKeyCertificatePassphrase ?: @"unknown", @"keyExtractorType" : self.internalKeyExtractorType ?: @"unknown", @"signKey" : [self.internalSignKey debugDescription] ?: @"unknown", @"verifyKey" : [self.internalVerifyKey debugDescription] ?: @"unknown" }; NSMutableDictionary *result = [[super debugInformation] mutableCopy]; [result addEntriesFromDictionary:add]; return result; } @end @implementation JWTAlgorithmRSFamilyDataHolder #pragma mark - Initialization - (instancetype)init { return (typeof(self))[super init].stringCoder([JWTBase64Coder withBase64String]); } + (instancetype)createWithAlgorithm256 { return [[self alloc] initWithAlgorithmName:JWTAlgorithmNameRS256]; } + (instancetype)createWithAlgorithm384 { return [[self alloc] initWithAlgorithmName:JWTAlgorithmNameRS384]; } + (instancetype)createWithAlgorithm512 { return [[self alloc] initWithAlgorithmName:JWTAlgorithmNameRS512]; } #pragma mark - Getters - (id)internalAlgorithm { id algorithm = [super internalAlgorithm]; if ([algorithm conformsToProtocol:@protocol(JWTRSAlgorithm)]) { // copy? idcurrentAlgorithm = [(id )algorithm copyWithZone:nil]; currentAlgorithm.privateKeyCertificatePassphrase = self.internalPrivateKeyCertificatePassphrase; currentAlgorithm.keyExtractorType = self.internalKeyExtractorType; currentAlgorithm.signKey = self.internalSignKey; currentAlgorithm.verifyKey = self.internalVerifyKey; algorithm = currentAlgorithm; } return algorithm; } #pragma mark - Copy - (id)copyWithZone:(NSZone *)zone { JWTAlgorithmRSFamilyDataHolder *holder = [super copyWithZone:zone]; holder.internalPrivateKeyCertificatePassphrase = self.internalPrivateKeyCertificatePassphrase; holder.internalKeyExtractorType = self.internalKeyExtractorType; holder.internalSignKey = self.internalSignKey; holder.internalVerifyKey = self.internalVerifyKey; return holder; } @end @implementation JWTAlgorithmRSFamilyDataHolder (Fluent) - (void)setupFluent { [super setupFluent]; __weak typeof(self) weakSelf = self; self.privateKeyCertificatePassphrase = ^(NSString *privateKeyCertificatePassphrase) { return [weakSelf privateKeyCertificatePassphrase:privateKeyCertificatePassphrase]; }; self.keyExtractorType = ^(NSString *keyExtractorType) { return [weakSelf keyExtractorType:keyExtractorType]; }; self.signKey = ^(id key){ return [weakSelf signKey:key]; }; self.verifyKey = ^(id key){ return [weakSelf verifyKey:key]; }; } @end @implementation JWTAlgorithmRSFamilyDataHolder (Setters) - (instancetype)privateKeyCertificatePassphrase:(NSString *)passphrase { self.internalPrivateKeyCertificatePassphrase = passphrase; return self; } - (instancetype)keyExtractorType:(NSString *)type { self.internalKeyExtractorType = type; return self; } - (instancetype)signKey:(id)key { self.internalSignKey = key; return self; } - (instancetype)verifyKey:(id)key { self.internalVerifyKey = key; return self; } @end ================================================ FILE: Sources/JWT/Algorithms/Holders/JWTAlgorithmDataHolderChain.m ================================================ // // JWTAlgorithmDataHolderChain.m // JWT // // Created by Lobanov Dmitry on 02.10.16. // Copyright © 2016 Karma. All rights reserved. // #import "JWTAlgorithmDataHolderChain.h" @interface JWTAlgorithmDataHolderChain() @property (strong, nonatomic, readwrite) NSArray *holders; @end @implementation JWTAlgorithmDataHolderChain - (NSArray *)holders { if (!_holders) { _holders = @[]; } return _holders; } #pragma mark - Initialization - (instancetype)initWithHolders:(NSArray *)holders { self = [super init]; if (holders) { // check that holders conform to protocol NSArray *checkedHolders = [holders filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id _Nullable evaluatedObject, NSDictionary * _Nullable bindings) { return [evaluatedObject conformsToProtocol:@protocol(JWTAlgorithmDataHolderProtocol)]; }]]; self.holders = checkedHolders; } return self; } - (instancetype)initWithHolder:(id)holder { if (holder) { return [self initWithHolders:@[holder]]; } return nil; } #pragma mark - Appending - (instancetype)chainByAppendingChain:(JWTAlgorithmDataHolderChain *)chain { NSArray *holders = self.holders; if (chain) { holders = [holders arrayByAddingObjectsFromArray:chain.holders]; } return [[self.class alloc] initWithHolders:holders]; } - (instancetype)chainByAppendingHolders:(NSArray *)holders { // create new chain with holders JWTAlgorithmDataHolderChain *chain = nil; if (holders) { chain = [[self.class alloc] initWithHolders:holders]; } return [self chainByAppendingChain:chain]; } - (instancetype)chainByAppendingHolder:(id)holder { return [self chainByAppendingHolders:holder ? @[holder] : nil]; } #pragma mark - Create + (instancetype)chainWithHolders:(NSArray *)holders { return [[self new] chainByAppendingHolders:holders]; } + (instancetype)chainWithHolder:(id)holder { return [[self new] chainByAppendingHolder:holder]; } #pragma mark - Debug - (NSString *)debugDescription { return [NSString stringWithFormat:@"%@ holders: %@", self.class, [self.holders valueForKey:@"debugDescription"]]; } @end @implementation JWTAlgorithmDataHolderChain (Convenient) - (id)firstHolderByAlgorithm:(id)algorithm { NSInteger index = [self.holders indexOfObjectPassingTest:^BOOL(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { return [[[obj internalAlgorithm] name] isEqualToString:[algorithm name]]; }]; if (index != NSNotFound) { return self.holders[index]; } return nil; } - (id)firstHolderBySecretData:(NSData *)secretData { NSInteger index = [self.holders indexOfObjectPassingTest:^BOOL(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { return [[obj internalSecretData] isEqualToData:secretData]; }]; if (index != NSNotFound) { return self.holders[index]; } return nil; } - (NSArray *)singleAlgorithm:(id)algorithm withManySecretData:(NSArray *)secretsData { NSArray *holders = @[]; id holder = [self firstHolderByAlgorithm:algorithm]; if (!holder) { return holders; } for (NSData *secretData in secretsData) { id newHolder = [holder copy]; [newHolder setInternalSecretData:secretData]; holders = [holders arrayByAddingObject:newHolder]; } return holders; } - (NSArray *)singleSecretData:(NSData *)secretData withManyAlgorithms:(NSArray *)algorithms { NSArray *holders = @[]; id holder = [self firstHolderBySecretData:secretData]; if (!holder) { return holders; } for (idalgorithm in algorithms) { id newHolder = [holder copy]; [newHolder setInternalAlgorithm:algorithm]; [holders arrayByAddingObject:newHolder]; } return holders; } - (instancetype)chainByPopulatingAlgorithm:(id)algorithm withManySecretData:(NSArray *)secretsData { return [[self.class alloc] initWithHolders:[self singleAlgorithm:algorithm withManySecretData:secretsData]]; } - (instancetype)chainByPopulatingSecretData:(NSData *)secretData withManyAlgorithms:(NSArray *)algorithms { return [[self.class alloc] initWithHolders:[self singleSecretData:secretData withManyAlgorithms:algorithms]]; } @end ================================================ FILE: Sources/JWT/Algorithms/RSFamily/JWTAlgorithmRSBase.m ================================================ // // JWTAlgorithmRSBase.m // JWT // // Created by Lobanov Dmitry on 13.03.16. // Copyright © 2016 Karma. All rights reserved. // #import "JWTAlgorithmRSBase.h" #import "JWTBase64Coder.h" #import "JWTCryptoSecurity.h" #import "JWTCryptoKeyExtractor.h" #import "JWTCryptoKey.h" #import "JWTAlgorithmFactory.h" #import #import "JWTAlgorithmErrorDescription+Subclass.h" NSString *const JWTAlgorithmRSFamilyErrorDomain = @"io.jwt.jwa.rs"; @implementation JWTAlgorithmRSFamilyErrorDescription #pragma mark - Subclass + (NSString *)errorDomain { return JWTAlgorithmRSFamilyErrorDomain; } + (NSInteger)defaultErrorCode { return JWTAlgorithmRSFamilyErrorUnexpected; } + (NSInteger)externalErrorCode { return JWTAlgorithmRSFamilyErrorInternalSecurityAPI; } + (NSDictionary *)codesAndUserDescriptions { static NSDictionary *dictionary = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ dictionary = @{ @(JWTAlgorithmRSFamilyErrorIncorrectHashComputation) : @"RS algorithm incorrect hash computation!", @(JWTAlgorithmRSFamilyErrorIncorrectKeySize) : @"RS algorithm incorrect key size. Apple have not sent any response about it.", @(JWTAlgorithmRSFamilyErrorInternalSecurityAPI) : @"RS algorithm internal security framework error.", @(JWTAlgorithmRSFamilyErrorUnexpected) : @"RS algorithm unexpected error!" }; }); return dictionary; } + (NSDictionary *)codesAndDescriptions { static NSDictionary *dictionary = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ dictionary = @{ @(JWTAlgorithmRSFamilyErrorIncorrectHashComputation) : @"JWTAlgorithmRSFamilyErrorIncorrectHashComputation", @(JWTAlgorithmRSFamilyErrorIncorrectKeySize) : @"JWTAlgorithmRSFamilyErrorIncorrectKeySize", @(JWTAlgorithmRSFamilyErrorInternalSecurityAPI) : @"JWTAlgorithmRSFamilyErrorInternalSecurityAPI", @(JWTAlgorithmRSFamilyErrorUnexpected) : @"JWTAlgorithmRSFamilyErrorUnexpected" }; }); return dictionary; } @end /* * * Possible inheritence * * * * RSBase (Public + Create-category) * / \ * / \ * RSBaseMac RSBaseIOS * \ ifdef / * \ / * RSFamilyMember * | * RSFamilyMemberMutable * */ NSString *const JWTAlgorithmNameRS256 = @"RS256"; NSString *const JWTAlgorithmNameRS384 = @"RS384"; NSString *const JWTAlgorithmNameRS512 = @"RS512"; @interface JWTAlgorithmRSBase() @property (nonatomic, readonly) id keyExtractor; @end @implementation JWTAlgorithmRSBase #pragma mark - NSCopying - (id)copyWithZone:(NSZone *)zone { // create new. id algorithm = (id)[JWTAlgorithmFactory algorithmByName:[self name]]; algorithm.privateKeyCertificatePassphrase = self.privateKeyCertificatePassphrase; algorithm.keyExtractorType = self.keyExtractorType; algorithm.signKey = self.signKey; algorithm.verifyKey = self.verifyKey; return algorithm; } @synthesize privateKeyCertificatePassphrase; @synthesize keyExtractorType; @synthesize signKey; @synthesize verifyKey; - (id) keyExtractor { return [JWTCryptoKeyExtractor createWithType:self.keyExtractorType]; } #pragma mark - Override - (size_t)ccSHANumberDigestLength { @throw [[NSException alloc] initWithName:NSInternalInconsistencyException reason:@"ccSHANumberDigestLength property should be overriden" userInfo:nil]; } - (uint32_t)secPaddingPKCS1SHANumber { @throw [[NSException alloc] initWithName:NSInternalInconsistencyException reason:@"secPaddingPKCS1SHANumber property should be overriden" userInfo:nil]; } - (unsigned char *)CC_SHANumberWithData:(const void *)data withLength:(CC_LONG)len withHashBytes:(unsigned char *)hashBytes { return nil; } - (NSString *)name { return @"RSBase"; } #pragma mark - JWTAlgorithm - (NSDictionary *)verifyKeyExtractorParameters { return @{[JWTCryptoKey parametersKeyBuilder] : [JWTCryptoKeyBuilder new].keyTypeRSA}; } - (NSDictionary *)signKeyExtractorParameters { NSMutableDictionary *mutableDictionary = [[self verifyKeyExtractorParameters] mutableCopy]; mutableDictionary[[JWTCryptoKeyExtractor parametersKeyCertificatePassphrase]] = self.privateKeyCertificatePassphrase ?: [NSNull null]; return [mutableDictionary copy]; } - (BOOL)removeKeyItem:(id)item error:(NSError *__autoreleasing *)error { NSError *theError = nil; [JWTCryptoSecurity removeKeyByTag:item.tag error:&theError]; if (error) { *error = theError; } return theError == nil; } - (NSData *)signHash:(NSData *)hash key:(NSData *)key error:(NSError *__autoreleasing *)error { id theExtractor = self.keyExtractor ?: [JWTCryptoKeyExtractor privateKeyInP12]; NSError *extractKeyError = nil; id keyItem = self.signKey ?: [theExtractor keyFromData:key parameters:[self signKeyExtractorParameters] error:&extractKeyError]; if (extractKeyError || keyItem == nil) { // tell about error if (extractKeyError && error) { *error = extractKeyError; } NSError *removeError = nil; [self removeKeyItem:keyItem error:&removeError]; return nil; } else { NSError *signError = nil; NSData *result = [self signData:hash key:keyItem.key error:&signError]; if (signError && error) { *error = signError; } return result; } } - (BOOL)verifyHash:(NSData *)hash signature:(NSData *)signature key:(NSData *)key error:(NSError *__autoreleasing *)error { id theExtractor = self.keyExtractor ?: [JWTCryptoKeyExtractor publicKeyWithCertificate]; NSError *extractKeyError = nil; id keyItem = self.verifyKey ?: [theExtractor keyFromData:key parameters:[self verifyKeyExtractorParameters] error:&extractKeyError]; if (extractKeyError || keyItem == nil) { if (extractKeyError && error) { *error = extractKeyError; } NSError *removeError = nil; [self removeKeyItem:keyItem error:&removeError]; return NO; } else { NSError *verifyError = nil; BOOL verified = [self verifyData:hash signature:signature key:keyItem.key error:&verifyError]; if (verifyError && error) { *error = verifyError; } NSError *removeError = nil; [self removeKeyItem:keyItem error:&removeError]; return verified; } } #pragma mark - Private ( Override-part depends on platform ) - (BOOL)verifyData:(NSData *)plainData signature:(NSData *)signature key:(SecKeyRef)publicKey error:(NSError *__autoreleasing*)error { return NO; } - (NSData *)signData:(NSData *)plainData key:(SecKeyRef)privateKey error:(NSError *__autoreleasing*)error { return nil; } @end #if TARGET_OS_MAC && TARGET_OS_IPHONE @interface JWTAlgorithmRSBaseIOS : JWTAlgorithmRSBase @end @implementation JWTAlgorithmRSBaseIOS - (BOOL)verifyData:(NSData *)plainData signature:(NSData *)signature key:(SecKeyRef)publicKey error:(NSError *__autoreleasing *)error { size_t signedHashBytesSize = SecKeyGetBlockSize(publicKey); const void* signedHashBytes = [signature bytes]; size_t hashBytesSize = self.ccSHANumberDigestLength; uint8_t* hashBytes = malloc(hashBytesSize); if (![self CC_SHANumberWithData:[plainData bytes] withLength:(CC_LONG)[plainData length] withHashBytes:hashBytes]) { if (error) { *error = [JWTAlgorithmRSFamilyErrorDescription errorWithCode:JWTAlgorithmRSFamilyErrorIncorrectHashComputation]; } return false; } OSStatus status = SecKeyRawVerify(publicKey, self.secPaddingPKCS1SHANumber, hashBytes, hashBytesSize, signedHashBytes, signedHashBytesSize); return status == errSecSuccess; } - (NSData *)signData:(NSData *)plainData key:(SecKeyRef)privateKey error:(NSError *__autoreleasing *)error { size_t signedHashBytesSize = SecKeyGetBlockSize(privateKey); uint8_t* signedHashBytes = malloc(signedHashBytesSize); memset(signedHashBytes, 0x0, signedHashBytesSize); size_t hashBytesSize = self.ccSHANumberDigestLength; uint8_t* hashBytes = malloc(hashBytesSize); // ([plainData bytes], (CC_LONG)[plainData length], hashBytes) unsigned char *str = [self CC_SHANumberWithData:[plainData bytes] withLength:(CC_LONG)[plainData length] withHashBytes:hashBytes]; if (!str) { if (error) { *error = [JWTAlgorithmRSFamilyErrorDescription errorWithCode:JWTAlgorithmRSFamilyErrorIncorrectHashComputation]; } return nil; } SecKeyRawSign(privateKey, self.secPaddingPKCS1SHANumber, hashBytes, hashBytesSize, signedHashBytes, &signedHashBytesSize); NSData* signedHash = [NSData dataWithBytes:signedHashBytes length:(NSUInteger)signedHashBytesSize]; if (hashBytes) { free(hashBytes); } if (signedHashBytes) { free(signedHashBytes); } return signedHash; } @end #endif #if TARGET_OS_MAC && !TARGET_OS_IPHONE @interface JWTAlgorithmRSBaseMac : JWTAlgorithmRSBase - (BOOL)checkKeyConsistency:(SecKeyRef)key; @end @implementation JWTAlgorithmRSBaseMac - (BOOL)checkKeyConsistency:(SecKeyRef)key { size_t keyLength = SecKeyGetBlockSize(key); size_t hashBytesSize = self.ccSHANumberDigestLength; Byte bitsPerByte = /*???*/sizeof(Byte) * CHAR_BIT; return keyLength == hashBytesSize * bitsPerByte; } - (NSData *)executeTransform:(SecTransformRef)transform withInput:(NSData *)input withDigestType:(CFStringRef)type withDigestLength:(NSNumber *)length withFalseResult:(CFTypeRef)falseResultRef { CFErrorRef errorRef = NULL; CFTypeRef resultRef = NULL; // inout NSData *resultData = nil; BOOL success = transform != NULL; //TODO: after import algorithm by pem, this code seems not working well. //error: Error Domain=com.apple.security.transforms.error Code=6 "Invalid digest algorithm for RSA signature, choose one of: SHA1, SHA2 (512bits, 348bits, 256bits, or 224 bits), MD2, or MD5" //TODO: add error inout parameter to this method. if (success) { // setup digest type success = SecTransformSetAttribute(transform, kSecDigestTypeAttribute, type, &errorRef); } if (success) { // digest length success = SecTransformSetAttribute(transform, kSecDigestLengthAttribute, (__bridge CFNumberRef)length, &errorRef); } if (success) { // set input success = SecTransformSetAttribute(transform, kSecTransformInputAttributeName, (__bridge CFDataRef)input, &errorRef); } if (success) { // execute resultRef = SecTransformExecute(transform, &errorRef); success = (resultRef != falseResultRef); } BOOL positiveResult = success; // resultRef != falseResultRef // error if (errorRef != NULL) { NSLog(@"%@ error: %@", self.debugDescription, (__bridge NSError *)errorRef); } else { if (positiveResult) { resultData = (__bridge NSData *)resultRef; } } if (resultRef != NULL) { CFRelease(resultRef); } if (errorRef != NULL) { CFRelease(errorRef); } return resultData; } - (BOOL)verifyData:(NSData *)plainData signature:(NSData *)signature key:(SecKeyRef)publicKey error:(NSError *__autoreleasing *)error { size_t signedHashBytesSize = SecKeyGetBlockSize(publicKey); //const void* signedHashBytes = [signature bytes]; size_t hashBytesSize = self.ccSHANumberDigestLength; uint8_t* hashBytes = malloc(hashBytesSize); Byte bitsPerByte = /*???*/sizeof(Byte) * CHAR_BIT; // NSNumber *plainDataLength = @((CC_LONG)[plainData length]); if (![self checkKeyConsistency:publicKey]) { // error in log! // bug? NSLog(@"the size of key(%@) should be related to SHA length in bits(%@)", @(signedHashBytesSize), @(hashBytesSize * bitsPerByte)); if (error) { *error = [JWTAlgorithmRSFamilyErrorDescription errorWithCode:JWTAlgorithmRSFamilyErrorIncorrectKeySize]; } return NO; } if (![self CC_SHANumberWithData:[plainData bytes] withLength:(CC_LONG)[plainData length] withHashBytes:hashBytes]) { if (error) { *error = [JWTAlgorithmRSFamilyErrorDescription errorWithCode:JWTAlgorithmRSFamilyErrorIncorrectHashComputation]; } return NO; } // NSString *formattedString = [NSString stringWithFormat:@"%@: %@ \n %@: %@ \n %@: %@", @"hashBytesSize", @(hashBytesSize), @"plainDataLength", plainDataLength, @"signedHashBytesSize", @(signedHashBytesSize)]; // // NSLog(@"%@ %@", self.debugDescription, formattedString); // verify for iOS // OSStatus status = SecKeyRawVerify(publicKey, // self.secPaddingPKCS1SHANumber, // hashBytes, // hashBytesSize, // signedHashBytes, // signedHashBytesSize); // return status == errSecSuccess; CFErrorRef errorRef = NULL; SecTransformRef transform = SecVerifyTransformCreate(publicKey, (__bridge CFDataRef)signature, &errorRef); // verification. false result is kCFBooleanFalse BOOL result = [self executeTransform:transform withInput:plainData withDigestType:kSecDigestSHA2 withDigestLength:@(signedHashBytesSize) withFalseResult:kCFBooleanFalse] != nil; if (transform != NULL) { // TODO: WTF? // somehow it stops there :/ // Is it a race condition with removeSecKeyForTag? // don't know :( CFRelease(transform); } if (errorRef != NULL) { CFRelease(errorRef); } if (hashBytes != NULL) { free(hashBytes); } return result; } - (NSData *)signData:(NSData *)plainData key:(SecKeyRef)privateKey error:(NSError *__autoreleasing *)error { size_t signedHashBytesSize = SecKeyGetBlockSize(privateKey); //uint8_t* signedHashBytes = malloc(signedHashBytesSize); //memset(signedHashBytes, 0x0, signedHashBytesSize); size_t hashBytesSize = self.ccSHANumberDigestLength; uint8_t* hashBytes = malloc(hashBytesSize); /** for sha256 CC_SHANumberWithData() is CC_SHA256() self.secPaddingPKCS1SHANumber = kSecPaddingPKCS1SHA256 self.ccSHANumberDigestLength = CC_SHA256_DIGEST_LENGTH */ unsigned char *str = [self CC_SHANumberWithData:[plainData bytes] withLength:(CC_LONG)[plainData length] withHashBytes:hashBytes]; if (!str) { if (error) { *error = [JWTAlgorithmRSFamilyErrorDescription errorWithCode:JWTAlgorithmRSFamilyErrorIncorrectHashComputation]; } return nil; } CFErrorRef errorRef = NULL; SecTransformRef transform = SecSignTransformCreate(privateKey, &errorRef); NSData *resultData = nil; // signing: false result is NULL. resultData = [self executeTransform:transform withInput:plainData withDigestType:kSecDigestSHA2 withDigestLength:@(signedHashBytesSize) withFalseResult:NULL]; if (transform != NULL) { CFRelease(transform); } if (errorRef != NULL) { CFRelease(errorRef); } if (hashBytes != NULL) { free(hashBytes); } return resultData; } @end #endif // MacOS OR iOS is Base #if TARGET_OS_MAC && !TARGET_OS_IPHONE @interface JWTAlgorithmRSFamilyMember : JWTAlgorithmRSBaseMac @end #else @interface JWTAlgorithmRSFamilyMember : JWTAlgorithmRSBaseIOS @end #endif @interface JWTAlgorithmRS256 : JWTAlgorithmRSFamilyMember @end @interface JWTAlgorithmRS384 : JWTAlgorithmRSFamilyMember @end @interface JWTAlgorithmRS512 : JWTAlgorithmRSFamilyMember @end @implementation JWTAlgorithmRSFamilyMember - (uint32_t)secPaddingPKCS1SHANumber { return 0; } @end @implementation JWTAlgorithmRS256 - (size_t)ccSHANumberDigestLength { return CC_SHA256_DIGEST_LENGTH; } #if TARGET_OS_MAC && TARGET_OS_IPHONE - (uint32_t)secPaddingPKCS1SHANumber { return kSecPaddingPKCS1SHA256; } #endif - (unsigned char *)CC_SHANumberWithData:(const void *)data withLength:(CC_LONG)len withHashBytes:(unsigned char *)hashBytes { return CC_SHA256(data, len, hashBytes); } - (NSString *)name { return JWTAlgorithmNameRS256; } @end @implementation JWTAlgorithmRS384 - (size_t)ccSHANumberDigestLength { return CC_SHA384_DIGEST_LENGTH; } #if TARGET_OS_MAC && TARGET_OS_IPHONE - (uint32_t)secPaddingPKCS1SHANumber { return kSecPaddingPKCS1SHA384; } #endif - (unsigned char *)CC_SHANumberWithData:(const void *)data withLength:(CC_LONG)len withHashBytes:(unsigned char *)hashBytes { return CC_SHA384(data, len, hashBytes); } - (NSString *)name { return JWTAlgorithmNameRS384; } @end @implementation JWTAlgorithmRS512 - (size_t)ccSHANumberDigestLength { return CC_SHA512_DIGEST_LENGTH; } #if TARGET_OS_MAC && TARGET_OS_IPHONE - (uint32_t)secPaddingPKCS1SHANumber { return kSecPaddingPKCS1SHA512; } #endif - (unsigned char *)CC_SHANumberWithData:(const void *)data withLength:(CC_LONG)len withHashBytes:(unsigned char *)hashBytes { return CC_SHA512(data, len, hashBytes); } - (NSString *)name { return JWTAlgorithmNameRS512; } @end @interface JWTAlgorithmRSFamilyMemberMutable : JWTAlgorithmRSFamilyMember @property (assign, nonatomic, readwrite) size_t ccSHANumberDigestLength; @property (assign, nonatomic, readwrite) uint32_t secPaddingPKCS1SHANumber; @property (copy, nonatomic, readwrite) unsigned char * (^ccShaNumberWithData)(const void *data, CC_LONG len, unsigned char *hashBytes); @property (copy, nonatomic, readwrite) NSString *name; @end @implementation JWTAlgorithmRSFamilyMemberMutable @synthesize ccSHANumberDigestLength = _ccSHANumberDigestLength; @synthesize secPaddingPKCS1SHANumber = _secPaddingPKCS1SHANumber; @synthesize name = _name; - (size_t)ccSHANumberDigestLength { return _ccSHANumberDigestLength; } - (uint32_t)secPaddingPKCS1SHANumber { return _secPaddingPKCS1SHANumber; } - (unsigned char *)CC_SHANumberWithData:(const void *)data withLength:(uint32_t)len withHashBytes:(unsigned char *)hashBytes { unsigned char *result = [super CC_SHANumberWithData:data withLength:len withHashBytes:hashBytes]; if (!result && self.ccShaNumberWithData) { result = self.ccShaNumberWithData(data, len, hashBytes); } return result; } @end @implementation JWTAlgorithmRSBase (Create) + (instancetype)algorithm256 { return [JWTAlgorithmRS256 new]; } + (instancetype)algorithm384 { return [JWTAlgorithmRS384 new]; } + (instancetype)algorithm512 { return [JWTAlgorithmRS512 new]; } + (instancetype)mutableAlgorithm { JWTAlgorithmRSFamilyMemberMutable *base = [JWTAlgorithmRSFamilyMemberMutable new]; base.ccSHANumberDigestLength = CC_SHA256_DIGEST_LENGTH; //set to something ok //base.secPaddingPKCS1SHANumber = kSecPaddingPKCS1SHA256; base.ccShaNumberWithData = ^unsigned char *(const void *data, CC_LONG len, unsigned char *hashBytes){ return CC_SHA256(data, len, hashBytes); }; base.name = @"RS256"; return base; } @end ================================================ FILE: Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoKey.m ================================================ // // JWTCryptoKey.m // JWT // // Created by Lobanov Dmitry on 04.02.17. // Copyright © 2017 JWTIO. All rights reserved. // #import "JWTCryptoKey.h" #import "JWTCryptoSecurity.h" #import "JWTCryptoSecurity+Extraction.h" #import "JWTCryptoSecurity+ExternalRepresentation.h" #import "JWTCryptoSecurity+ErrorHandling.h" #import "JWTBase64Coder.h" @interface JWTCryptoKeyBuilder() + (NSString *)keyTypeRSA; + (NSString *)keyTypeEC; @property (assign, nonatomic, readwrite) BOOL public; @property (assign, nonatomic, readwrite) NSString *keyType; @property (nonatomic, readonly) BOOL withKeyTypeRSA; @property (nonatomic, readonly) BOOL withKeyTypeEC; @end @implementation JWTCryptoKeyBuilder + (NSString *)keyTypeRSA { return @"RSA"; } + (NSString *)keyTypeEC { return @"EC"; } - (instancetype)keyTypeRSA { self.keyType = [self.class keyTypeRSA]; return self; } - (instancetype)keyTypeEC { self.keyType = [self.class keyTypeEC]; return self; } - (BOOL)withKeyTypeRSA { return [self.keyType isEqualToString:self.class.keyTypeRSA]; } - (BOOL)withKeyTypeEC { return [self.keyType isEqualToString:self.class.keyTypeEC]; } @end @interface JWTCryptoKey () @property (copy, nonatomic, readwrite) NSString *tag; @property (assign, nonatomic, readwrite) SecKeyRef key; @property (copy, nonatomic, readwrite) NSData *rawKey; @end @interface JWTCryptoKey (Class) + (NSString *)generateUniqueTag; @end @implementation JWTCryptoKey (Class) + (NSString *)generateUniqueTag { return [[NSUUID UUID].UUIDString stringByReplacingOccurrencesOfString:@"-" withString:@""].lowercaseString; } @end @implementation JWTCryptoKey (Parameters) + (NSString *)parametersKeyBuilder { return NSStringFromSelector(_cmd); } @end @interface JWTCryptoKey (ParametersExtraction) - (NSString *)extractedSecKeyTypeWithParameters:(NSDictionary *)parameters; - (JWTCryptoKeyBuilder *)extractedBuilderWithParameters:(NSDictionary *)parameters; @end // Consider that both methods in this category should return non-nullable values @implementation JWTCryptoKey (ParametersExtraction) // Parameters are nil at that moment, could be used later for some purposes - (JWTCryptoKeyBuilder *)extractedBuilderWithParameters:(NSDictionary *)parameters { return (JWTCryptoKeyBuilder *)parameters[[self.class parametersKeyBuilder]] ?: [JWTCryptoKeyBuilder new].keyTypeRSA; } // Parameters are nil at that moment, could be used later for some purposes - (NSString *)extractedSecKeyTypeWithParameters:(NSDictionary *)parameters { JWTCryptoKeyBuilder *builder = [self extractedBuilderWithParameters:parameters]; if (builder.withKeyTypeEC) { return JWTCryptoSecurityKeysTypes.EC; } return JWTCryptoSecurityKeysTypes.RSA; } @end @interface JWTCryptoKey (Generator) @end @implementation JWTCryptoKey (Generator) - (instancetype)initWithSecKeyRef:(SecKeyRef)key { if (key == NULL) { return nil; } if (self = [super init]) { self.key = key; } return self; } - (instancetype)initWithData:(NSData *)data parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error { // add check that everything is fine. return [super init]; } - (instancetype)initWithBase64String:(NSString *)base64String parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error { return [self initWithData:[JWTBase64Coder dataWithBase64UrlEncodedString:base64String] parameters:parameters error:error]; } - (instancetype)initWithPemEncoded:(NSString *)encoded parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error { //TODO: check correctness. //maybe use clean initWithBase64String and remove ?: encoded tail. NSString *clean = ((JWTCryptoSecurityComponent *)[[JWTCryptoSecurity componentsFromFileContent:encoded] componentsOfType:JWTCryptoSecurityComponents.Key].firstObject).content ?: encoded;//[JWTCryptoSecurity stringByRemovingPemHeadersFromString:encoded]; return [self initWithBase64String:clean parameters:parameters error:error]; } - (instancetype)initWithPemAtURL:(NSURL *)url parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error { // contents of url NSError *contentsExtractingError = nil; NSString *pemEncoded = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&contentsExtractingError]; if (error && contentsExtractingError) { *error = contentsExtractingError; return nil; } return [self initWithPemEncoded:pemEncoded parameters:parameters error:error]; } @end @implementation JWTCryptoKey (Check) - (void)cleanup { if (self.key != NULL) { CFRelease(self.key); } } - (instancetype)checkedWithError:(NSError *__autoreleasing*)error { BOOL checked = self.key != NULL; if (error && !checked) { *error = [NSError errorWithDomain:@"org.opensource.jwt.security.key" code:-200 userInfo:@{NSLocalizedDescriptionKey : @"Security key isn't retrieved! Something went wrong!"}]; } return self; } @end @implementation JWTCryptoKey (ExternalRepresentation) - (NSString *)externalRepresentationForCoder:(JWTBase64Coder *)coder error:(NSError *__autoreleasing *)error { NSData *data = [JWTCryptoSecurity externalRepresentationForKey:self.key error:error]; NSString *result = (NSString *)[coder ?: JWTBase64Coder.withBase64String stringWithData:data]; return result; } @end @implementation JWTCryptoKey - (void)dealloc { [self cleanup]; } @end @implementation JWTCryptoKeyPublic - (instancetype)initWithData:(NSData *)data parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error { if (self = [super initWithData:data parameters:parameters error:error]) { self.tag = [self.class generateUniqueTag]; if (!data) { return nil; } NSError *removingHeaderError = nil; // asks builder JWTCryptoKeyBuilder *builder = [self extractedBuilderWithParameters:parameters]; NSData *keyData = data; if (builder.withKeyTypeRSA) { keyData = [JWTCryptoSecurity dataByRemovingPublicKeyHeader:data error:&removingHeaderError]; if (!keyData || removingHeaderError) { if (error && removingHeaderError != nil) { *error = removingHeaderError; } return nil; } } if (builder.withKeyTypeEC) { NSError *theError = nil; // keyData = [JWTCryptoSecurity dataByExtractingKeyFromANS1:data error:&theError]; if (!keyData || theError) { if (error && theError != nil) { *error = theError; } return nil; } // unknown here. // process keyData before passing it to JWTCryptoSecurity+addKey... method. // keyData = [JWTCryptoSecurity dataByRemovingPublicKeyHeader:data error:&removingHeaderError]; // if (!keyData || removingHeaderError) { // if (error && removingHeaderError != nil) { // *error = removingHeaderError; // } // return nil; // } // NSData *theData = [data copy]; // while (theData != nil && theData.length > 0) { // NSError *theError = nil; // self.key = [JWTCryptoSecurity addKeyWithData:theData asPublic:YES tag:self.tag type:[self extractedSecKeyTypeWithParameters:parameters] error:&theError]; // NSLog(@"theData: %@", theData); // NSLog(@"theError: %@", theError); // if (!theError && self.key) { // NSLog(@"Found!"); // NSLog(@"theData: %@", theData); // NSLog(@"theKey: %@", self.key); // break; // } // NSUInteger length = theData.length - 1; // NSRange range = NSMakeRange(1, length); // theData = [NSData dataWithBytes:((char *)theData.bytes) + range.location length:range.length]; // } } NSError *addKeyError = nil; self.key = [JWTCryptoSecurity addKeyWithData:keyData asPublic:YES tag:self.tag type:[self extractedSecKeyTypeWithParameters:parameters] error:&addKeyError]; if (!self.key || addKeyError) { if (error && addKeyError != nil) { *error = addKeyError; } [self cleanup]; return nil; } } return self; } - (instancetype)initWithCertificateData:(NSData *)certificateData parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error { SecKeyRef key = [JWTCryptoSecurity publicKeyFromCertificate:certificateData]; if (!key) { // error: Public certificate incorrect. return nil; } if (self = [super init]) { self.key = key; } return self; } - (instancetype)initWithCertificateBase64String:(NSString *)certificate parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error { // cleanup certificate if needed. // call initWithCertificateData:(NSData *)certificateData NSData *certificateData = [JWTBase64Coder dataWithBase64UrlEncodedString:certificate]; return [self initWithCertificateData:certificateData parameters:parameters error:error]; } @end @implementation JWTCryptoKeyPrivate - (instancetype)initWithData:(NSData *)data parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error { if (self = [super initWithData:data parameters:parameters error:error]) { self.tag = [self.class generateUniqueTag]; NSError *addKeyError = nil; if (!data) { // error: no data? // or put it in superclass? return nil; } NSData *theData = [data copy]; JWTCryptoKeyBuilder *builder = [self extractedBuilderWithParameters:parameters]; if (builder.withKeyTypeEC) { // cheat and shit! // ahaha. try to find correct key here. // possible soultion - dataByExtracting in cryptoKeySecurity. while (/* DISABLES CODE */ (0) && theData != nil && theData.length > 0) { NSError *theError = nil; self.key = [JWTCryptoSecurity addKeyWithData:theData asPublic:NO tag:self.tag type:[self extractedSecKeyTypeWithParameters:parameters] error:&theError]; NSLog(@"theData: %@", theData); NSLog(@"theError: %@", theError); if (!theError && self.key) { NSLog(@"Found!"); NSLog(@"theData: %@", theData); NSLog(@"theKey: %@", self.key); break; } NSUInteger length = theData.length - 1; NSRange range = NSMakeRange(1, length); theData = [NSData dataWithBytes:((char *)theData.bytes) + range.location length:range.length]; } } self.key = [JWTCryptoSecurity addKeyWithData:theData asPublic:NO tag:self.tag type:[self extractedSecKeyTypeWithParameters:parameters] error:&addKeyError]; if (!self.key || addKeyError) { if (error && addKeyError) { *error = addKeyError; } [self cleanup]; return nil; } } return self; } // Exists - (instancetype)initWithP12AtURL:(NSURL *)url withPassphrase:(NSString *)passphrase parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error { // take data. // cleanup if needed. NSData *data = [NSData dataWithContentsOfURL:url]; return [self initWithP12Data:data withPassphrase:passphrase parameters:parameters error:error]; } - (instancetype)initWithP12Data:(NSData *)p12Data withPassphrase:(NSString *)passphrase parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error { if (p12Data == nil) { return nil; } // cleanup if needed. SecIdentityRef identity = nil; SecTrustRef trust = nil; { CFErrorRef extractError = NULL; [JWTCryptoSecurity extractIdentityAndTrustFromPKCS12:(__bridge CFDataRef)p12Data password:(__bridge CFStringRef)passphrase identity:&identity trust:&trust error:&extractError]; if (extractError != nil) { if (error) { *error = (NSError *)CFBridgingRelease(extractError); return nil; } } } BOOL identityAndTrust = identity && trust; // we don't need trust anymore. if (trust) { CFRelease(trust); } SecKeyRef privateKey = NULL; if (identityAndTrust) { OSStatus status = SecIdentityCopyPrivateKey(identity, &privateKey); NSError *theError = [JWTCryptoSecurity securityErrorWithOSStatus:status]; if (theError) { if (error) { *error = theError; } } } if (identity) { CFRelease(identity); } if (privateKey != NULL) { if (self = [super init]) { self.key = privateKey; } } return self; } @end ================================================ FILE: Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoKeyExtractor+FluentStyle.m ================================================ // // JWTCryptoKeyExtractor+FluentStyle.m // JWT // // Created by Dmitry Lobanov on 07/06/2019. // Copyright © 2019 JWTIO. All rights reserved. // #import "JWTCryptoKeyExtractor+FluentStyle.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wobjc-property-implementation" @implementation JWTCryptoKeyExtractor (FluentStyle) @end #pragma clang diagnostic pop ================================================ FILE: Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoKeyExtractor.m ================================================ // // JWTCryptoKeyExtractor.m // JWT // // Created by Lobanov Dmitry on 04.02.17. // Copyright © 2017 JWTIO. All rights reserved. // #import "JWTCryptoKeyExtractor.h" #import "JWTCryptoKey.h" #import "JWTBase64Coder.h" @interface JWTCryptoKeyExtractor () @property (strong, nonatomic, readwrite) JWTCryptoKeyBuilder *internalKeyBuilder; @property (copy, nonatomic, readwrite) JWTCryptoKeyExtractor * (^keyBuilder)(JWTCryptoKeyBuilder *keyBuilder); @end @interface JWTCryptoKeyExtractor (Parameters) - (NSDictionary *)enhancedParameters:(NSDictionary *)parameters; @end @implementation JWTCryptoKeyExtractor (Parameters) - (NSDictionary *)enhancedParameters:(NSDictionary *)parameters { if (self.internalKeyBuilder != nil) { NSMutableDictionary *theParameters = [NSMutableDictionary dictionaryWithDictionary:parameters ?: @{}]; [theParameters setObject:self.internalKeyBuilder forKeyedSubscript:JWTCryptoKey.parametersKeyBuilder]; } return parameters; } @end @implementation JWTCryptoKeyExtractor - (NSString *)type { return self.class.type; } + (NSString *)type { return NSStringFromClass(self); } + (NSString *)parametersKeyCertificatePassphrase { return NSStringFromSelector(_cmd); } - (instancetype)init { if (self = [super init]) { [self setupFluent]; } return self; } #pragma mark - Fluent - (void)setupFluent { __weak typeof(self) weakSelf = self; self.keyBuilder = ^(JWTCryptoKeyBuilder *keyBuilder) { return [weakSelf configuredByKeyBuilder:keyBuilder]; }; } #pragma mark - - (id)keyFromData:(NSData *)data parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing *)error { //#pragma message "Not Implemented" if (error) { *error = [NSError errorWithDomain:@"io.jwt.crypto.rsa" code:-100 userInfo:@{ NSLocalizedDescriptionKey : @"Method not implemented" }]; } return nil; } - (id)keyFromString:(NSString *)string parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing *)error { if (error) { *error = [NSError errorWithDomain:@"io.jwt.crypto.rsa" code:-100 userInfo:@{ NSLocalizedDescriptionKey : @"Method not implemented" }]; } return nil; } @end @implementation JWTCryptoKeyExtractor (Setters) - (instancetype)configuredByKeyBuilder:(JWTCryptoKeyBuilder *)keyBuilder { self.internalKeyBuilder = keyBuilder; return self; } @end @interface JWTCryptoKeyExtractor_Public_Pem_Certificate : JWTCryptoKeyExtractor @end @implementation JWTCryptoKeyExtractor_Public_Pem_Certificate - (id)keyFromData:(NSData *)data parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing *)error { NSDictionary *theParameters = [self enhancedParameters:parameters]; return [[JWTCryptoKeyPublic alloc] initWithCertificateData:data parameters:theParameters error:error]; } @end @interface JWTCryptoKeyExtractor_Private_P12 : JWTCryptoKeyExtractor @end @implementation JWTCryptoKeyExtractor_Private_P12 - (id)keyFromData:(NSData *)data parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing *)error { NSString *certificatePassphrase = parameters[self.class.parametersKeyCertificatePassphrase]; if ([certificatePassphrase isEqual:[NSNull null]]) { certificatePassphrase = nil; } NSDictionary *theParameters = [self enhancedParameters:parameters]; return [[JWTCryptoKeyPrivate alloc] initWithP12Data:data withPassphrase:certificatePassphrase parameters:theParameters error:error]; } @end @interface JWTCryptoKeyExtractor_Public_Pem_Key : JWTCryptoKeyExtractor @end @implementation JWTCryptoKeyExtractor_Public_Pem_Key - (id)keyFromData:(NSData *)data parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing *)error { return [self keyFromString:[JWTBase64Coder base64UrlEncodedStringWithData:data] parameters:parameters error:error]; } - (id)keyFromString:(NSString *)string parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing *)error { NSDictionary *theParameters = [self enhancedParameters:parameters]; return [[JWTCryptoKeyPublic alloc] initWithPemEncoded:string parameters:theParameters error:error]; } @end @interface JWTCryptoKeyExtractor_Private_Pem_Key : JWTCryptoKeyExtractor @end @implementation JWTCryptoKeyExtractor_Private_Pem_Key - (id)keyFromData:(NSData *)data parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing *)error { return [self keyFromString:[JWTBase64Coder base64UrlEncodedStringWithData:data] parameters:parameters error:error]; } - (id)keyFromString:(NSString *)string parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing *)error { NSDictionary *theParameters = [self enhancedParameters:parameters]; return [[JWTCryptoKeyPrivate alloc] initWithPemEncoded:string parameters:theParameters error:error]; } @end @implementation JWTCryptoKeyExtractor (ClassCluster) + (instancetype)publicKeyWithCertificate { return [JWTCryptoKeyExtractor_Public_Pem_Certificate new]; } + (instancetype)privateKeyInP12 { return [JWTCryptoKeyExtractor_Private_P12 new]; } + (instancetype)publicKeyWithPEMBase64 { return [JWTCryptoKeyExtractor_Public_Pem_Key new]; } + (instancetype)privateKeyWithPEMBase64 { return [JWTCryptoKeyExtractor_Private_Pem_Key new]; } + (NSArray *)availableExtractors { return @[ [self publicKeyWithCertificate], [self privateKeyInP12], [self publicKeyWithPEMBase64], [self privateKeyWithPEMBase64] ]; } + (NSDictionary *)typesAndExtractors { static NSDictionary *dictionary = nil; return dictionary ?: (dictionary = [[NSDictionary alloc] initWithObjects:[self availableExtractors] forKeys:[[self availableExtractors] valueForKey:@"type"]]); } + (instancetype)createWithType:(NSString *)type { return [self typesAndExtractors][type]; } @end ================================================ FILE: Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity+ErrorHandling.m ================================================ // // JWTCryptoSecurity+ErrorHandling.m // JWT // // Created by Dmitry Lobanov on 08.08.2018. // Copyright © 2018 JWTIO. All rights reserved. // #import "JWTCryptoSecurity+ErrorHandling.h" #import "JWTDeprecations.h" @implementation JWTCryptoSecurity (ErrorHandling) + (NSError *)securityErrorWithOSStatus:(OSStatus)status { if (status == errSecSuccess) { return nil; } // if @available(macOS 10.3, iOS 11.3, tvOS 11.3, watchOS 4.3, *) // appropriate for Xcode 9 and higher. // rewrite it later? #if JWT_COMPILE_TIME_AVAILABILITY(JWT_macOS(1030), JWT_iOS(110300), JWT_tvOS(110300), JWT_watchOS(40300)) NSString *message = (NSString *)CFBridgingRelease(SecCopyErrorMessageString(status, NULL)) ?: @"Unknown error message"; return [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:@{NSLocalizedDescriptionKey : message}]; #else return [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil]; #endif } @end ================================================ FILE: Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity+ExternalRepresentation.m ================================================ // // JWTCryptoSecurity+ExternalRepresentation.m // JWT // // Created by Dmitry Lobanov on 08.08.2018. // Copyright © 2018 JWTIO. All rights reserved. // #import "JWTCryptoSecurity+ExternalRepresentation.h" @implementation JWTCryptoSecurity (ExternalRepresentation) + (NSData *)externalRepresentationForKey:(SecKeyRef)key error:(NSError *__autoreleasing *)error { if (key == NULL) { return nil; } if (@available(macOS 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *)) { CFErrorRef copyError = NULL; NSData *result = (NSData *)CFBridgingRelease(SecKeyCopyExternalRepresentation(key, ©Error)); if (error && copyError != NULL) { *error = CFBridgingRelease(copyError); return nil; } return result; } else { return nil; } } @end ================================================ FILE: Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity+Extraction.m ================================================ // // JWTCryptoSecurity+Extraction.m // JWT // // Created by Dmitry on 7/31/18. // Copyright © 2018 JWTIO. All rights reserved. // #import "JWTCryptoSecurity+Extraction.h" @implementation JWTCryptoSecurityComponent - (instancetype)initWithContent:(NSString *)content type:(NSString *)type { if (type == nil || content == nil) { return nil; } if (self = [super init]) { self.content = content; self.type = type; } return self; } @end @interface JWTCryptoSecurityComponents () @property (copy, nonatomic, readwrite) NSArray *components; @end @implementation JWTCryptoSecurityComponents + (NSString *)Certificate { return NSStringFromSelector(_cmd).uppercaseString; } + (NSString *)PrivateKey { return @"Private".uppercaseString; } + (NSString *)PublicKey { return @"Public".uppercaseString; } + (NSString *)Key { return NSStringFromSelector(_cmd).uppercaseString; } + (NSArray *)components:(NSArray *)components ofType:(NSString *)type { return [components filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"type contains %@", type]]; } - (instancetype)initWithComponents:(NSArray *)components { if (self = [self init]) { self.components = components; } return self; } - (NSArray *)componentsOfType:(NSString *)type { return [self.class components:self.components ofType:type]; } @end @interface JWTCryptoSecurityComponents (Extraction) + (NSString *)determineTypeByPemHeaderType:(NSString *)headerType; + (NSRegularExpression *)pemEntryRegularExpression; + (JWTCryptoSecurityComponent *)componentFromTextResult:(NSTextCheckingResult *)textResult inContent:(NSString *)content; + (instancetype)parsedComponentsInContent:(NSString *)content; @end @implementation JWTCryptoSecurityComponents (Extraction) + (NSString *)determineTypeByPemHeaderType:(NSString *)headerType { __auto_type validateBlock = ^(NSString *headerType, NSString *string) { return [headerType rangeOfString:string options:NSCaseInsensitiveSearch].location != NSNotFound; }; if (validateBlock(headerType, @"CERTIFICATE")) { return self.Certificate; } if (validateBlock(headerType, @"PUBLIC")) { return self.PublicKey; } if (validateBlock(headerType, @"PRIVATE")) { return self.PrivateKey; } if (validateBlock(headerType, @"KEY")) { return self.Key; } return nil; } + (NSRegularExpression *)pemEntryRegularExpression { __auto_type expression = [[NSRegularExpression alloc] initWithPattern:@"-----BEGIN(?[\\w\\s]+)-----(?.+?)-----END(?[\\w\\s]+)-----" options:NSRegularExpressionDotMatchesLineSeparators error:nil]; return expression; } + (JWTCryptoSecurityComponent *)componentFromTextResult:(NSTextCheckingResult *)textResult inContent:(NSString *)content { if (textResult.numberOfRanges > 2) { __auto_type beginRange = [textResult rangeAtIndex:1]; __auto_type contentRange = [textResult rangeAtIndex:2]; // cleanup string. __auto_type beginString = [content substringWithRange:beginRange]; __auto_type contentString = [content substringWithRange:contentRange]; __auto_type resultType = [beginString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];//[self determineTypeByPemHeaderType:beginString]; // we need full string to parse attributes "Private/Public" "EC/RSA" "KEY/CERTIFICATE" etc. __auto_type resultContent = [contentString stringByReplacingOccurrencesOfString:@"\n" withString:@""]; return [[JWTCryptoSecurityComponent alloc] initWithContent:resultContent type:resultType]; } else { return nil; } } + (instancetype)parsedComponentsInContent:(NSString *)content { __auto_type expression = [self pemEntryRegularExpression]; __auto_type results = [expression matchesInString:content options:0 range:NSMakeRange(0, content.length)]; __auto_type components = (NSArray *)@[]; for (NSTextCheckingResult *result in results) { id object = [self componentFromTextResult:result inContent:content]; components = [components arrayByAddingObject:object]; } return [[self alloc] initWithComponents:components]; } @end @implementation JWTCryptoSecurity (Extraction) + (JWTCryptoSecurityComponents *)componentsFromFile:(NSURL *)url { NSError *error = nil; __auto_type content = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error]; return [self componentsFromFileContent:content]; } + (JWTCryptoSecurityComponents *)componentsFromFileContent:(NSString *)content { return [JWTCryptoSecurityComponents parsedComponentsInContent:content]; } @end ================================================ FILE: Sources/JWT/Algorithms/RSFamily/RSKeys/JWTCryptoSecurity.m ================================================ // // JWTCryptoSecurity.m // JWT // // Created by Lobanov Dmitry on 04.02.17. // Copyright © 2017 JWTIO. All rights reserved. // #import "JWTCryptoSecurity.h" #import "JWTCryptoSecurity+ErrorHandling.h" #import "JWTErrorDescription.h" #import "JWTDeprecations.h" @interface JWTMemoryLayout : NSObject + (NSString *)typeUInt8; + (NSString *)typeCUnsignedChar; - (instancetype)initWithType:(NSString *)type; + (instancetype)createWithType:(NSString *)type; @property (copy, nonatomic, readwrite) NSString *type; @property (assign, nonatomic, readonly) NSInteger size; @end @implementation JWTMemoryLayout + (NSString *)typeUInt8 { return NSStringFromSelector(_cmd); } + (NSString *)typeCUnsignedChar { return [self typeUInt8]; } - (instancetype)initWithType:(NSString *)type { self = [super init]; if (self) { self.type = type; } return self; } + (instancetype)createWithType:(NSString *)type { return [[self alloc] initWithType:type]; } + (NSDictionary *)sizesAndTypes { static NSDictionary *sizesAndTypes = nil; return sizesAndTypes ?: (sizesAndTypes = @{ [self typeUInt8] : @(1) // or 8? }); } - (NSInteger)size { return [[self.class sizesAndTypes][self.type] integerValue]; } @end @implementation JWTCryptoSecurityKeysTypes + (NSString *)RSA { return (__bridge NSString *)kSecAttrKeyTypeRSA; } + (NSString *)EC { // extern const CFStringRef kSecAttrKeyTypeEC // __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_4_0); // extern const CFStringRef kSecAttrKeyTypeECSECPrimeRandom // __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0); return (__bridge NSString *)kSecAttrKeyTypeEC; } @end @interface JWTCryptoSecurity () + (NSDictionary *)dictionaryByCombiningDictionaries:(NSArray *)dictionaries; @end @implementation JWTCryptoSecurity (KeysManipulation) + (SecKeyRef)addKeyWithData:(NSData *)data asPublic:(BOOL)thePublic tag:(NSString *)tag type:(NSString *)type error:(NSError *__autoreleasing*)error; { NSString *keyClass = (__bridge NSString *)(thePublic ? kSecAttrKeyClassPublic : kSecAttrKeyClassPrivate); NSInteger sizeInBits = data.length * [JWTMemoryLayout createWithType:[JWTMemoryLayout typeUInt8]].size; NSDictionary *attributes = @{ (__bridge NSString*)kSecAttrKeyType : type, (__bridge NSString*)kSecAttrKeyClass : keyClass, (__bridge NSString*)kSecAttrKeySizeInBits : @(sizeInBits) }; if (@available(macOS 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *)) { CFErrorRef createError = NULL; SecKeyRef key = SecKeyCreateWithData((__bridge CFDataRef)data, (__bridge CFDictionaryRef)attributes, &createError); if (error && createError != NULL) { *error = (__bridge NSError*)createError; } return key; } // oh... not avaialbe API :/ else { CFTypeRef result = NULL; NSData *tagData = [tag dataUsingEncoding:NSUTF8StringEncoding]; NSDictionary *commonAttributes = @{ (__bridge NSString*)kSecClass: (__bridge NSString*)kSecClassKey, (__bridge NSString*)kSecAttrApplicationTag: tagData, (__bridge NSString*)kSecAttrAccessible: (__bridge NSString*)kSecAttrAccessibleWhenUnlocked }; NSDictionary *addItemAttributes = @{ (__bridge NSString*)kSecValueData: data, (__bridge NSString*)kSecReturnPersistentRef: @(YES), }; OSStatus addItemStatus = SecItemAdd((__bridge CFDictionaryRef)[self dictionaryByCombiningDictionaries:@[attributes, commonAttributes, addItemAttributes]], &result); if (addItemStatus != errSecSuccess && addItemStatus != errSecDuplicateItem) { // add item error // not duplicate and not added to keychain. return NULL; } NSDictionary *copyAttributes = @{ (__bridge NSString*)kSecReturnRef: @(YES), }; CFTypeRef key = NULL; // TODO: Add error handling later. OSStatus copyItemStatus = SecItemCopyMatching((__bridge CFDictionaryRef)[self dictionaryByCombiningDictionaries:@[attributes, commonAttributes, copyAttributes]], &key); if (key == NULL) { // copy item error if (error) { *error = [JWTCryptoSecurity securityErrorWithOSStatus:copyItemStatus]; } } return (SecKeyRef)key; } return NULL; } + (SecKeyRef)addKeyWithData:(NSData *)data asPublic:(BOOL)public tag:(NSString *)tag error:(NSError *__autoreleasing*)error; { return [self addKeyWithData:data asPublic:public tag:tag type:JWTCryptoSecurityKeysTypes.RSA error:error]; } + (SecKeyRef)keyByTag:(NSString *)tag error:(NSError *__autoreleasing*)error; { return NULL; } + (BOOL)removeKeyByTag:(NSString *)tag error:(NSError *__autoreleasing*)error; { NSData *tagData = [tag dataUsingEncoding:NSUTF8StringEncoding]; if (tagData == nil) { // tell that nothing to remove. if (error) { *error = [JWTErrorDescription errorWithCode:JWTUnexpectedError]; } return NO; } NSDictionary *removeAttributes = @{ (__bridge NSString*)kSecClass: (__bridge NSString*)kSecClassKey, (__bridge NSString*)kSecAttrKeyType: (__bridge NSString*)kSecAttrKeyTypeRSA, (__bridge NSString*)kSecAttrApplicationTag: tagData }; OSStatus status = SecItemDelete((__bridge CFDictionaryRef)removeAttributes); if (status != errSecSuccess) { if (error) { *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil]; } } return status != errSecSuccess; } @end @implementation JWTCryptoSecurity + (NSDictionary *)dictionaryByCombiningDictionaries:(NSArray *)dictionaries { NSMutableDictionary *result = [@{} mutableCopy]; for (NSDictionary *dictionary in dictionaries) { [result addEntriesFromDictionary:dictionary]; } return [result copy]; } + (NSString *)keyTypeRSA { return JWTCryptoSecurityKeysTypes.RSA; } + (NSString *)keyTypeEC { return JWTCryptoSecurityKeysTypes.EC; } @end @implementation JWTCryptoSecurity (Certificates) + (OSStatus)extractIdentityAndTrustFromPKCS12:(CFDataRef)inPKCS12Data password:(CFStringRef)password identity:(SecIdentityRef *)outIdentity trust:(SecTrustRef *)outTrust { return [self extractIdentityAndTrustFromPKCS12:inPKCS12Data password:password identity:outIdentity trust:outTrust error:NULL]; } + (OSStatus)extractIdentityAndTrustFromPKCS12:(CFDataRef)inPKCS12Data password:(CFStringRef)password identity:(SecIdentityRef *)outIdentity trust:(SecTrustRef *)outTrust error:(CFErrorRef *)error { OSStatus securityError = errSecSuccess; const void *keys[] = { kSecImportExportPassphrase }; const void *values[] = { password }; CFDictionaryRef optionsDictionary = NULL; /* Create a dictionary containing the passphrase if one was specified. Otherwise, create an empty dictionary. */ optionsDictionary = CFDictionaryCreate( NULL, keys, values, (password ? 1 : 0), NULL, NULL); // 1 CFArrayRef items = NULL; securityError = SecPKCS12Import(inPKCS12Data, optionsDictionary, &items); // 2 /** @discussion If a pkcs12 that was created with only one private key in it and no certificate was tried used, this just crashed when accessing index 0 with the CFArrayGetValueAtIndex. */ if (items != nil && CFArrayGetCount(items) == 0) { securityError = errSecPkcs12VerifyFailure; } // if (securityError == 0) { // 3 CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0); const void *tempIdentity = NULL; tempIdentity = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemIdentity); CFRetain(tempIdentity); *outIdentity = (SecIdentityRef)tempIdentity; const void *tempTrust = NULL; tempTrust = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust); CFRetain(tempTrust); *outTrust = (SecTrustRef)tempTrust; } else { if (error) { NSError *resultError = [JWTCryptoSecurity securityErrorWithOSStatus:securityError]; CFErrorRef theError = (CFErrorRef)CFBridgingRetain(resultError); *error = theError; } } if (optionsDictionary) { CFRelease(optionsDictionary); } if (items) { CFRelease(items); } return securityError; } + (SecKeyRef)trustCopyKey:(SecTrustRef)trust { // API_DEPRECATED_WITH_REPLACEMENT("SecTrustCopyKey", macos(10.7, 11.0), ios(2.0, 14.0), watchos(1.0, 7.0), tvos(9.0, 14.0)); #if JWT_COMPILE_TIME_AVAILABILITY(JWT_macOS(110000), JWT_iOS(140000), JWT_tvOS(140000), JWT_watchOS(70000)) return SecTrustCopyKey(trust); #else return SecTrustCopyPublicKey(trust); #endif } + (SecKeyRef)publicKeyFromCertificate:(NSData *)certificateData { SecCertificateRef certificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData); if (certificate != NULL) { SecPolicyRef secPolicy = SecPolicyCreateBasicX509(); SecTrustRef trust; SecTrustCreateWithCertificates(certificate, secPolicy, &trust); // if (@available(macOS 10.14, iOS 12.0, tvOS 12.0, watchOS 5.0, *)) { #if JWT_COMPILE_TIME_AVAILABILITY(JWT_macOS(101400), JWT_iOS(120000), JWT_tvOS(120000), JWT_watchOS(50000)) CFErrorRef errorRef = NULL; BOOL result = SecTrustEvaluateWithError(trust, &errorRef); if (result == NO) { NSError *error = (__bridge NSError *)errorRef; NSLog(@"%s Error occured while retrieving public key from : %@", __PRETTY_FUNCTION__, error); if (errorRef != NULL) { CFRelease(errorRef); } } #else SecTrustResultType resultType; SecTrustEvaluate(trust, &resultType); #endif SecKeyRef publicKey = [self trustCopyKey:trust]; (CFRelease(trust)); (CFRelease(secPolicy)); (CFRelease(certificate)); return publicKey; } return NULL; } @end @implementation JWTCryptoSecurity (PublicKey) /** This method strips the x509 from a provided ASN.1 DER public key. If the key doesn't contain a header, the DER data is returned as is. Supported formats are: Headerless: SEQUENCE INTEGER (1024 or 2048 bit) -- modulo INTEGER -- public exponent With x509 header: SEQUENCE SEQUENCE OBJECT IDENTIFIER 1.2.840.113549.1.1.1 NULL BIT STRING SEQUENCE INTEGER (1024 or 2048 bit) -- modulo INTEGER -- public exponent Example of headerless key: https://lapo.it/asn1js/#3082010A0282010100C1A0DFA367FBC2A5FD6ED5A071E02A4B0617E19C6B5AD11BB61192E78D212F10A7620084A3CED660894134D4E475BAD7786FA1D40878683FD1B7A1AD9C0542B7A666457A270159DAC40CE25B2EAE7CCD807D31AE725CA394F90FBB5C5BA500545B99C545A9FE08EFF00A5F23457633E1DB84ED5E908EF748A90F8DFCCAFF319CB0334705EA012AF15AA090D17A9330159C9AFC9275C610BB9B7C61317876DC7386C723885C100F774C19830F475AD1E9A9925F9CA9A69CE0181A214DF2EB75FD13E6A546B8C8ED699E33A8521242B7E42711066AEC22D25DD45D56F94D3170D6F2C25164D2DACED31C73963BA885ADCB706F40866B8266433ED5161DC50E4B3B0203010001 Example of key with X509 header (notice the additional ASN.1 sequence): https://lapo.it/asn1js/#30819F300D06092A864886F70D010101050003818D0030818902818100D0674615A252ED3D75D2A3073A0A8A445F3188FD3BEB8BA8584F7299E391BDEC3427F287327414174997D147DD8CA62647427D73C9DA5504E0A3EED5274A1D50A1237D688486FADB8B82061675ABFA5E55B624095DB8790C6DBCAE83D6A8588C9A6635D7CF257ED1EDE18F04217D37908FD0CBB86B2C58D5F762E6207FF7B92D0203010001 */ //static func stripPublicKeyHeader(keyData: Data) throws -> Data { // let count = keyData.count / MemoryLayout.size // // guard count > 0 else { // throw SwiftyRSAError(message: "Provided public key is empty") // } // // var byteArray = [UInt8](repeating: 0, count: count) // (keyData as NSData).getBytes(&byteArray, length: keyData.count) // // var index = 0 // guard byteArray[index] == 0x30 else { // throw SwiftyRSAError(message: "Provided key doesn't have a valid ASN.1 structure (first byte should be 0x30 == SEQUENCE)") // } // // index += 1 // if byteArray[index] > 0x80 { // index += Int(byteArray[index]) - 0x80 + 1 // } else { // index += 1 // } // // // If current byte marks an integer (0x02), it means the key doesn't have a X509 header and just // // contains its modulo & public exponent. In this case, we can just return the provided DER data as is. // if Int(byteArray[index]) == 0x02 { // return keyData // } // // // Now that we've excluded the possibility of headerless key, we're looking for a valid X509 header sequence. // // It should look like this: // // 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00 // guard Int(byteArray[index]) == 0x30 else { // throw SwiftyRSAError(message: "Provided key doesn't have a valid X509 header") // } // // index += 15 // if byteArray[index] != 0x03 { // throw SwiftyRSAError(message: "Invalid byte at index \(index - 1) (\(byteArray[index - 1])) for public key header") // } // // index += 1 // if byteArray[index] > 0x80 { // index += Int(byteArray[index]) - 0x80 + 1 // } else { // index += 1 // } // // guard byteArray[index] == 0 else { // throw SwiftyRSAError(message: "Invalid byte at index \(index - 1) (\(byteArray[index - 1])) for public key header") // } // // index += 1 // // let strippedKeyBytes = [UInt8](byteArray[index...keyData.count - 1]) // let data = Data(bytes: UnsafePointer(strippedKeyBytes), count: keyData.count - index) // // return data //} typedef NS_ENUM(NSInteger, JWTPublicHeaderStrippingError) { JWTPublicHeaderStrippingError_KeyIsEmpty = -200, JWTPublicHeaderStrippingError_Invalid_ASN1_Structure, JWTPublicHeaderStrippingError_Invalid_X509_Header, JWTPublicHeaderStrippingError_Invalid_Byte_At_Index, }; + (NSDictionary *)publicHeaderStrippingMessagesAndCodes { static NSDictionary *publicHeaderStrippingMessagesAndCodes = nil; return publicHeaderStrippingMessagesAndCodes ?: (publicHeaderStrippingMessagesAndCodes = @{ @(JWTPublicHeaderStrippingError_KeyIsEmpty) : @"Provided public key is empty", @(JWTPublicHeaderStrippingError_Invalid_ASN1_Structure) : @"Provided key doesn't have a valid ASN.1 structure (first byte should be 0x30 == SEQUENCE)", @(JWTPublicHeaderStrippingError_Invalid_X509_Header) : @"Provided key doesn't have a valid X509 header", @(JWTPublicHeaderStrippingError_Invalid_Byte_At_Index) : @"Invalid byte at index (index - 1) ((bytes[index - 1])) for public key header. Access as error.userInfo[Parameters][index] or error.userInfo[Parameters][byte]" }); } + (NSString *)stringForPublicHeaderStrippingErrorCode:(NSInteger)code { return [self publicHeaderStrippingMessagesAndCodes][@(code)] ?: @"Unknown Public Header Stripping Error"; } + (NSError*)publicHeaderStrippingErrorForCode:(NSInteger)code parameters:(NSDictionary *)parameters { return [NSError errorWithDomain:@"io.jwt.crypto.stripping_public_header" code:code userInfo:@{ @"Parameters" : parameters ?: [NSNull null],NSLocalizedDescriptionKey: [self stringForPublicHeaderStrippingErrorCode:code] }]; } + (NSError*)publicHeaderStrippingErrorForCode:(NSInteger)code { return [self publicHeaderStrippingErrorForCode:code parameters:nil]; } + (NSData *)dataByRemovingPublicKeyHeader:(NSData *)data error:(NSError *__autoreleasing *)error { NSError *currentError = nil; NSData *currentData = [data copy]; // let count = keyData.count / MemoryLayout.size // // guard count > 0 else { // throw SwiftyRSAError(message: "Provided public key is empty") // } NSInteger countOfBytes = currentData.length / [JWTMemoryLayout createWithType:[JWTMemoryLayout typeUInt8]].size; if (countOfBytes == 0) { // throw SwiftyRSAError(message: "Provided public key is empty") currentError = [self publicHeaderStrippingErrorForCode:JWTPublicHeaderStrippingError_KeyIsEmpty]; if (error) { *error = currentError; } return nil; } // var byteArray = [UInt8](repeating: 0, count: count) // (keyData as NSData).getBytes(&byteArray, length: keyData.count) // UInt8 *bytes = (UInt8*)malloc(countOfBytes); UInt8 *bytes = (UInt8 *)[currentData bytes]; // memcpy(bytes, [currentData bytes], countOfBytes); // var index = 0 // guard byteArray[index] == 0x30 else { // throw SwiftyRSAError(message: "Provided key doesn't have a valid ASN.1 structure (first byte should be 0x30 == SEQUENCE)") // } UInt8 index = 0; if (bytes[index] != 0x30) { // throw SwiftyRSAError(message: "Provided key doesn't have a valid ASN.1 structure (first byte should be 0x30 == SEQUENCE)") currentError = [self publicHeaderStrippingErrorForCode:JWTPublicHeaderStrippingError_Invalid_ASN1_Structure]; if (error) { *error = currentError; } return nil; } // index += 1 // if byteArray[index] > 0x80 { // index += Int(byteArray[index]) - 0x80 + 1 // } else { // index += 1 // } index += 1; if (bytes[index] > 0x80) { index += (SInt8)bytes[index] - 0x80 + 1; } else { index += 1; } // Headerless! // // If current byte marks an integer (0x02), it means the key doesn't have a X509 header and just // // contains its modulo & public exponent. In this case, we can just return the provided DER data as is. // if Int(byteArray[index]) == 0x02 { // return keyData // } if ((SInt8)bytes[index] == 0x02) { return currentData; } // Has header. // // Now that we've excluded the possibility of headerless key, we're looking for a valid X509 header sequence. // // It should look like this: // // 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00 // guard Int(byteArray[index]) == 0x30 else { // throw SwiftyRSAError(message: "Provided key doesn't have a valid X509 header") // } if ((SInt8)bytes[index] != 0x30) { // throw SwiftyRSAError(message: "Provided key doesn't have a valid X509 header") currentError = [self publicHeaderStrippingErrorForCode:JWTPublicHeaderStrippingError_Invalid_X509_Header]; if (error) { *error = currentError; } return nil; } // index += 15 // if byteArray[index] != 0x03 { // throw SwiftyRSAError(message: "Invalid byte at index \(index - 1) (\(byteArray[index - 1])) for public key header") // } index += 15; if (bytes[index] != 0x03) { // throw SwiftyRSAError(message: "Invalid byte at index \(index - 1) (\(byteArray[index - 1])) for public key header") currentError = [self publicHeaderStrippingErrorForCode:JWTPublicHeaderStrippingError_Invalid_Byte_At_Index parameters:@{@"index" : @(index - 1), @"byte": @(bytes[index - 1] ?: 0)}]; if (error) { *error = currentError; } return nil; } // index += 1 // if byteArray[index] > 0x80 { // index += Int(byteArray[index]) - 0x80 + 1 // } else { // index += 1 // } index += 1; if (bytes[index] > 0x80) { index += (SInt8)bytes[index] - 0x80 + 1; } else { index += 1; } // guard byteArray[index] == 0 else { // throw SwiftyRSAError(message: "Invalid byte at index \(index - 1) (\(byteArray[index - 1])) for public key header") // } if (bytes[index] != 0) { // throw SwiftyRSAError(message: "Invalid byte at index \(index - 1) (\(byteArray[index - 1])) for public key header") currentError = [self publicHeaderStrippingErrorForCode:JWTPublicHeaderStrippingError_Invalid_Byte_At_Index parameters:@{@"index" : @(index - 1), @"byte": @(bytes[index - 1] ?: 0)}]; if (error) { *error = currentError; } return nil; } // index += 1 // // let strippedKeyBytes = [UInt8](byteArray[index...keyData.count - 1]) // let data = Data(bytes: UnsafePointer(strippedKeyBytes), count: keyData.count - index) index += 1; NSInteger countOfStrippedBytes = currentData.length - index; UInt8 *strippedBytes = (UInt8 *)(bytes + index); NSData *resultData = [[NSData alloc] initWithBytes:strippedBytes length:countOfStrippedBytes]; // return data return resultData; } + (NSData *)dataByExtractingKeyFromANS1:(NSData *)data error:(NSError *__autoreleasing *)error { if (data == nil) { return nil; } // look for 03 42 00 04 int8_t bytesToSearchFor[] = {0x03, 0x42, 0x00, 0x04}; int count = sizeof(bytesToSearchFor) / sizeof(bytesToSearchFor[0]); NSData *dataToSearchFor = [NSData dataWithBytes:bytesToSearchFor length:count]; NSRange fullRange = NSMakeRange(0, data.length); NSRange foundRange = [data rangeOfData:dataToSearchFor options:0 range:fullRange]; NSData *foundData = nil; if (foundRange.location != NSNotFound && foundRange.length != 0) { // try to extract tail of data. // but we should also preserve 0x04. // so, one byte less. NSInteger tailPosition = foundRange.location + foundRange.length - 1; NSInteger length = data.length - tailPosition; if (tailPosition >= 0 && length >= 0) { foundData = [NSData dataWithBytes:((char *)data.bytes) + tailPosition length:length]; } } return foundData; } @end ================================================ FILE: Sources/JWT/ClaimSet/JWTClaim.m ================================================ // // JWTClaim.m // JWT // // Created by Lobanov Dmitry on 13.02.16. // Copyright © 2016 Karma. All rights reserved. // #import "JWTClaim.h" // TODO(3.0): Claim aud should check include in collection? // Add claims specification tests. // "iss" (Issuer) Claim // "sub" (Subject) Claim // "aud" (Audience) Claim // "exp" (Expiration Time) Claim // "nbf" (Not Before) Claim // "iat" (Issued At) Claim // "jti" (JWT ID) Claim // "typ" (Type) Claim // "scope" (Scope) Claim @interface JWTClaimIssuer : JWTClaim @end @implementation JWTClaimIssuer + (NSString *)name { return @"iss"; } + (BOOL)verifyValue:(NSString *)value withTrustedValue:(NSString *)trustedValue { return [trustedValue isEqualToString:value]; } @end @interface JWTClaimSubject : JWTClaim @end @implementation JWTClaimSubject + (NSString *)name { return @"sub"; } + (BOOL)verifyValue:(NSString *)value withTrustedValue:(NSString *)trustedValue { return [trustedValue isEqualToString:value]; } @end @interface JWTClaimAudience : JWTClaim @end // TODO: add array support later @implementation JWTClaimAudience + (NSString *)name { return @"aud"; } + (BOOL)verifyValue:(NSString *)value withTrustedValue:(NSString *)trustedValue { return [trustedValue isEqualToString:value]; } @end @interface JWTClaimExpirationTime : JWTClaim @end @implementation JWTClaimExpirationTime + (NSString *)name { return @"exp"; } + (BOOL)verifyValue:(NSDate *)value withTrustedValue:(NSDate *)trustedValue { // trustedValue - current date // value - expiration date // trustedValue < value, so return [trustedValue compare:value] == NSOrderedAscending; } @end @interface JWTClaimNotBefore : JWTClaim @end @implementation JWTClaimNotBefore + (NSString *)name { return @"nbf"; } + (BOOL)verifyValue:(NSDate *)value withTrustedValue:(NSDate *)trustedValue { // trustedValue - current date // value - start date // value <= trustedValue, so // trustedValue >= value, which means: // !(trustedValue < value) or NOT OrderedAscending return [trustedValue compare:value] != NSOrderedAscending; } @end @interface JWTClaimIssuedAt : JWTClaim @end @implementation JWTClaimIssuedAt + (NSString *)name { return @"iat"; } + (BOOL)verifyValue:(NSDate *)value withTrustedValue:(NSDate *)trustedValue { // trustedValue - current date // value - issued at date // value < trustedValue, so // trustedValue > value return [trustedValue compare:value] == NSOrderedDescending; } @end @interface JWTClaimJWTID : JWTClaim @end @implementation JWTClaimJWTID + (NSString *)name { return @"jti"; } + (BOOL)verifyValue:(NSString *)value withTrustedValue:(NSString *)trustedValue { return [trustedValue isEqualToString:value]; } @end @interface JWTClaimType : JWTClaim @end @implementation JWTClaimType + (NSString *)name { return @"typ"; } + (BOOL)verifyValue:(NSString *)value withTrustedValue:(NSString *)trustedValue { return [trustedValue isEqualToString:value]; } @end @interface JWTClaimScope : JWTClaim @end @implementation JWTClaimScope + (NSString *)name { return @"scope"; } + (BOOL)verifyValue:(NSString *)value withTrustedValue:(NSString *)trustedValue { return [trustedValue isEqualToString:value]; } @end @implementation JWTClaim + (NSString *)name { return @""; } + (NSDictionary *)claimsAndNames { static NSDictionary *dictionary = nil; return dictionary ? dictionary : (dictionary = @{ [JWTClaimIssuer name] : [JWTClaimIssuer new], [JWTClaimSubject name] : [JWTClaimSubject new], [JWTClaimAudience name] : [JWTClaimAudience new], [JWTClaimExpirationTime name] : [JWTClaimExpirationTime new], [JWTClaimNotBefore name] : [JWTClaimNotBefore new], [JWTClaimIssuedAt name] : [JWTClaimIssuedAt new], [JWTClaimJWTID name] : [JWTClaimJWTID new], [JWTClaimType name] : [JWTClaimType new], [JWTClaimScope name] : [JWTClaimScope new] }); } + (instancetype)claimByName:(NSString *)name { return [self claimsAndNames][name]; } + (BOOL)verifyValue:(NSObject *)value withTrustedValue:(NSObject *)trustedValue { return NO; } - (BOOL)verifyValue:(NSObject *)value withTrustedValue:(NSObject *)trustedValue { return [self.class verifyValue:value withTrustedValue:trustedValue]; } @end ================================================ FILE: Sources/JWT/ClaimSet/JWTClaimBase.m ================================================ // // JWTClaimBase.m // JWT // // Created by Dmitry Lobanov on 10.08.2020. // Copyright © 2020 JWTIO. All rights reserved. // #import "JWTClaimBase.h" @interface JWTClaimBase () @property (nonatomic, readwrite) NSObject *value; @property (copy, nonatomic, readwrite) NSString *name; @end @implementation JWTClaimBase @synthesize value = _value; - (instancetype)initWithValue:(NSObject *)value { if (self = [super init]) { self.value = value; } return self; } // MARK: - NSCopying - (nonnull id)copyWithZone:(nullable NSZone *)zone { return [self copyWithValue:self.value]; } // MARK: - JWTClaimProtocol + (NSString *)name { return @""; } - (NSString *)name { return _name ?: self.class.name; } - (instancetype)copyWithValue:(NSObject *)value { typeof(self) result = [[self.class alloc] initWithValue:value]; result.name = self.name; return result; } - (instancetype)copyWithName:(NSString *)name { typeof(self) result = [[self.class alloc] initWithValue:self.value]; result.name = name; return result; } @end ================================================ FILE: Sources/JWT/ClaimSet/JWTClaimSerializerBase.m ================================================ // // JWTClaimSerializerBase.m // JWT // // Created by Dmitry Lobanov on 30.05.2021. // Copyright © 2021 JWTIO. All rights reserved. // #import "JWTClaimSerializerBase.h" @implementation JWTClaimSerializerBase - (nonnull NSObject *)deserializedClaimValue:(nonnull NSObject *)value forName:(nonnull NSString *)name { return value; } - (nonnull NSObject *)serializedClaimValue:(nonnull id)claim { return claim.value; } @end ================================================ FILE: Sources/JWT/ClaimSet/JWTClaimSerializerVariations.m ================================================ // // JWTClaimSerializerVariations.m // JWT // // Created by Dmitry Lobanov on 30.05.2021. // Copyright © 2021 JWTIO. All rights reserved. // #import "JWTClaimSerializerVariations.h" @implementation JWTClaimSerializerVariations + (id)dateAndTimestampTransform { return [JWTClaimSerializerBaseConcreteDateAndTimestamp new]; } + (id)identityTransform { return [JWTClaimSerializerBase new]; } @end @implementation JWTClaimSerializerBaseConcreteDateAndTimestamp - (NSObject *)deserializedClaimValue:(NSObject *)value forName:(NSString *)name { if ([value isKindOfClass:NSNumber.class]) { return [NSDate dateWithTimeIntervalSince1970:[(NSNumber *)value doubleValue]]; } return value; } - (NSObject *)serializedClaimValue:(id)claim { __auto_type value = claim.value; if ([value isKindOfClass:NSDate.class]) { return @([(NSDate *)value timeIntervalSince1970]); } return value; } @end ================================================ FILE: Sources/JWT/ClaimSet/JWTClaimVariations.m ================================================ // // JWTClaimVariations.m // JWT // // Created by Dmitry Lobanov on 10.08.2020. // Copyright © 2020 JWTIO. All rights reserved. // #import "JWTClaimVariations.h" NSString *JWTRegisteredClaimNameIssuer = @"iss"; NSString *JWTRegisteredClaimNameSubject = @"sub"; NSString *JWTRegisteredClaimNameAudience = @"aud"; NSString *JWTRegisteredClaimNameExpirationTime = @"exp"; NSString *JWTRegisteredClaimNameNotBefore = @"nbf"; NSString *JWTRegisteredClaimNameIssuedAt = @"iat"; NSString *JWTRegisteredClaimNameJWTID = @"jti"; NSString *JWTRegisteredClaimNameType = @"typ"; NSString *JWTRegisteredClaimNameScope = @"scope"; @implementation JWTClaimsNames + (NSString *)issuer { return JWTRegisteredClaimNameIssuer; } + (NSString *)subject { return JWTRegisteredClaimNameSubject; } + (NSString *)audience { return JWTRegisteredClaimNameAudience; } + (NSString *)expirationTime { return JWTRegisteredClaimNameExpirationTime; } + (NSString *)notBefore { return JWTRegisteredClaimNameNotBefore; } + (NSString *)issuedAt { return JWTRegisteredClaimNameIssuedAt; } + (NSString *)jwtID { return JWTRegisteredClaimNameJWTID; } + (NSString *)type { return JWTRegisteredClaimNameType; } + (NSString *)scope { return JWTRegisteredClaimNameScope; } @end @interface JWTClaimBaseConcreteIssuer : JWTClaimBase @end @interface JWTClaimBaseConcreteSubject : JWTClaimBase @end @interface JWTClaimBaseConcreteAudience : JWTClaimBase @end @interface JWTClaimBaseConcreteExpirationTime : JWTClaimBase @end @interface JWTClaimBaseConcreteNotBefore : JWTClaimBase @end @interface JWTClaimBaseConcreteIssuedAt : JWTClaimBase @end @interface JWTClaimBaseConcreteJWTID : JWTClaimBase @end @interface JWTClaimBaseConcreteType : JWTClaimBase @end @interface JWTClaimBaseConcreteScope : JWTClaimBase @end @implementation JWTClaimVariations + (id)issuer { return [JWTClaimBaseConcreteIssuer new]; } + (id)subject { return [JWTClaimBaseConcreteSubject new]; } + (id)audience { return [JWTClaimBaseConcreteAudience new]; } + (id)expirationTime { return [JWTClaimBaseConcreteExpirationTime new]; } + (id)notBefore { return [JWTClaimBaseConcreteNotBefore new]; } + (id)issuedAt { return [JWTClaimBaseConcreteIssuedAt new]; } + (id)jwtID { return [JWTClaimBaseConcreteJWTID new]; } + (id)type { return [JWTClaimBaseConcreteType new]; } + (id)scope { return [JWTClaimBaseConcreteScope new]; } @end // MARK: - Base Concrete Claims @implementation JWTClaimBaseConcreteIssuer + (NSString *)name { return JWTRegisteredClaimNameIssuer; } @end @implementation JWTClaimBaseConcreteSubject + (NSString *)name { return JWTRegisteredClaimNameSubject; } @end @implementation JWTClaimBaseConcreteAudience + (NSString *)name { return JWTRegisteredClaimNameAudience; } @end @implementation JWTClaimBaseConcreteExpirationTime + (NSString *)name { return JWTRegisteredClaimNameExpirationTime; } @end @implementation JWTClaimBaseConcreteNotBefore + (NSString *)name { return JWTRegisteredClaimNameNotBefore; } @end @implementation JWTClaimBaseConcreteIssuedAt + (NSString *)name { return JWTRegisteredClaimNameIssuedAt; } @end @implementation JWTClaimBaseConcreteJWTID + (NSString *)name { return JWTRegisteredClaimNameJWTID; } @end @implementation JWTClaimBaseConcreteType + (NSString *)name { return JWTRegisteredClaimNameType; } @end @implementation JWTClaimBaseConcreteScope + (NSString *)name { return JWTRegisteredClaimNameScope; } @end ================================================ FILE: Sources/JWT/ClaimSet/JWTClaimVerifierBase.m ================================================ // // JWTClaimVerifierBase.m // JWT // // Created by Dmitry Lobanov on 30.05.2021. // Copyright © 2021 JWTIO. All rights reserved. // #import "JWTClaimVerifierBase.h" @implementation JWTClaimVerifierBase - (BOOL)verifyValue:(NSObject *)value withTrustedValue:(NSObject *)trustedValue { return NO; } @end ================================================ FILE: Sources/JWT/ClaimSet/JWTClaimVerifierVariations.m ================================================ // // JWTClaimVerifierVariations.m // JWT // // Created by Dmitry Lobanov on 30.05.2021. // Copyright © 2021 JWTIO. All rights reserved. // #import "JWTClaimVerifierVariations.h" @implementation JWTClaimVerifierVariations + (id)issuer { return [JWTClaimVerifierBaseConcreteEqualityForString new]; } + (id)subject { return [JWTClaimVerifierBaseConcreteEqualityForString new]; } + (id)audienceEqualSingle { return [JWTClaimVerifierBaseConcreteEqualityForString new]; } + (id)audienceInSet { return [JWTClaimVerifierBaseConcreteInclusionInSet new]; } // trustedValue - current date // value - expiration date // trustedValue < value, so + (id)expirationTime { __auto_type verifier = [JWTClaimVerifierBaseConcreteComparison new]; verifier.trustedValueAtLeft = YES; verifier.expectedComparison = NSOrderedAscending; return verifier; } // trustedValue - current date // value - start date // value <= trustedValue, so // trustedValue >= value, which means: // !(trustedValue < value) or NOT OrderedAscending + (id)notBefore { __auto_type verifier = [JWTClaimVerifierBaseConcreteComparison new]; verifier.trustedValueAtLeft = YES; verifier.expectedComparison = NSOrderedAscending; verifier.notEqual = YES; return verifier; } // trustedValue - current date // value - issued at date // value < trustedValue, so // trustedValue > value + (id)issuedAt { __auto_type verifier = [JWTClaimVerifierBaseConcreteComparison new]; verifier.trustedValueAtLeft = YES; verifier.expectedComparison = NSOrderedDescending; return verifier; } + (id)jwtID { return [JWTClaimVerifierBaseConcreteEqualityForString new]; } + (id)type { return [JWTClaimVerifierBaseConcreteEqualityForString new]; } + (id)scope { return [JWTClaimVerifierBaseConcreteEqualityForString new]; } @end @implementation JWTClaimVerifierBaseConcreteEquality - (instancetype)init { if (self = [super init]) { self.equal = YES; } return self; } - (BOOL)verifyValue:(NSObject *)value withTrustedValue:(NSObject *)trustedValue { return [value isEqual:trustedValue] == self.equal; } @end @implementation JWTClaimVerifierBaseConcreteComparison - (BOOL)verifyValue:(NSObject *)value withTrustedValue:(NSObject *)trustedValue { if (self.trustedValueAtLeft) { __auto_type swap = value; value = trustedValue; trustedValue = swap; } if ([value respondsToSelector:@selector(compare:)]) { __auto_type result = (NSComparisonResult)[value performSelector:@selector(compare:) withObject:trustedValue]; if (self.notEqual) { return result != self.expectedComparison; } return result == self.expectedComparison; } return NO; } @end @implementation JWTClaimVerifierBaseConcreteEqualityForString - (BOOL)verifyValue:(NSObject *)value withTrustedValue:(NSObject *)trustedValue { if ([value isKindOfClass:NSString.class] && [trustedValue isKindOfClass:NSString.class]) { return [(NSString *)value isEqualToString:(NSString *)trustedValue] == self.equal; } return [super verifyValue:value withTrustedValue:trustedValue]; } @end @implementation JWTClaimVerifierBaseConcreteInclusionInSet - (BOOL)verifyValue:(NSObject *)value withTrustedValue:(NSObject *)trustedValue { if ([trustedValue isKindOfClass:NSSet.class]) { return [(NSSet *)trustedValue containsObject:value]; } return NO; } @end ================================================ FILE: Sources/JWT/ClaimSet/JWTClaimsProviderBase.m ================================================ // // JWTClaimsProviderBase.m // JWT // // Created by Dmitry Lobanov on 22.05.2021. // Copyright © 2021 JWTIO. All rights reserved. // #import "JWTClaimsProviderBase.h" #import "JWTClaimVariations.h" @interface JWTClaimsProviderBase () @property (strong, nonatomic, readwrite) NSMutableDictionary > *claimsAndNames; @end @implementation JWTClaimsProviderBase + (NSDictionary *)createClaimsAndNames { __auto_type issuer = JWTClaimVariations.issuer; __auto_type subject = JWTClaimVariations.subject; __auto_type audience = JWTClaimVariations.audience; __auto_type expirationTime = JWTClaimVariations.expirationTime; __auto_type notBefore = JWTClaimVariations.notBefore; __auto_type issuedAt = JWTClaimVariations.issuedAt; __auto_type jwtId = JWTClaimVariations.jwtID; __auto_type type = JWTClaimVariations.type; __auto_type scope = JWTClaimVariations.scope; return @{ issuer.name : issuer, subject.name : subject, audience.name : audience, expirationTime.name : expirationTime, notBefore.name : notBefore, issuedAt.name : issuedAt, jwtId.name : jwtId, type.name : type, scope.name : scope }; } - (instancetype)init { return [self initWithClaimsAndNames:self.class.createClaimsAndNames]; } - (instancetype)initWithClaimsAndNames:(NSDictionary *)dictionary { if (self = [super init]) { self.claimsAndNames = [NSMutableDictionary dictionaryWithDictionary:dictionary]; } return self; } // MARK: - JWTClaimsProviderProtocol - (NSArray *)availableClaimsNames { return self.claimsAndNames.allKeys; } - (nonnull id)claimByName:(nonnull NSString *)name { __auto_type claim = self.claimsAndNames[name]; return [claim copyWithValue:claim.value]; } - (void)registerClaim:(id)claim forClaimName:(NSString *)name { if (name == nil) { return; } self.claimsAndNames[name] = [[claim copyWithName:name] copyWithValue:claim.value]; } - (void)unregisterClaimForClaimName:(NSString *)name { if (name == nil) { return; } [self.claimsAndNames removeObjectForKey:name]; } @end ================================================ FILE: Sources/JWT/ClaimSet/JWTClaimsSet.m ================================================ // // JWTClaimsSet.m // JWT // // Created by Klaas Pieter Annema on 31-05-13. // Copyright (c) 2013 Karma. All rights reserved. // #import "JWTClaimsSet.h" @implementation JWTClaimsSet - (id)copyWithZone:(NSZone *)zone { JWTClaimsSet *newClaimsSet = [[self.class alloc] init]; newClaimsSet.issuer = self.issuer; newClaimsSet.subject = self.subject; newClaimsSet.audience = self.audience; newClaimsSet.expirationDate = self.expirationDate; newClaimsSet.notBeforeDate = self.notBeforeDate; newClaimsSet.issuedAt = self.issuedAt; newClaimsSet.identifier = self.identifier; newClaimsSet.type = self.type; newClaimsSet.scope = self.scope; return newClaimsSet; } @end ================================================ FILE: Sources/JWT/ClaimSet/JWTClaimsSetBase.m ================================================ // // JWTClaimsSetBase.m // JWT // // Created by Dmitry Lobanov on 10.08.2020. // Copyright © 2020 JWTIO. All rights reserved. // #import "JWTClaimsSetBase.h" #import "JWTClaimVariations.h" @interface JWTClaimsSetBase () @property (strong, nonatomic, readwrite) NSMutableDictionary > *namesAndClaims; @end @implementation JWTClaimsSetBase - (instancetype)initWithClaims:(nonnull NSArray> *)claims { if (self = [super init]) { self.namesAndClaims = [NSMutableDictionary dictionaryWithObjects:claims forKeys:[claims valueForKey:@"name"]]; } return self; } - (instancetype)init { return [self initWithClaims:@[]]; } // MARK: - NSCopying - (nonnull id)copyWithZone:(nullable NSZone *)zone { return [self copyWithClaims:self.claims]; } // MARK: - JWTClaimsSetProtocol - (NSArray> *)claims { return self.namesAndClaims.allValues; } - (instancetype)copyWithClaims:(NSArray> *)claims { return [[self.class alloc] initWithClaims:claims]; } - (id)claimByName:(NSString *)name { if (name == nil) { return nil; } return self.namesAndClaims[name]; } - (void)appendClaim:(id)claim { if (claim == nil || claim.name == nil) { return; } if (self.namesAndClaims[claim.name]) { return; } self.namesAndClaims[claim.name] = claim; } - (void)removeClaimByName:(NSString *)name { if (name == nil) { return; } [self.namesAndClaims removeObjectForKey:name]; } - (BOOL)isEmpty { return self.namesAndClaims.count == 0; } @end ================================================ FILE: Sources/JWT/ClaimSet/JWTClaimsSetCoordinatorBase.m ================================================ // // JWTClaimsSetCoordinatorBase.m // JWT // // Created by Dmitry Lobanov on 31.05.2021. // Copyright © 2021 JWTIO. All rights reserved. // #import "JWTClaimsSetCoordinatorBase.h" #import "JWTClaimsProviderBase.h" #import "JWTClaimsSetBase.h" #import "JWTClaimsSetSerializerBase.h" #import "JWTClaimsSetVerifierBase.h" #import "JWTClaimsSetDSLBase.h" @interface JWTClaimsSetCoordinatorBase () @property (copy, nonatomic, readwrite) id (^configureClaimsSet)(JWTClaimsSetDSLBase *(^)(JWTClaimsSetDSLBase *claimsSetDSL)); @end @implementation JWTClaimsSetCoordinatorBase - (void)sanitize { self.claimsSetSerializer.claimsProvider = self.claimsProvider; self.claimsSetSerializer.claimsSetStorage = self.claimsSetStorage; self.claimsSetVerifier.claimsProvider = self.claimsProvider; } - (instancetype)init { if (self = [super init]) { self.claimsProvider = [JWTClaimsProviderBase new]; self.claimsSetStorage = [JWTClaimsSetBase new]; self.claimsSetSerializer = [JWTClaimsSetSerializerBase new]; self.claimsSetVerifier = [JWTClaimsSetVerifierBase new]; [self setupFluent]; [self sanitize]; } return self; } // MARK: - JWTClaimsSetCoordinatorProtocol - (void)setClaimsProvider:(id)claimsProvider { _claimsProvider = claimsProvider; [self sanitize]; } - (void)setClaimsSetStorage:(id)claimsSetStorage { _claimsSetStorage = claimsSetStorage; [self sanitize]; } - (void)setClaimsSetSerializer:(id)claimsSetSerializer { _claimsSetSerializer = claimsSetSerializer; [self sanitize]; } - (void)setClaimsSetVerifier:(id)claimsSetVerifier { _claimsSetVerifier = claimsSetVerifier; [self sanitize]; } - (JWTClaimsSetDSLBase *)dslDesrciption { return [[JWTClaimsSetDSLBase alloc] initWithClaimsProvider:self.claimsProvider claimsSetStorage:self.claimsSetStorage]; } - (instancetype)configureClaimsSet:(JWTClaimsSetDSLBase *(^)(JWTClaimsSetDSLBase *claimsSetDSL))claimsSet { if (claimsSet) { __auto_type dsl = self.dslDesrciption; __auto_type value = claimsSet(dsl); self.claimsSetStorage = value.claimsSetStorage ?: [JWTClaimsSetBase new]; } return self; } - (void)registerClaim:(id)claim serializer:(id)serializer verifier:(id)verifier forClaimName:(NSString *)name { [self.claimsProvider registerClaim:claim forClaimName:name]; [self.claimsSetSerializer registerSerializer:serializer forClaimName:name]; [self.claimsSetVerifier registerVerifier:verifier forClaimName:name]; } - (void)unregisterClaimWithSerializerAndVerifierForClaimName:(NSString *)name { [self.claimsProvider unregisterClaimForClaimName:name]; [self.claimsSetSerializer unregisterSerializerForClaimName:name]; [self.claimsSetVerifier unregisterVerifierForClaimName:name]; } // MARK: - Fluent - (void)setupFluent { __weak typeof(self) weakSelf = self; self.configureClaimsSet = ^(JWTClaimsSetDSLBase *(^block)(JWTClaimsSetDSLBase *claimsSetDSL)) { return [weakSelf configureClaimsSet:block]; }; } @end ================================================ FILE: Sources/JWT/ClaimSet/JWTClaimsSetDSLBase.m ================================================ // // JWTClaimsSetDSLBase.m // JWT // // Created by Dmitry Lobanov on 31.05.2021. // Copyright © 2021 JWTIO. All rights reserved. // #import "JWTClaimsSetDSLBase.h" #import "JWTClaimVariations.h" @interface JWTClaimsSetDSLBase () @property (strong, nonatomic, readwrite) id claimsProvider; @property (copy, nonatomic, readwrite) id claimsSetStorage; @end @implementation JWTClaimsSetDSLBase - (instancetype)initWithClaimsProvider:(id)claimsProvider claimsSetStorage:(id)claimsSetStorage { if (self = [self init]) { self.claimsProvider = claimsProvider; self.claimsSetStorage = claimsSetStorage; } return self; } @end @implementation JWTClaimsSetDSLBase (DSL) - (nullable NSObject *)dslValueForName:(NSString *)name { __auto_type claim = [self.claimsProvider claimByName:name]; if (claim == nil) { return nil; } return [self.claimsSetStorage claimByName:name].value; } - (void)dslSetValue:(NSObject *)value forName:(NSString *)name { __auto_type claim = [self.claimsProvider claimByName:name]; if (claim == nil) { return; } [self.claimsSetStorage removeClaimByName:name]; [self.claimsSetStorage appendClaim:[claim copyWithValue:value]]; } // MARK: - DSL - (NSString *)issuer { return (NSString *)[self dslValueForName:JWTClaimsNames.issuer]; } - (void)setIssuer:(NSString *)value { [self dslSetValue:value forName:JWTClaimsNames.issuer]; } - (NSString *)subject { return (NSString *)[self dslValueForName:JWTClaimsNames.subject]; } - (void)setSubject:(NSString *)value { [self dslSetValue:value forName:JWTClaimsNames.subject]; } - (NSString *)audience { return (NSString *)[self dslValueForName:JWTClaimsNames.audience]; } - (void)setAudience:(NSString *)value { [self dslSetValue:value forName:JWTClaimsNames.audience]; } - (NSDate *)expirationDate { return (NSDate *)[self dslValueForName:JWTClaimsNames.expirationTime]; } - (void)setExpirationDate:(NSDate *)value { [self dslSetValue:value forName:JWTClaimsNames.expirationTime]; } - (NSDate *)notBeforeDate { return (NSDate *)[self dslValueForName:JWTClaimsNames.notBefore]; } - (void)setNotBeforeDate:(NSDate *)value { [self dslSetValue:value forName:JWTClaimsNames.notBefore]; } - (NSDate *)issuedAt { return (NSDate *)[self dslValueForName:JWTClaimsNames.issuedAt]; } - (void)setIssuedAt:(NSDate *)value { [self dslSetValue:value forName:JWTClaimsNames.issuedAt]; } - (NSString *)identifier { return (NSString *)[self dslValueForName:JWTClaimsNames.jwtID]; } - (void)setIdentifier:(NSString *)value { [self dslSetValue:value forName:JWTClaimsNames.jwtID]; } - (NSString *)type { return (NSString *)[self dslValueForName:JWTClaimsNames.type]; } - (void)setType:(NSString *)value { [self dslSetValue:value forName:JWTClaimsNames.type]; } - (NSString *)scope { return (NSString *)[self dslValueForName:JWTClaimsNames.scope]; } - (void)setScope:(NSString *)value { [self dslSetValue:value forName:JWTClaimsNames.scope]; } @end ================================================ FILE: Sources/JWT/ClaimSet/JWTClaimsSetSerializer.m ================================================ // // JWTClaimsSetSerializer.m // JWT // // Created by Klaas Pieter Annema on 31-05-13. // Copyright (c) 2013 Karma. All rights reserved. // #import "JWTClaimsSetSerializer.h" @implementation JWTClaimsSetSerializer + (NSArray *)claimsSetKeys { return @[@"iss", @"sub", @"aud", @"exp", @"nbf", @"iat", @"jti", @"typ", @"scope"]; } + (NSDictionary *)dictionaryWithClaimsSet:(JWTClaimsSet *)theClaimsSet; { NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; [self dictionary:dictionary setObjectIfNotNil:theClaimsSet.issuer forKey:@"iss"]; [self dictionary:dictionary setObjectIfNotNil:theClaimsSet.subject forKey:@"sub"]; [self dictionary:dictionary setObjectIfNotNil:theClaimsSet.audience forKey:@"aud"]; [self dictionary:dictionary setDateIfNotNil:theClaimsSet.expirationDate forKey:@"exp"]; [self dictionary:dictionary setDateIfNotNil:theClaimsSet.notBeforeDate forKey:@"nbf"]; [self dictionary:dictionary setDateIfNotNil:theClaimsSet.issuedAt forKey:@"iat"]; [self dictionary:dictionary setObjectIfNotNil:theClaimsSet.identifier forKey:@"jti"]; [self dictionary:dictionary setObjectIfNotNil:theClaimsSet.type forKey:@"typ"]; [self dictionary:dictionary setObjectIfNotNil:theClaimsSet.scope forKey:@"scope"]; return [dictionary copy]; } + (JWTClaimsSet *)claimsSetWithDictionary:(NSDictionary *)theDictionary; { JWTClaimsSet *claimsSet = [[JWTClaimsSet alloc] init]; claimsSet.issuer = [theDictionary objectForKey:@"iss"]; claimsSet.subject = [theDictionary objectForKey:@"sub"]; claimsSet.audience = [theDictionary objectForKey:@"aud"]; claimsSet.expirationDate = [NSDate dateWithTimeIntervalSince1970:[[theDictionary objectForKey:@"exp"] doubleValue]]; claimsSet.notBeforeDate = [NSDate dateWithTimeIntervalSince1970:[[theDictionary objectForKey:@"nbf"] doubleValue]]; claimsSet.issuedAt = [NSDate dateWithTimeIntervalSince1970:[[theDictionary objectForKey:@"iat"] doubleValue]]; claimsSet.identifier = [theDictionary objectForKey:@"jti"]; claimsSet.type = [theDictionary objectForKey:@"typ"]; claimsSet.scope = [theDictionary objectForKey:@"scope"]; return claimsSet; } + (void)dictionary:(NSMutableDictionary *)theDictionary setObjectIfNotNil:(id)theObject forKey:(id)theKey; { if (!theObject) return; [theDictionary setObject:theObject forKey:theKey]; } + (void)dictionary:(NSMutableDictionary *)theDictionary setDateIfNotNil:(NSDate*)date forKey:(id)theKey; { if (!date) return; NSNumber* value = @((unsigned long)[date timeIntervalSince1970]); [theDictionary setObject:value forKey:theKey]; } @end ================================================ FILE: Sources/JWT/ClaimSet/JWTClaimsSetSerializerBase.m ================================================ // // JWTClaimsSetSerializerBase.m // JWT // // Created by Dmitry Lobanov on 10.08.2020. // Copyright © 2020 JWTIO. All rights reserved. // #import "JWTClaimsSetSerializerBase.h" #import "JWTClaimVariations.h" #import "JWTClaimSerializerVariations.h" @interface JWTClaimsSetSerializerBase () @property (strong, nonatomic, readwrite) NSMutableDictionary > *namesAndSerializers; @end @implementation JWTClaimsSetSerializerBase + (NSDictionary *)createNamesAndSerializers { __auto_type expirationTime = JWTClaimsNames.expirationTime; __auto_type notBefore = JWTClaimsNames.notBefore; __auto_type issuedAt = JWTClaimsNames.issuedAt; return @{ expirationTime : JWTClaimSerializerVariations.dateAndTimestampTransform, notBefore : JWTClaimSerializerVariations.dateAndTimestampTransform, issuedAt : JWTClaimSerializerVariations.dateAndTimestampTransform, }; } - (instancetype)init { if (self = [super init]) { self.namesAndSerializers = [NSMutableDictionary dictionaryWithDictionary:self.class.createNamesAndSerializers]; } return self; } - (NSObject *)deserializedClaimValue:(NSObject *)value forName:(NSString *)name { __auto_type serializer = self.namesAndSerializers[name] ?: [JWTClaimSerializerBase new]; return [serializer deserializedClaimValue:value forName:name]; } - (NSObject *)serializedClaimValue:(id)claim { __auto_type name = claim.name; __auto_type serializer = self.namesAndSerializers[name] ?: [JWTClaimSerializerBase new]; return [serializer serializedClaimValue:claim]; } // MARK: - JWTClaimsSetSerializerProtocol - (void)registerSerializer:(id)serializer forClaimName:(NSString *)name { if (name != nil) { self.namesAndSerializers[name] = serializer; } } - (void)unregisterSerializerForClaimName:(NSString *)name { if (name != nil) { [self.namesAndSerializers removeObjectForKey:name]; } } - (nullable id)claimsSetFromDictionary:(nonnull NSDictionary *)dictionary { if (dictionary == nil) { return nil; } if (dictionary.count == 0) { return nil; } __auto_type result = [NSMutableArray new]; for (NSString *key in dictionary) { __auto_type claim = [self.claimsProvider claimByName:key]; __auto_type skipVerification = self.skipClaimsProviderLookupCheck; if (skipVerification || claim != nil) { __auto_type value = [self deserializedClaimValue:dictionary[key] forName:key]; [result addObject:[claim copyWithValue:value]]; } } if (result.count == 0) { return nil; } return [self.claimsSetStorage copyWithClaims:result]; } - (nullable NSDictionary *)dictionaryFromClaimsSet:(nonnull id)claimsSet { if (claimsSet == nil) { return nil; } if (claimsSet.isEmpty) { return nil; } __auto_type result = [NSMutableDictionary new]; for (id value in claimsSet.claims) { __auto_type claim = [self.claimsProvider claimByName:value.name]; __auto_type skipVerification = self.skipClaimsProviderLookupCheck; if (skipVerification || claim != nil) { result[value.name] = [self serializedClaimValue:value]; } } if (result.count == 0) { return nil; } return [NSDictionary dictionaryWithDictionary:result]; } @end ================================================ FILE: Sources/JWT/ClaimSet/JWTClaimsSetVerifier.m ================================================ // // JWTClaimsSetVerifier.m // JWT // // Created by Lobanov Dmitry on 13.02.16. // Copyright © 2016 Karma. All rights reserved. // #import "JWTClaimsSetVerifier.h" #import "JWTClaimsSetSerializer.h" #import "JWTClaim.h" @implementation JWTClaimsSetVerifier + (BOOL)verifyDictionary:(NSDictionary *)dictionary withTrustedDictionary:(NSDictionary *)trustedDictionary byKey:(NSString *)key { NSObject *value = dictionary[key]; NSObject *trustedValue = trustedDictionary[key]; BOOL result = YES; if (trustedValue) { result = [[JWTClaim claimByName:key] verifyValue:value withTrustedValue:trustedValue]; } return result; } + (BOOL)verifyClaimsSetDictionary:(NSDictionary *)theClaimsSetDictionary withTrustedClaimsSetDictionary:(NSDictionary *)trustedClaimsSetDictionary { NSArray *claimsSets = [JWTClaimsSetSerializer claimsSetKeys]; if (!trustedClaimsSetDictionary) { return YES; } if (!theClaimsSetDictionary) { return NO; } BOOL result = YES; for (NSString *key in claimsSets) { result = result && [self verifyDictionary:theClaimsSetDictionary withTrustedDictionary:trustedClaimsSetDictionary byKey:key]; } return result; } + (BOOL)verifyClaimsSet:(JWTClaimsSet *)theClaimsSet withTrustedClaimsSet:(JWTClaimsSet *)trustedClaimsSet { NSDictionary *dictionary = [JWTClaimsSetSerializer dictionaryWithClaimsSet:theClaimsSet]; NSDictionary *trustedDictionary = [JWTClaimsSetSerializer dictionaryWithClaimsSet:trustedClaimsSet]; NSArray *claimsSets = [JWTClaimsSetSerializer claimsSetKeys]; BOOL result = YES; for (NSString *key in claimsSets) { result = result && [self verifyDictionary:dictionary withTrustedDictionary:trustedDictionary byKey:key]; } return result; } + (BOOL)verifyClaimsSetDictionary:(NSDictionary *)theClaimsSetDictionary withTrustedClaimsSet:(JWTClaimsSet *)trustedClaimsSet { NSDictionary *trustedDictionary = [JWTClaimsSetSerializer dictionaryWithClaimsSet:trustedClaimsSet]; return [self verifyClaimsSetDictionary:theClaimsSetDictionary withTrustedClaimsSetDictionary:trustedDictionary]; } @end ================================================ FILE: Sources/JWT/ClaimSet/JWTClaimsSetVerifierBase.m ================================================ // // JWTClaimsSetVerifierBase.m // JWT // // Created by Dmitry Lobanov on 10.08.2020. // Copyright © 2020 JWTIO. All rights reserved. // #import "JWTClaimsSetVerifierBase.h" #import "JWTClaimVariations.h" #import "JWTClaimVerifierVariations.h" @interface JWTClaimsSetVerifierBase () @property (strong, nonatomic, readwrite) NSMutableDictionary > *namesAndVerifiers; @end @implementation JWTClaimsSetVerifierBase + (NSDictionary *)createNamesAndVerifiers { __auto_type issuer = JWTClaimsNames.issuer; __auto_type subject = JWTClaimsNames.subject; __auto_type audience = JWTClaimsNames.audience; __auto_type expirationTime = JWTClaimsNames.expirationTime; __auto_type notBefore = JWTClaimsNames.notBefore; __auto_type issuedAt = JWTClaimsNames.issuedAt; __auto_type jwtId = JWTClaimsNames.jwtID; __auto_type type = JWTClaimsNames.type; __auto_type scope = JWTClaimsNames.scope; return @{ issuer : JWTClaimVerifierVariations.issuer, subject : JWTClaimVerifierVariations.subject, audience : JWTClaimVerifierVariations.audienceEqualSingle, expirationTime : JWTClaimVerifierVariations.expirationTime, notBefore : JWTClaimVerifierVariations.notBefore, issuedAt : JWTClaimVerifierVariations.issuedAt, jwtId : JWTClaimVerifierVariations.jwtID, type : JWTClaimVerifierVariations.type, scope : JWTClaimVerifierVariations.scope, }; } - (instancetype)init { if (self = [super init]) { self.namesAndVerifiers = [NSMutableDictionary dictionaryWithDictionary:self.class.createNamesAndVerifiers]; } return self; } - (BOOL)verifyClaim:(id)claim withValue:(NSObject *)value withTrustedValue:(NSObject *)trustedValue { __auto_type verifier = self.namesAndVerifiers[claim.name] ?: [JWTClaimVerifierBase new]; return [verifier verifyValue:value withTrustedValue:trustedValue]; } // MARK: - JWTClaimsSetVerifierProtocol - (void)registerVerifier:(id)verifier forClaimName:(NSString *)name { if (name != nil) { self.namesAndVerifiers[name] = verifier; } } - (void)unregisterVerifierForClaimName:(NSString *)name { if (name != nil) { [self.namesAndVerifiers removeObjectForKey:name]; } } - (BOOL)verifyClaimsSet:(id)theClaimsSet withTrustedClaimsSet:(id)trustedClaimsSet { __auto_type untrustedDictionary = [self.serializer dictionaryFromClaimsSet:theClaimsSet]; __auto_type trustedDictionary = [self.serializer dictionaryFromClaimsSet:trustedClaimsSet]; if (trustedDictionary == nil) { return YES; } if (untrustedDictionary == nil) { return NO; } for (NSString *key in self.claimsProvider.availableClaimsNames) { __auto_type claim = [self.claimsProvider claimByName:key]; if (claim == nil) { return NO; } __auto_type trustedValue = (NSObject *)trustedDictionary[key]; __auto_type untrustedValue = (NSObject *)untrustedDictionary[key]; if (!trustedValue) { continue; } __auto_type claimVerified = [self verifyClaim:claim withValue:untrustedValue withTrustedValue:trustedValue]; if (!claimVerified) { return NO; } } return YES; } @end ================================================ FILE: Sources/JWT/Coding/JWTBuilder+FluentStyle.m ================================================ // // JWTBuilder+FluentStyle.m // JWT // // Created by Dmitry Lobanov on 15/06/2019. // Copyright © 2019 JWTIO. All rights reserved. // #import "JWTBuilder+FluentStyle.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wobjc-property-implementation" @implementation JWTBuilder (FluentStyle) @end #pragma clang diagnostic pop ================================================ FILE: Sources/JWT/Coding/JWTCoding+ResultTypes.m ================================================ // // JWTCoding+ResultTypes.m // JWT // // Created by Lobanov Dmitry on 30.11.16. // Copyright © 2016 JWTIO. All rights reserved. // #import "JWTCoding+ResultTypes.h" static NSString *JWTCodingResultHeaders = @"headers"; static NSString *JWTCodingResultPayload = @"payload"; @implementation JWT (ResultTypes) @end @implementation JWTCodingResultComponents + (NSString *)headers { return JWTCodingResultHeaders; } + (NSString *)payload { return JWTCodingResultPayload; } @end // Protected? @protocol JWTMutableCodingResultTypeSuccessEncodedProtocol @property (copy, nonatomic, readwrite) NSString *encoded; @property (copy, nonatomic, readwrite) NSString *token; @end // Protected? @protocol JWTMutableCodingResultTypeSuccessDecodedProtocol @property (copy, nonatomic, readwrite) NSDictionary *headers; @property (copy, nonatomic, readwrite) NSDictionary *payload; @property (copy, nonatomic, readwrite) id claimsSetStorage; @end // Protected? @protocol JWTMutableCodingResultTypeErrorProtocol @property (copy, nonatomic, readwrite) NSError *error; @end @interface JWTCodingResultTypeSuccess () @end @implementation JWTCodingResultTypeSuccess @synthesize encoded = _encoded; @synthesize headers = _headers; @synthesize payload = _payload; @synthesize claimsSetStorage = _claimsSetStorage; //Not used yet. Could be replacement for _encoded. @synthesize token = _token; - (NSDictionary *)headerAndPayloadDictionary { if (self.headers && self.payload) { return @{ JWTCodingResultComponents.headers: self.headers, JWTCodingResultComponents.payload: self.payload }; } return nil; } - (instancetype)initWithEncoded:(NSString *)encoded { if (self = [super init]) { self.encoded = encoded; } return self; } - (instancetype)initWithToken:(NSString *)token { if (self = [super init]) { self.token = token; } return self; } - (instancetype)initWithHeaders:(NSDictionary *)headers withPayload:(NSDictionary *)payload { if (self = [super init]) { self.headers = headers; self.payload = payload; } return self; } - (instancetype)initWithHeadersAndPayload:(NSDictionary *)headersAndPayloadDictionary { NSDictionary *headers = headersAndPayloadDictionary[JWTCodingResultComponents.headers]; NSDictionary *payload = headersAndPayloadDictionary[JWTCodingResultComponents.payload]; return [self initWithHeaders:headers withPayload:payload]; } - (instancetype)initWithClaimsSetStorage:(id)claimsSetStorage { if (self = [super init]) { self.claimsSetStorage = claimsSetStorage; } return self; } @end @interface JWTCodingResultTypeError () @end @implementation JWTCodingResultTypeError @synthesize error = _error; - (instancetype)initWithError:(NSError *)error { if (self = [super init]) { self.error = error; } return self; } @end @interface JWTCodingResultType () @property (strong, nonatomic, readwrite) JWTCodingResultTypeSuccess *successResult; @property (strong, nonatomic, readwrite) JWTCodingResultTypeError *errorResult; @end @implementation JWTCodingResultType - (instancetype)initWithSuccessResult:(JWTCodingResultTypeSuccess *)success { if (self = [super init]) { self.successResult = success; } return self; } - (instancetype)initWithErrorResult:(JWTCodingResultTypeError *)error { if (self = [super init]) { self.errorResult = error; } return self; } @end ================================================ FILE: Sources/JWT/Coding/JWTCoding+VersionOne.m ================================================ // // JWTCoding+VersionOne.m // JWT // // Created by Lobanov Dmitry on 27.11.16. // Copyright © 2016 JWTIO. All rights reserved. // #import "JWTCoding+VersionOne.h" #import "JWTBase64Coder.h" #import "JWTRSAlgorithm.h" #import "JWTAlgorithmFactory.h" #import "JWTAlgorithmHSBase.h" #import "JWTAlgorithmDataHolder.h" #import "JWTClaimsSetSerializer.h" #import "JWTClaimsSetVerifier.h" #import "JWTErrorDescription.h" static inline void setError(NSError **error, NSError* value) { if (error) { *error = value; } } @implementation JWT (VersionOne) #pragma mark - Private Methods + (NSString *)encodeSegment:(id)theSegment withError:(NSError **)error { NSData *encodedSegmentData = nil; if (theSegment) { encodedSegmentData = [NSJSONSerialization dataWithJSONObject:theSegment options:0 error:error]; } else { // error! NSError *generatedError = [JWTErrorDescription errorWithCode:JWTInvalidSegmentSerializationError]; if (error) { *error = generatedError; } NSLog(@"%@ Could not encode segment: %@", self.class, generatedError.localizedDescription); return nil; } NSString *encodedSegment = nil; if (encodedSegmentData) { encodedSegment = [JWTBase64Coder base64UrlEncodedStringWithData:encodedSegmentData];//[encodedSegmentData base64UrlEncodedString]; } return encodedSegment; } + (NSString *)encodeSegment:(id)theSegment; { NSError *error; return [self encodeSegment:theSegment withError:&error]; } #pragma mark - Public Methods + (NSString *)encodeClaimsSet:(JWTClaimsSet *)theClaimsSet withSecret:(NSString *)theSecret; { return [self encodeClaimsSet:theClaimsSet withSecret:theSecret algorithm:[JWTAlgorithmFactory algorithmByName:JWTAlgorithmNameHS512]]; } + (NSString *)encodeClaimsSet:(JWTClaimsSet *)theClaimsSet withSecret:(NSString *)theSecret algorithm:(id)theAlgorithm; { NSDictionary *payload = [JWTClaimsSetSerializer dictionaryWithClaimsSet:theClaimsSet]; return [self encodePayload:payload withSecret:theSecret algorithm:theAlgorithm]; } + (NSString *)encodePayload:(NSDictionary *)thePayload withSecret:(NSString *)theSecret; { return [self encodePayload:thePayload withSecret:theSecret algorithm:[JWTAlgorithmFactory algorithmByName:JWTAlgorithmNameHS512]]; } + (NSString *)encodePayload:(NSDictionary *)thePayload withSecret:(NSString *)theSecret algorithm:(id)theAlgorithm; { return [self encodePayload:thePayload withSecret:theSecret withHeaders:nil algorithm:theAlgorithm]; } + (NSString *)encodePayload:(NSDictionary *)thePayload withSecret:(NSString *)theSecret withHeaders:(NSDictionary *)theHeaders algorithm:(id)theAlgorithm; { NSError *error = nil; NSString *encodedString = [self encodePayload:thePayload withSecret:theSecret withHeaders:theHeaders algorithm:theAlgorithm withError:&error]; if (error) { // do something } return encodedString; } + (NSString *)encodePayload:(NSDictionary *)thePayload withSecret:(NSString *)theSecret withHeaders:(NSDictionary *)theHeaders algorithm:(id)theAlgorithm withError:(NSError * __autoreleasing *)theError; { NSDictionary *header = @{@"typ": @"JWT", @"alg": theAlgorithm.name}; NSMutableDictionary *allHeaders = [header mutableCopy]; if (theHeaders.allKeys.count) { [allHeaders addEntriesFromDictionary:theHeaders]; } NSString *headerSegment = [self encodeSegment:[allHeaders copy] withError:theError]; if (!headerSegment) { // encode header segment error setError(theError, [JWTErrorDescription errorWithCode:JWTEncodingHeaderError]); return nil; } NSString *payloadSegment = [self encodeSegment:thePayload withError:theError]; if (!payloadSegment) { // encode payment segment error setError(theError, [JWTErrorDescription errorWithCode:JWTEncodingPayloadError]); return nil; } if (!theAlgorithm) { // error setError(theError, [JWTErrorDescription errorWithCode:JWTUnsupportedAlgorithmError]); return nil; } NSString *signingInput = [@[headerSegment, payloadSegment] componentsJoinedByString:@"."]; __auto_type theAlgorithmHolder = [[JWTAlgorithmHolder alloc] initWithAlgorithm:theAlgorithm]; NSData *signedOutputData = [theAlgorithmHolder encodePayload:signingInput withSecret:theSecret]; NSString *signedOutput = [JWTBase64Coder base64UrlEncodedStringWithData:signedOutputData]; return [@[headerSegment, payloadSegment, signedOutput] componentsJoinedByString:@"."]; } #pragma mark - Decode + (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withTrustedClaimsSet:(JWTClaimsSet *)theTrustedClaimsSet withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName { return [self decodeMessage:theMessage withSecret:theSecret withTrustedClaimsSet:theTrustedClaimsSet withError:theError withForcedAlgorithmByName:theAlgorithmName withForcedOption:NO]; } + (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withTrustedClaimsSet:(JWTClaimsSet *)theTrustedClaimsSet withError:(NSError *__autoreleasing *)theError withForcedOption:(BOOL)theForcedOption { return [self decodeMessage:theMessage withSecret:theSecret withTrustedClaimsSet:theTrustedClaimsSet withError:theError withForcedAlgorithmByName:JWTAlgorithmNameHS512 withForcedOption:theForcedOption]; } + (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withTrustedClaimsSet:(JWTClaimsSet *)theTrustedClaimsSet withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName withForcedOption:(BOOL)theForcedOption { return [self decodeMessage:theMessage withSecret:theSecret withTrustedClaimsSet:theTrustedClaimsSet withError:theError withForcedAlgorithmByName:theAlgorithmName withForcedOption:theForcedOption withAlgorithmWhiteList:nil]; } + (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withTrustedClaimsSet:(JWTClaimsSet *)theTrustedClaimsSet withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName withForcedOption:(BOOL)theForcedOption withAlgorithmWhiteList:(NSSet *)theWhitelist { NSDictionary *dictionary = [self decodeMessage:theMessage withSecret:theSecret withError:theError withForcedAlgorithmByName:theAlgorithmName skipVerification:theForcedOption whitelist:theWhitelist]; if (*theError) { // do something return dictionary; } if (theTrustedClaimsSet) { BOOL claimVerified = [JWTClaimsSetVerifier verifyClaimsSet:[JWTClaimsSetSerializer claimsSetWithDictionary:dictionary[@"payload"]] withTrustedClaimsSet:theTrustedClaimsSet]; if (claimVerified) { return dictionary; } else { setError(theError, [JWTErrorDescription errorWithCode:JWTClaimsSetVerificationFailed]); return nil; } } return dictionary; } + (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withError:(NSError *__autoreleasing *)theError withForcedOption:(BOOL)theForcedOption; { return [self decodeMessage:theMessage withSecret:theSecret withError:theError withForcedAlgorithmByName:JWTAlgorithmNameHS512 skipVerification:theForcedOption]; } + (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName; { return [self decodeMessage:theMessage withSecret:theSecret withError:theError withForcedAlgorithmByName:theAlgorithmName skipVerification:NO]; } + (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName skipVerification:(BOOL)skipVerification { return [self decodeMessage:theMessage withSecret:theSecret withError:theError withForcedAlgorithmByName:theAlgorithmName skipVerification:skipVerification whitelist:nil]; } + (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName skipVerification:(BOOL)skipVerification whitelist:(NSSet *)theWhitelist { NSArray *parts = [theMessage componentsSeparatedByString:@"."]; if (parts.count < 3) { // generate error? setError(theError, [JWTErrorDescription errorWithCode:JWTInvalidFormatError]); return nil; } NSString *headerPart = parts[0]; NSString *payloadPart = parts[1]; NSString *signedPart = parts[2]; // decode headerPart NSError *jsonError = nil; NSData *headerData = [JWTBase64Coder dataWithBase64UrlEncodedString:headerPart]; id headerJSON = [NSJSONSerialization JSONObjectWithData:headerData options:0 error:&jsonError]; if (jsonError) { setError(theError, [JWTErrorDescription errorWithCode:JWTDecodingHeaderError]); return nil; } NSDictionary *header = (NSDictionary *)headerJSON; if (!header) { setError(theError, [JWTErrorDescription errorWithCode:JWTNoHeaderError]); return nil; } if (!skipVerification) { // find algorithm //It is insecure to trust the header's value for the algorithm, since //the signature hasn't been verified yet, so an algorithm must be provided if (!theAlgorithmName) { setError(theError, [JWTErrorDescription errorWithCode:JWTUnspecifiedAlgorithmError]); return nil; } NSString *headerAlgorithmName = header[@"alg"]; //If the algorithm in the header doesn't match what's expected, verification fails if (![theAlgorithmName isEqualToString:headerAlgorithmName]) { setError(theError, [JWTErrorDescription errorWithCode:JWTUnsupportedAlgorithmError]); return nil; } //If a whitelist is passed in, ensure the chosen algorithm is allowed if (theWhitelist) { if (![theWhitelist containsObject:theAlgorithmName]) { setError(theError, [JWTErrorDescription errorWithCode:JWTUnsupportedAlgorithmError]); return nil; } } id algorithm = [JWTAlgorithmFactory algorithmByName:theAlgorithmName]; if (!algorithm) { setError(theError, [JWTErrorDescription errorWithCode:JWTUnsupportedAlgorithmError]); return nil; } // Verify the signed part NSString *signingInput = [@[headerPart, payloadPart] componentsJoinedByString:@"."]; __auto_type theAlgorithmHolder = [[JWTAlgorithmHolder alloc] initWithAlgorithm:algorithm]; BOOL signatureValid = [theAlgorithmHolder verifySignedInput:signingInput withSignature:signedPart verificationKey:theSecret]; if (!signatureValid) { setError(theError, [JWTErrorDescription errorWithCode:JWTInvalidSignatureError]); return nil; } } // and decode payload jsonError = nil; NSData *payloadData = [JWTBase64Coder dataWithBase64UrlEncodedString:payloadPart]; id payloadJSON = [NSJSONSerialization JSONObjectWithData:payloadData options:0 error:&jsonError]; if (jsonError) { setError(theError, [JWTErrorDescription errorWithCode:JWTDecodingPayloadError]); return nil; } NSDictionary *payload = (NSDictionary *)payloadJSON; if (!payload) { setError(theError, [JWTErrorDescription errorWithCode:JWTNoPayloadError]); return nil; } NSDictionary *result = @{ @"header" : header, @"payload" : payload }; return result; } + (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withError:(NSError * __autoreleasing *)theError; { return [self decodeMessage:theMessage withSecret:theSecret withError:theError withForcedAlgorithmByName:JWTAlgorithmNameHS512]; } + (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret; { NSError *error = nil; NSDictionary *dictionary = [self decodeMessage:theMessage withSecret:theSecret withError:&error]; if (error) { // do something } return dictionary; } @end ================================================ FILE: Sources/JWT/Coding/JWTCoding+VersionThree.m ================================================ // // JWTCoding+VersionThree.m // JWT // // Created by Lobanov Dmitry on 27.11.16. // Copyright © 2016 JWTIO. All rights reserved. // #import "JWTCoding+VersionThree.h" #import "JWTAlgorithmDataHolderChain.h" #import "JWTRSAlgorithm.h" #import "JWTCoding+ResultTypes.h" #import "JWTAlgorithmFactory.h" #import "JWTErrorDescription.h" #import "JWTBase64Coder.h" #import "JWTClaimsSetsProtocols.h" #import "JWTClaimsSetDSLBase.h" #import "JWTAlgorithmDataHolder+FluentStyle.h" #import "JWTCodingBuilder+FluentStyle.h" static inline void setError(NSError **error, NSError* value) { if (error) { *error = value; } } @implementation JWT (VersionThree) + (JWTEncodingBuilder *)encodeWithHolders:(NSArray *)holders { return [JWTEncodingBuilder createWithHolders:holders]; } + (JWTEncodingBuilder *)encodeWithChain:(JWTAlgorithmDataHolderChain *)chain { return [JWTEncodingBuilder createWithChain:chain]; } + (JWTDecodingBuilder *)decodeWithHolders:(NSArray *)holders { return [JWTDecodingBuilder createWithHolders:holders]; } + (JWTDecodingBuilder *)decodeWithChain:(JWTAlgorithmDataHolderChain *)chain { return [JWTDecodingBuilder createWithChain:chain]; } @end @interface JWTCodingBuilder () #pragma mark - Internal @property (strong, nonatomic, readwrite) JWTAlgorithmDataHolderChain *internalChain; @property (copy, nonatomic, readwrite) NSNumber *internalOptions; @property (strong, nonatomic, readwrite) id internalTokenCoder; @property (strong, nonatomic, readwrite) id internalHashCoder; #pragma mark - Fluent @property (copy, nonatomic, readwrite) JWTCodingBuilder *(^chain)(JWTAlgorithmDataHolderChain *chain); @property (copy, nonatomic, readwrite) JWTCodingBuilder *(^constructChain)(JWTAlgorithmDataHolderChain *(^block)(void)); @property (copy, nonatomic, readwrite) JWTCodingBuilder *(^modifyChain)(JWTAlgorithmDataHolderChain *(^block)(JWTAlgorithmDataHolderChain * chain)); @property (copy, nonatomic, readwrite) JWTCodingBuilder *(^options)(NSNumber *options); @property (copy, nonatomic, readwrite) JWTCodingBuilder *(^addHolder)(id holder); @property (copy, nonatomic, readwrite) JWTCodingBuilder *(^constructHolder)(id(^block)(id holder)); @property (copy, nonatomic, readwrite) JWTCodingBuilder *(^tokenCoder)(id tokenCoder); @end @interface JWTCodingBuilder (Fluent_Setup) - (void)setupFluent; @end @implementation JWTCodingBuilder (Fluent_Setup) - (instancetype)chain:(JWTAlgorithmDataHolderChain *)chain { self.internalChain = chain; return self; } - (instancetype)options:(NSNumber *)options { self.internalOptions = options; return self; } - (instancetype)addHolder:(id)holder { self.internalChain = [self.internalChain chainByAppendingHolder:holder]; return self; } - (instancetype)tokenCoder:(id)tokenCoder { self.internalTokenCoder = tokenCoder; return self; } - (void)setupFluent { __weak typeof(self) weakSelf = self; self.chain = ^(JWTAlgorithmDataHolderChain *chain) { return [weakSelf chain:chain]; }; self.constructChain = ^(JWTAlgorithmDataHolderChain *(^block)(void)) { if (block) { JWTAlgorithmDataHolderChain *chain = block(); return [weakSelf chain:chain]; } return weakSelf; }; self.modifyChain = ^(JWTAlgorithmDataHolderChain *(^block)(JWTAlgorithmDataHolderChain *chain)) { if (block) { JWTAlgorithmDataHolderChain *chain = block(weakSelf.internalChain); return [weakSelf chain:chain]; } return weakSelf; }; self.options = ^(NSNumber *options) { return [weakSelf options:options]; }; self.addHolder = ^(id holder) { return [weakSelf addHolder:holder]; }; self.constructHolder = ^(id (^block)(id holder)) { if (block) { [weakSelf addHolder:block([JWTAlgorithmBaseDataHolder new])]; } return weakSelf; }; self.tokenCoder = ^(id tokenCoder) { return [weakSelf tokenCoder:tokenCoder]; }; } @end @implementation JWTCodingBuilder #pragma mark - Getters // Chain always exists - (JWTAlgorithmDataHolderChain *)internalChain { return _internalChain ?: (_internalChain = [JWTAlgorithmDataHolderChain new]); } #pragma mark - Create - (instancetype)initWithChain:(JWTAlgorithmDataHolderChain *)chain { if (self = [super init]) { self.internalChain = chain; self.internalTokenCoder = [JWTBase64Coder withBase64String]; self.internalHashCoder = [JWTStringCoderForEncoding utf8Encoding]; [self setupFluent]; } return self; } + (instancetype)createWithHolders:(NSArray *)items { return [self createWithChain:[[JWTAlgorithmDataHolderChain alloc] initWithHolders:items]]; } + (instancetype)createWithChain:(JWTAlgorithmDataHolderChain *)chain { return [[self alloc] initWithChain:chain]; } + (instancetype)createWithEmptyChain { return [self createWithChain:nil]; } @end @implementation JWTCodingBuilder (Sugar) - (instancetype)and { return self; } - (instancetype)with { return self; } @end @interface JWTEncodingBuilder () #pragma mark - Internal @property (copy, nonatomic, readwrite) NSDictionary *internalPayload; @property (copy, nonatomic, readwrite) NSDictionary *internalHeaders; @property (strong, nonatomic, readwrite) id internalClaimsSetCoordinator; @property (copy, nonatomic, readwrite) NSDictionary *internalMixingClaimsPayload; #pragma mark - Fluent @property (copy, nonatomic, readwrite) JWTEncodingBuilder *(^payload)(NSDictionary *payload); @property (copy, nonatomic, readwrite) JWTEncodingBuilder *(^headers)(NSDictionary *headers); @property (copy, nonatomic, readwrite) JWTEncodingBuilder *(^claimsSetCoordinator)(id claimsSetCoordinator); @end @implementation JWTEncodingBuilder (Setters) - (instancetype)payload:(NSDictionary *)payload { self.internalPayload = payload; return self; } - (instancetype)headers:(NSDictionary *)headers { self.internalHeaders = headers; return self; } - (instancetype)claimsSetCoordinator:(id)claimsSetCoordinator { self.internalClaimsSetCoordinator = claimsSetCoordinator; return self; } @end @implementation JWTEncodingBuilder (Fluent_Setup) - (void)setupFluent { [super setupFluent]; __weak typeof(self) weakSelf = self; self.payload = ^(NSDictionary *payload) { return [weakSelf payload:payload]; }; self.headers = ^(NSDictionary *headers) { return [weakSelf headers:headers]; }; self.claimsSetCoordinator = ^(id claimsSetCoordinator) { return [weakSelf claimsSetCoordinator:claimsSetCoordinator]; }; } @end @implementation JWTEncodingBuilder #pragma mark - Getters - (NSDictionary *)internalMixingClaimsPayload { NSMutableDictionary *dictionary = [@{} mutableCopy]; if (_internalPayload) { [dictionary addEntriesFromDictionary:_internalPayload]; } if (_internalClaimsSetCoordinator) { __auto_type claimsDictionary = [_internalClaimsSetCoordinator.claimsSetSerializer dictionaryFromClaimsSet:_internalClaimsSetCoordinator.claimsSetStorage]; [dictionary addEntriesFromDictionary:claimsDictionary]; } return dictionary; } #pragma mark - Create + (instancetype)encodePayload:(NSDictionary *)payload { return ((JWTEncodingBuilder *)[self createWithEmptyChain]).payload(payload); } + (instancetype)encodeClaimsSetWithCoordinator:(id)coordinator { return ((JWTEncodingBuilder *)[self createWithEmptyChain]).claimsSetCoordinator(coordinator); } @end @implementation JWTEncodingBuilder (Coding) - (JWTCodingResultType *)encode { NSDictionary *headers = self.internalHeaders; NSDictionary *payload = self.internalMixingClaimsPayload; NSString *encodedMessage = nil; NSError *error = nil; NSArray *holders = self.internalChain.holders; // ERROR: HOLDERS ARE EMPTY. if (holders.count == 0) { error = [JWTErrorDescription errorWithCode:JWTDecodingHoldersChainEmptyError]; } for (id holder in holders) { id algorithm = holder.internalAlgorithm; NSData *secretData = holder.internalSecretData; // BUG: // Read about it in // if ([holder isKindOfClass:JWTAlgorithmRSFamilyDataHolder.class]) { // JWTAlgorithmRSFamilyDataHolder *theHolder = (JWTAlgorithmRSFamilyDataHolder *)holder; // BOOL bugExists = (theHolder.internalSignKey != nil || theHolder.internalVerifyKey != nil ) && secretData == nil; // if (bugExists) { // return [[JWTCodingResultType alloc] initWithErrorResult:[[JWTCodingResultTypeError alloc] initWithError:[JWTErrorDescription errorWithCode:JWTHolderSecretDataNotSetError]]]; // return nil; // } // } encodedMessage = [self encodeWithAlgorithm:algorithm withHeaders:headers withPayload:payload withSecretData:secretData withError:&error]; if (encodedMessage && (error == nil)) { break; } } JWTCodingResultType *result = nil; if (error) { result = [[JWTCodingResultType alloc] initWithErrorResult:[[JWTCodingResultTypeError alloc] initWithError:error]]; } else if (encodedMessage) { result = [[JWTCodingResultType alloc] initWithSuccessResult:[[JWTCodingResultTypeSuccess alloc] initWithEncoded:encodedMessage]]; } else { NSLog(@"%@ something went wrong! result is nil!", self.debugDescription); } return result; } - (NSString *)encodeWithAlgorithm:(id)theAlgorithm withHeaders:(NSDictionary *)theHeaders withPayload:(NSDictionary *)thePayload withSecretData:(NSData *)theSecretData withError:(NSError *__autoreleasing *)theError { // do it! if (!theAlgorithm) { setError(theError, [JWTErrorDescription errorWithCode:JWTUnspecifiedAlgorithmError]); return nil; } NSString *theAlgorithmName = [theAlgorithm name]; if (!theAlgorithmName) { setError(theError, [JWTErrorDescription errorWithCode:JWTUnsupportedAlgorithmError]); return nil; } NSDictionary *header = @{ @"alg": theAlgorithmName, @"typ": @"JWT" }; NSMutableDictionary *allHeaders = [header mutableCopy]; if (theHeaders.allKeys.count > 0) { [allHeaders addEntriesFromDictionary:theHeaders]; } NSString *headerSegment = [self.internalTokenCoder stringWithData:[self encodeSegment:[allHeaders copy] withError:nil]]; if (!headerSegment) { // encode header segment error setError(theError, [JWTErrorDescription errorWithCode:JWTEncodingHeaderError]); return nil; } NSString *payloadSegment = [self.internalTokenCoder stringWithData:[self encodeSegment:thePayload withError:nil]]; if (!payloadSegment) { // encode payment segment error setError(theError, [JWTErrorDescription errorWithCode:JWTEncodingPayloadError]); return nil; } NSString *signingInput = [@[headerSegment, payloadSegment] componentsJoinedByString:@"."]; NSString *signedOutput = nil; // this happens somewhere outside. NSError *algorithmError = nil; if ([theAlgorithm conformsToProtocol:@protocol(JWTRSAlgorithm)]) { theSecretData = theSecretData ?: [NSData data]; } if (theSecretData && [theAlgorithm respondsToSelector:@selector(signHash:key:error:)]) { __auto_type hash = [self.internalHashCoder dataWithString:signingInput]; __auto_type signedOutputData = [theAlgorithm signHash:hash key:theSecretData error:&algorithmError]; signedOutput = [self.internalTokenCoder stringWithData:signedOutputData]; } if (algorithmError) { // algorithmError setError(theError, algorithmError); return nil; } if (!signedOutput) { // Make sure signing worked (e.g. we may have issues extracting the key from the PKCS12 bundle if passphrase is incorrect) setError(theError, [JWTErrorDescription errorWithCode:JWTEncodingSigningError]); return nil; } return [@[headerSegment, payloadSegment, signedOutput] componentsJoinedByString:@"."]; } - (NSData *)encodeSegment:(id)theSegment withError:(NSError *__autoreleasing*)error { NSData *encodedSegmentData = nil; if (theSegment) { encodedSegmentData = [NSJSONSerialization dataWithJSONObject:theSegment options:0 error:error]; } else { // error! NSError *generatedError = [JWTErrorDescription errorWithCode:JWTInvalidSegmentSerializationError]; if (error) { *error = generatedError; } NSLog(@"%@ Could not encode segment: %@", self.class, generatedError.localizedDescription); return nil; } return encodedSegmentData; } - (JWTCodingResultType *)result { return self.encode; } @end @interface JWTDecodingBuilder () #pragma mark - Internal @property (copy, nonatomic, readwrite) NSString *internalMessage; @property (strong, nonatomic, readwrite) id internalClaimsSetCoordinator; #pragma mark - Fluent @property (copy, nonatomic, readwrite) JWTDecodingBuilder *(^message)(NSString *message); @property (copy, nonatomic, readwrite) JWTDecodingBuilder *(^claimsSetCoordinator)(id claimsSetCoordinator); @end @implementation JWTDecodingBuilder (Setters) - (instancetype)message:(NSString *)message { self.internalMessage = message; return self; } - (instancetype)claimsSetCoordinator:(id)claimsSetCoordinator { self.internalClaimsSetCoordinator = claimsSetCoordinator; return self; } @end @implementation JWTDecodingBuilder (Fluent_Setup) - (void)setupFluent { [super setupFluent]; __weak typeof(self) weakSelf = self; self.message = ^(NSString *message) { return [weakSelf message:message]; }; self.claimsSetCoordinator = ^(id claimsSetCoordinator) { return [weakSelf claimsSetCoordinator:claimsSetCoordinator]; }; } @end @implementation JWTDecodingBuilder #pragma mark - Create + (instancetype)decodeMessage:(NSString *)message { return ((JWTDecodingBuilder *)[self createWithEmptyChain]).message(message); } @end @implementation JWTDecodingBuilder (Coding) - (JWTCodingResultType *)decode { // do! // iterate over items in chain! // and return if everything ok! // or return error! __auto_type error = (NSError *)nil; __auto_type decodedDictionary = (NSDictionary *)nil; __auto_type message = self.internalMessage; __auto_type options = self.internalOptions; __auto_type holders = self.internalChain.holders; __auto_type claimsSetCoordinator = self.internalClaimsSetCoordinator; // ERROR: HOLDERS ARE EMPTY. if (holders.count == 0) { error = [JWTErrorDescription errorWithCode:JWTDecodingHoldersChainEmptyError]; } for (id holder in self.internalChain.holders) { // try decode! id algorithm = holder.internalAlgorithm; NSData *secretData = holder.internalSecretData; // try to retrieve passphrase. decodedDictionary = [self decodeMessage:message secretData:secretData algorithm:algorithm options:options error:&error]; if (decodedDictionary && (error == nil)) { break; } } // TODO: claimsSet could be removed. // The claimsSet verification should be computed from payload dictionary. // claimsSet verification. JWTCodingResultType *result = nil; if (error) { return [[JWTCodingResultType alloc] initWithErrorResult:[[JWTCodingResultTypeError alloc] initWithError:error]]; } if (claimsSetCoordinator) { __auto_type untrustedClaimsSet = [claimsSetCoordinator.claimsSetSerializer claimsSetFromDictionary:decodedDictionary[JWTCodingResultComponents.payload]]; __auto_type trustedClaimsSet = claimsSetCoordinator.claimsSetStorage; __auto_type claimsVerified = [claimsSetCoordinator.claimsSetVerifier verifyClaimsSet:untrustedClaimsSet withTrustedClaimsSet:trustedClaimsSet]; if (!claimsVerified) { error = [JWTErrorDescription errorWithCode:JWTClaimsSetVerificationFailed]; return [[JWTCodingResultType alloc] initWithErrorResult:[[JWTCodingResultTypeError alloc] initWithError:error]]; } } if (decodedDictionary) { NSDictionary *headers = decodedDictionary[JWTCodingResultComponents.headers]; NSDictionary *payload = decodedDictionary[JWTCodingResultComponents.payload]; id claimsSetStorage = nil; // extract claims from payload. BOOL shouldExtractClaimsSetCoordinator = YES; // add option later. BOOL extractClaimsSetCoordinator = claimsSetCoordinator != nil || shouldExtractClaimsSetCoordinator; if (extractClaimsSetCoordinator) { claimsSetStorage = [self.internalClaimsSetCoordinator.claimsSetSerializer claimsSetFromDictionary:payload]; } result = [[JWTCodingResultType alloc] initWithSuccessResult:[[[JWTCodingResultTypeSuccess alloc] initWithHeaders:headers withPayload:payload] initWithClaimsSetStorage:claimsSetStorage]]; } else { NSLog(@"%@ something went wrong! result is nil!", self.debugDescription); } return result; } // Maybe later add algorithmName - (NSDictionary *)decodeMessage:(NSString *)theMessage secretData:(NSData *)theSecretData algorithm:(id)theAlgorithm options:(NSNumber *)theOptions error:(NSError *__autoreleasing *)theError { BOOL skipVerification = [theOptions boolValue]; NSString *theAlgorithmName = [theAlgorithm name]; NSArray *parts = [theMessage componentsSeparatedByString:@"."]; if (parts.count < 3) { // generate error? setError(theError, [JWTErrorDescription errorWithCode:JWTInvalidFormatError]); return nil; } NSString *headerPart = parts[0]; NSString *payloadPart = parts[1]; NSString *signaturePart = parts[2]; // decode headerPart NSError *jsonError = nil; NSData *headerData = [self.internalTokenCoder dataWithString:headerPart]; id headerJSON = [NSJSONSerialization JSONObjectWithData:headerData options:0 error:&jsonError]; if (jsonError) { setError(theError, [JWTErrorDescription errorWithCode:JWTDecodingHeaderError]); return nil; } NSDictionary *header = (NSDictionary *)headerJSON; if (!header) { setError(theError, [JWTErrorDescription errorWithCode:JWTNoHeaderError]); return nil; } if (!skipVerification) { // find algorithm //It is insecure to trust the header's value for the algorithm, since //the signature hasn't been verified yet, so an algorithm must be provided if (!theAlgorithmName) { setError(theError, [JWTErrorDescription errorWithCode:JWTUnspecifiedAlgorithmError]); return nil; } NSString *headerAlgorithmName = header[@"alg"]; //If the algorithm in the header doesn't match what's expected, verification fails if (![theAlgorithmName isEqualToString:headerAlgorithmName]) { setError(theError, [JWTErrorDescription errorWithCode:JWTAlgorithmNameMismatchError]); return nil; } // A shit logic, but... // You should copy algorithm if this algorithm conforms to RSAlgorithm (NSCopying). // Now RS Algorithm holds too much. ( All data about keys :/ ) // Need further investigation. id algorithm = nil; if ([theAlgorithm conformsToProtocol:@protocol(JWTRSAlgorithm)]) { algorithm = [(id)theAlgorithm copyWithZone:nil]; theSecretData = theSecretData ?: [NSData data]; } else { algorithm = [JWTAlgorithmFactory algorithmByName:theAlgorithmName]; } if (!algorithm) { setError(theError, [JWTErrorDescription errorWithCode:JWTUnsupportedAlgorithmError]); return nil; } // Verify the signed part NSString *signingInput = [@[headerPart, payloadPart] componentsJoinedByString:@"."]; BOOL signatureValid = NO; NSError *algorithmError = nil; if (theSecretData && [algorithm respondsToSelector:@selector(verifyHash:signature:key:error:)]) { __auto_type hash = [self.internalHashCoder dataWithString:signingInput]; __auto_type signedInputData = [self.internalTokenCoder dataWithString:signaturePart]; signatureValid = [algorithm verifyHash:hash signature:signedInputData key:theSecretData error:&algorithmError]; } if (algorithmError) { setError(theError, algorithmError); return nil; } if (!signatureValid) { setError(theError, [JWTErrorDescription errorWithCode:JWTInvalidSignatureError]); return nil; } } // and decode payload jsonError = nil; NSData *payloadData = [self.internalTokenCoder dataWithString:payloadPart]; id payloadJSON = [NSJSONSerialization JSONObjectWithData:payloadData options:0 error:&jsonError]; if (jsonError) { setError(theError, [JWTErrorDescription errorWithCode:JWTDecodingPayloadError]); return nil; } NSDictionary *payload = (NSDictionary *)payloadJSON; if (!payload) { setError(theError, [JWTErrorDescription errorWithCode:JWTNoPayloadError]); return nil; } NSDictionary *result = @{ JWTCodingResultComponents.headers : header, JWTCodingResultComponents.payload : payload }; setError(theError, nil); return result; } - (JWTCodingResultType *)result { return self.decode; } @end ================================================ FILE: Sources/JWT/Coding/JWTCoding+VersionTwo.m ================================================ // // JWTCoding+VersionTwo.m // JWT // // Created by Lobanov Dmitry on 27.11.16. // Copyright © 2016 JWTIO. All rights reserved. // #import "JWTCoding+VersionTwo.h" #import "JWTBase64Coder.h" #import "JWTRSAlgorithm.h" #import "JWTAlgorithmFactory.h" #import "JWTAlgorithmDataHolder.h" #import "JWTClaimsSetSerializer.h" #import "JWTClaimsSetVerifier.h" #import "JWTErrorDescription.h" static inline void setError(NSError **error, NSError* value) { if (error) { *error = value; } } @implementation JWT (VersionTwo) #pragma mark - Builder + (JWTBuilder *)encodePayload:(NSDictionary *)payload { return [JWTBuilder encodePayload:payload]; } + (JWTBuilder *)encodeClaimsSet:(JWTClaimsSet *)claimsSet { return [JWTBuilder encodeClaimsSet:claimsSet]; } + (JWTBuilder *)decodeMessage:(NSString *)message { return [JWTBuilder decodeMessage:message]; } @end @interface JWTBuilder() @property (copy, nonatomic, readwrite) NSString *jwtMessage; @property (copy, nonatomic, readwrite) NSDictionary *jwtPayload; @property (copy, nonatomic, readwrite) NSDictionary *jwtHeaders; @property (copy, nonatomic, readwrite) JWTClaimsSet *jwtClaimsSet; @property (copy, nonatomic, readwrite) NSArray *jwtDataHolders; @property (copy, nonatomic, readwrite) NSString *jwtSecret; @property (copy, nonatomic, readwrite) NSData *jwtSecretData; @property (copy, nonatomic, readwrite) NSString *jwtPrivateKeyCertificatePassphrase; @property (copy, nonatomic, readwrite) NSError *jwtError; @property (strong, nonatomic, readwrite) id jwtAlgorithm; @property (copy, nonatomic, readwrite) NSString *jwtAlgorithmName; @property (copy, nonatomic, readwrite) NSNumber *jwtOptions; @property (copy, nonatomic, readwrite) NSSet *algorithmWhitelist; @property (copy, nonatomic, readwrite) JWTBuilder *(^message)(NSString *message); @property (copy, nonatomic, readwrite) JWTBuilder *(^payload)(NSDictionary *payload); @property (copy, nonatomic, readwrite) JWTBuilder *(^headers)(NSDictionary *headers); @property (copy, nonatomic, readwrite) JWTBuilder *(^claimsSet)(JWTClaimsSet *claimsSet); @property (copy, nonatomic, readwrite) JWTBuilder *(^secret)(NSString *secret); @property (copy, nonatomic, readwrite) JWTBuilder *(^secretData)(NSData *secretData); @property (copy, nonatomic, readwrite) JWTBuilder *(^privateKeyCertificatePassphrase)(NSString *privateKeyCertificatePassphrase); @property (copy, nonatomic, readwrite) JWTBuilder *(^algorithm)(idalgorithm); @property (copy, nonatomic, readwrite) JWTBuilder *(^algorithmName)(NSString *algorithmName); @property (copy, nonatomic, readwrite) JWTBuilder *(^options)(NSNumber *options); @property (copy, nonatomic, readwrite) JWTBuilder *(^whitelist)(NSArray *whitelist); @property (copy, nonatomic, readwrite) JWTBuilder * (^addDataHolder)(JWTAlgorithmBaseDataHolder *dataHolder); @property (copy, nonatomic, readwrite) JWTBuilder * (^constructDataHolder)(id (^block)(void)); @end @implementation JWTBuilder (Setters) - (instancetype)message:(NSString *)message { self.jwtMessage = message; return self; } - (instancetype)payload:(NSDictionary *)payload { self.jwtPayload = payload; return self; } - (instancetype)headers:(NSDictionary *)headers { self.jwtHeaders = headers; return self; } - (instancetype)claimSet:(JWTClaimsSet *)claimSet { self.jwtClaimsSet = claimSet; return self; } - (instancetype)secret:(NSString *)secret { self.jwtSecret = secret; return self; } - (instancetype)secretData:(NSData *)secretData { self.jwtSecretData = secretData; return self; } - (instancetype)privateKeyCertificatePassphrase:(NSString *)privateKeyCertificatePassphrase { self.jwtPrivateKeyCertificatePassphrase = privateKeyCertificatePassphrase; return self; } - (instancetype)algorithm:(id)algorithm { self.jwtAlgorithm = algorithm; return self; } - (instancetype)algorithmName:(NSString *)algorithmName { self.jwtAlgorithmName = algorithmName; return self; } - (instancetype)options:(NSNumber *)options { self.jwtOptions = options; return self; } - (instancetype)whitelist:(NSArray *)whitelist { if (whitelist) { self.algorithmWhitelist = [NSSet setWithArray:whitelist]; } else { self.algorithmWhitelist = nil; } return self; } - (instancetype)addDataHolder:(JWTAlgorithmBaseDataHolder *)dataHolder { if (dataHolder) { } return self; } @end @implementation JWTBuilder #pragma mark - Getters - (id)jwtAlgorithm { if (!_jwtAlgorithm) { _jwtAlgorithm = [JWTAlgorithmFactory algorithmByName:_jwtAlgorithmName]; } return _jwtAlgorithm; } - (NSDictionary *)jwtPayload { return _jwtClaimsSet ? [JWTClaimsSetSerializer dictionaryWithClaimsSet:_jwtClaimsSet] : _jwtPayload; } #pragma mark - Fluent - (void)setupFluent { __weak typeof(self) weakSelf = self; self.message = ^(NSString *message) { return [weakSelf message:message]; }; self.payload = ^(NSDictionary *payload) { return [weakSelf payload:payload]; }; self.headers = ^(NSDictionary *headers) { return [weakSelf headers:headers]; }; self.claimsSet = ^(JWTClaimsSet *claimSet) { return [weakSelf claimSet:claimSet]; }; self.secret = ^(NSString *secret) { return [weakSelf secret:secret]; }; self.secretData = ^(NSData *secretData) { return [weakSelf secretData:secretData]; }; self.privateKeyCertificatePassphrase = ^(NSString *privateKeyCertificatePassphrase) { return [weakSelf privateKeyCertificatePassphrase:privateKeyCertificatePassphrase]; }; self.algorithm = ^(id algorithm) { return [weakSelf algorithm:algorithm]; }; self.algorithmName = ^(NSString *algorithmName) { return [weakSelf algorithmName:algorithmName]; }; self.options = ^(NSNumber *options) { return [weakSelf options:options]; }; self.whitelist = ^(NSArray *whitelist) { return [weakSelf whitelist:whitelist]; }; self.addDataHolder = ^(JWTAlgorithmBaseDataHolder *holder) { return [weakSelf addDataHolder:holder]; }; self.constructDataHolder = ^(id (^block)(void)) { if (block) { return [weakSelf addDataHolder:block()]; } return weakSelf; }; } #pragma mark - Initialization + (JWTBuilder *)encodePayload:(NSDictionary *)payload { return [[JWTBuilder alloc] init].payload(payload); } + (JWTBuilder *)encodeClaimsSet:(JWTClaimsSet *)claimsSet { return [[JWTBuilder alloc] init].claimsSet(claimsSet); } + (JWTBuilder *)decodeMessage:(NSString *)message { return [[JWTBuilder alloc] init].message(message); } - (instancetype)init { if (self = [super init]) { [self setupFluent]; } return self; } #pragma mark - Encoding/Decoding - (NSString *)encode { NSString *result = nil; self.jwtError = nil; result = [self encodeHelper]; return result; } - (NSDictionary *)decode { NSDictionary *result = nil; self.jwtError = nil; result = [self decodeHelper]; return result; } #pragma mark - Private #pragma mark - Encode Helpers - (NSString *)encodeHelper { if (!self.jwtAlgorithm) { self.jwtError = [JWTErrorDescription errorWithCode:JWTUnspecifiedAlgorithmError]; return nil; } NSDictionary *header = @{@"typ": @"JWT", @"alg": self.jwtAlgorithm.name}; NSMutableDictionary *allHeaders = [header mutableCopy]; if (self.jwtHeaders.allKeys.count > 0) { [allHeaders addEntriesFromDictionary:self.jwtHeaders]; } NSString *headerSegment = [self encodeSegment:[allHeaders copy] withError:nil]; if (!headerSegment) { // encode header segment error self.jwtError = [JWTErrorDescription errorWithCode:JWTEncodingHeaderError]; return nil; } NSString *payloadSegment = [self encodeSegment:self.jwtPayload withError:nil]; if (!payloadSegment) { // encode payment segment error self.jwtError = [JWTErrorDescription errorWithCode:JWTEncodingPayloadError]; return nil; } NSString *signingInput = [@[headerSegment, payloadSegment] componentsJoinedByString:@"."]; NSString *signedOutput; if ([self.jwtAlgorithm conformsToProtocol:@protocol(JWTRSAlgorithm)]) { id jwtRsAlgorithm = (id ) self.jwtAlgorithm; jwtRsAlgorithm.privateKeyCertificatePassphrase = self.jwtPrivateKeyCertificatePassphrase; } __auto_type theAlgorithmHolder = [[JWTAlgorithmHolder alloc] initWithAlgorithm:self.jwtAlgorithm]; if (self.jwtSecretData && [theAlgorithmHolder respondsToSelector:@selector(encodePayloadData:withSecret:)]) { NSData *signedOutputData = [theAlgorithmHolder encodePayloadData:[signingInput dataUsingEncoding:NSUTF8StringEncoding] withSecret:self.jwtSecretData]; signedOutput = [JWTBase64Coder base64UrlEncodedStringWithData:signedOutputData]; } else { NSData *signedOutputData = [theAlgorithmHolder encodePayload:signingInput withSecret:self.jwtSecret]; signedOutput = [JWTBase64Coder base64UrlEncodedStringWithData:signedOutputData]; } if (signedOutput) { // Make sure signing worked (e.g. we may have issues extracting the key from the PKCS12 bundle if passphrase is incorrect) return [@[headerSegment, payloadSegment, signedOutput] componentsJoinedByString:@"."]; } else { self.jwtError = [JWTErrorDescription errorWithCode:JWTEncodingSigningError]; return nil; } } - (NSString *)encodeSegment:(id)theSegment withError:(NSError **)error { NSData *encodedSegmentData = nil; if (theSegment) { encodedSegmentData = [NSJSONSerialization dataWithJSONObject:theSegment options:0 error:error]; } else { // error! NSError *generatedError = [JWTErrorDescription errorWithCode:JWTInvalidSegmentSerializationError]; if (error) { *error = generatedError; } NSLog(@"%@ Could not encode segment: %@", self.class, generatedError.localizedDescription); return nil; } NSString *encodedSegment = nil; if (encodedSegmentData) { encodedSegment = [JWTBase64Coder base64UrlEncodedStringWithData:encodedSegmentData]; } return encodedSegment; } #pragma mark - Decode Helpers - (NSDictionary *)decodeHelper { NSError *error = nil; NSDictionary *dictionary = [self decodeMessage:self.jwtMessage withSecret:self.jwtSecret withSecretData:self.jwtSecretData withError:&error withForcedAlgorithmByName:self.jwtAlgorithmName skipVerification:[self.jwtOptions boolValue] whitelist:self.algorithmWhitelist]; if (error) { self.jwtError = error; return nil; } if (self.jwtClaimsSet) { BOOL claimVerified = [JWTClaimsSetVerifier verifyClaimsSet:[JWTClaimsSetSerializer claimsSetWithDictionary:dictionary[@"payload"]] withTrustedClaimsSet:self.jwtClaimsSet]; if (claimVerified) { return dictionary; } else { self.jwtError = [JWTErrorDescription errorWithCode:JWTClaimsSetVerificationFailed]; return nil; } } return dictionary; } - (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withSecretData:(NSData *)secretData withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName skipVerification:(BOOL)skipVerification { NSArray *parts = [theMessage componentsSeparatedByString:@"."]; if (parts.count < 3) { // generate error? setError(theError, [JWTErrorDescription errorWithCode:JWTInvalidFormatError]); return nil; } NSString *headerPart = parts[0]; NSString *payloadPart = parts[1]; NSString *signedPart = parts[2]; // decode headerPart NSError *jsonError = nil; NSData *headerData = [JWTBase64Coder dataWithBase64UrlEncodedString:headerPart]; id headerJSON = [NSJSONSerialization JSONObjectWithData:headerData options:0 error:&jsonError]; if (jsonError) { setError(theError, [JWTErrorDescription errorWithCode:JWTDecodingHeaderError]); return nil; } NSDictionary *header = (NSDictionary *)headerJSON; if (!header) { setError(theError, [JWTErrorDescription errorWithCode:JWTNoHeaderError]); return nil; } if (!skipVerification) { // find algorithm //It is insecure to trust the header's value for the algorithm, since //the signature hasn't been verified yet, so an algorithm must be provided if (!theAlgorithmName) { setError(theError, [JWTErrorDescription errorWithCode:JWTUnspecifiedAlgorithmError]); return nil; } NSString *headerAlgorithmName = header[@"alg"]; //If the algorithm in the header doesn't match what's expected, verification fails if (![theAlgorithmName isEqualToString:headerAlgorithmName]) { setError(theError, [JWTErrorDescription errorWithCode:JWTAlgorithmNameMismatchError]); return nil; } id algorithm = [JWTAlgorithmFactory algorithmByName:theAlgorithmName]; if (!algorithm) { setError(theError, [JWTErrorDescription errorWithCode:JWTUnsupportedAlgorithmError]); return nil; // NSAssert(!algorithm, @"Can't decode segment!, %@", header); } // Verify the signed part NSString *signingInput = [@[headerPart, payloadPart] componentsJoinedByString:@"."]; BOOL signatureValid = NO; __auto_type theAlgorithmHolder = [[JWTAlgorithmHolder alloc] initWithAlgorithm:algorithm]; if (secretData && [theAlgorithmHolder respondsToSelector:@selector(verifySignedInput:withSignature:verificationKeyData:)]) { signatureValid = [theAlgorithmHolder verifySignedInput:signingInput withSignature:signedPart verificationKeyData:secretData]; } else { signatureValid = [theAlgorithmHolder verifySignedInput:signingInput withSignature:signedPart verificationKey:theSecret]; } if (!signatureValid) { setError(theError, [JWTErrorDescription errorWithCode:JWTInvalidSignatureError]); return nil; } } // and decode payload jsonError = nil; NSData *payloadData = [JWTBase64Coder dataWithBase64UrlEncodedString:payloadPart]; id payloadJSON = [NSJSONSerialization JSONObjectWithData:payloadData options:0 error:&jsonError]; if (jsonError) { setError(theError, [JWTErrorDescription errorWithCode:JWTDecodingPayloadError]); return nil; } NSDictionary *payload = (NSDictionary *)payloadJSON; if (!payload) { setError(theError, [JWTErrorDescription errorWithCode:JWTNoPayloadError]); return nil; } NSDictionary *result = @{ @"header" : header, @"payload" : payload }; return result; } - (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withSecretData:(NSData *)secretData withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName skipVerification:(BOOL)skipVerification whitelist:(NSSet *)theWhitelist { /* many cases: 1. whitelist 1, algorithm 1, match 1 everything fine, match exists. just decode by algorithm name. 2. whitelist 1, algorithm 0 // match not needed. use every algorithm and try to decode. 3. whitelist 1, algorithm 1, match 0 throw black list error. 4. whitelist 0 normal decode by algorithm. */ if (theWhitelist) { if (!theAlgorithmName) { // name -> decoding NSMutableArray *tries = [@[] mutableCopy]; NSMutableDictionary *result = nil; for (NSString *name in theWhitelist) { // special case for none algorithm. // none algorithm uses // maybe remove later? NSDictionary *try = nil; if ([name isEqualToString:@"none"]) { try = [self decodeMessage:theMessage withSecret:nil withSecretData:nil withError:theError withForcedAlgorithmByName:name skipVerification:skipVerification]; } else { try = [self decodeMessage:theMessage withSecret:theSecret withSecretData:secretData withError:theError withForcedAlgorithmByName:name skipVerification:skipVerification]; } if (try) { result = [try mutableCopy]; result[@"tries"] = [tries copy]; setError(theError, nil); break; } else { if (theError && *theError) { [tries addObject:*theError]; } } } return [result copy]; } else { //If a whitelist is passed in, ensure the chosen algorithm is allowed if (![theWhitelist containsObject:theAlgorithmName]) { setError(theError, [JWTErrorDescription errorWithCode:JWTBlacklistedAlgorithmError]); return nil; } } } return [self decodeMessage:theMessage withSecret:theSecret withSecretData:secretData withError:theError withForcedAlgorithmByName:theAlgorithmName skipVerification:skipVerification]; } @end ================================================ FILE: Sources/JWT/Coding/JWTCoding.m ================================================ // // JWT.m // JWT // // Created by Klaas Pieter Annema on 31-05-13. // Copyright (c) 2013 Karma. All rights reserved. // #import "JWTCoding.h" @implementation JWT @end ================================================ FILE: Sources/JWT/Coding/JWTCodingBuilder+FluentStyle.m ================================================ // // JWTCodingBuilder+FluentStyle.m // JWT // // Created by Dmitry Lobanov on 07/06/2019. // Copyright © 2019 JWTIO. All rights reserved. // #import "JWTCodingBuilder+FluentStyle.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wobjc-property-implementation" @implementation JWTCodingBuilder (FluentStyle) @end @implementation JWTEncodingBuilder (FluentStyle) @end @implementation JWTDecodingBuilder (FluentStyle) @end #pragma clang diagnostic pop ================================================ FILE: Sources/JWT/Supplement/JWTBase64Coder.m ================================================ // // JWTBase64Coder.m // Pods // // Created by Lobanov Dmitry on 05.10.16. // // #import "JWTBase64Coder.h" #ifndef HAS_INCLUDE_MF_Base64Additions_AS_FRAMEWORK #define HAS_INCLUDE_MF_Base64Additions_AS_FRAMEWORK (__has_include()) #endif #ifndef HAS_INCLUDE_MF_Base64Additions_AS_PLAIN_LIBRARY #define HAS_INCLUDE_MF_Base64Additions_AS_PLAIN_LIBRARY (__has_include("MF_Base64Additions.h")) #endif #ifndef HAS_INCLUDE_MF_Base64Additions #define HAS_INCLUDE_MF_Base64Additions (HAS_INCLUDE_MF_Base64Additions_AS_FRAMEWORK || HAS_INCLUDE_MF_Base64Additions_AS_PLAIN_LIBRARY) #endif #if HAS_INCLUDE_MF_Base64Additions_AS_FRAMEWORK #import #elif HAS_INCLUDE_MF_Base64Additions_AS_PLAIN_LIBRARY #import "MF_Base64Additions.h" #endif @interface JWTBase64Coder () @property (assign, nonatomic, readwrite) BOOL isBase64String; @end @implementation JWTBase64Coder + (instancetype)withBase64String { JWTBase64Coder* coder = [[self alloc] init]; coder.isBase64String = YES; return coder; } + (instancetype)withPlainString { JWTBase64Coder* coder = [[self alloc] init]; coder.isBase64String = NO; return coder; } + (NSString *)base64UrlEncodedStringWithData:(NSData *)data { #if HAS_INCLUDE_MF_Base64Additions if ([data respondsToSelector:@selector(base64UrlEncodedString)]) { return [data performSelector:@selector(base64UrlEncodedString)]; } #endif return [data base64EncodedStringWithOptions:0]; } + (NSData *)dataWithBase64UrlEncodedString:(NSString *)urlEncodedString { #if HAS_INCLUDE_MF_Base64Additions if ([[NSData class] respondsToSelector:@selector(dataWithBase64UrlEncodedString:)]) { return [[NSData class] performSelector:@selector(dataWithBase64UrlEncodedString:) withObject:urlEncodedString]; } #endif return [[NSData alloc] initWithBase64EncodedString:urlEncodedString options:0]; } @end @implementation JWTBase64Coder (JWTStringCoderProtocol) - (NSString *)stringWithData:(NSData *)data { NSString *result = nil; if (self.isBase64String) { result = [self.class base64UrlEncodedStringWithData:data]; } else { result = [self.class base64UrlEncodedStringWithData:data]; } return result; } - (NSData *)dataWithString:(NSString *)string { NSData *result = nil; if (self.isBase64String) { result = [self.class dataWithBase64UrlEncodedString:string]; } else { result = [self.class dataWithBase64UrlEncodedString:[[string dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0]]; } return result; } @end @implementation JWTStringCoderForEncoding + (instancetype)utf8Encoding { __auto_type coding = (JWTStringCoderForEncoding *)[self new]; coding.stringEncoding = NSUTF8StringEncoding; return coding; } @end @implementation JWTStringCoderForEncoding (JWTStringCoderProtocol) - (NSString *)stringWithData:(NSData *)data { return [[NSString alloc] initWithData:data encoding:self.stringEncoding]; } - (NSData *)dataWithString:(NSString *)string { return [string dataUsingEncoding:self.stringEncoding]; } @end ================================================ FILE: Sources/JWT/Supplement/JWTErrorDescription.m ================================================ // // JWTErrorDescription.m // JWT // // Created by Lobanov Dmitry on 27.11.16. // Copyright © 2016 JWTIO. All rights reserved. // #import "JWTErrorDescription.h" NSString *JWTErrorDomain = @"io.jwt"; @implementation JWTErrorDescription + (NSDictionary *)userDescriptionsAndCodes { static NSDictionary *userDescriptionsAndCodes = nil; return userDescriptionsAndCodes ?: (userDescriptionsAndCodes = @{ @(JWTUnexpectedError): @"JWT unexpected error", @(JWTInvalidFormatError): @"Invalid format! Try to check your encoding algorithm. Maybe you put too many dots as delimiters?", @(JWTUnsupportedAlgorithmError): @"Unsupported algorithm! You could implement it by yourself", @(JWTAlgorithmNameMismatchError): @"Algorithm doesn't match name in header.", @(JWTInvalidSignatureError): @"Invalid signature! It seems that signed part of jwt mismatch generated part by algorithm provided in header.", @(JWTNoPayloadError): @"No payload! Hey, forget payload?", @(JWTNoHeaderError): @"No header! Hmm", @(JWTEncodingHeaderError): @"It seems that header encoding failed", @(JWTEncodingPayloadError): @"It seems that payload encoding failed", @(JWTEncodingSigningError): @"It seems that signing output corrupted. Make sure signing worked (e.g. we may have issues extracting the key from the PKCS12 bundle if passphrase is incorrect).", @(JWTClaimsSetVerificationFailed): @"It seems that claims verification failed", @(JWTInvalidSegmentSerializationError): @"It seems that json serialization failed for segment", @(JWTUnspecifiedAlgorithmError): @"Unspecified algorithm! You must explicitly choose an algorithm to decode with.", @(JWTBlacklistedAlgorithmError): @"Algorithm in blacklist? Try to check whitelist parameter", @(JWTDecodingHeaderError): @"Error decoding the JWT Header segment.", @(JWTDecodingPayloadError): @"Error decoding the JWT Payload segment.", @(JWTDecodingHoldersChainEmptyError): @"Error decoding the JWT algorithm and data holders chain is empty!", @(JWTHolderSecretDataNotSetError): @"Error encoding/decoding .secretData not set when using sign/verify keys. Bug. Workaround is simple. Set secretData: { holder.secretData([NSData data]); }" }); } + (NSDictionary *)errorDescriptionsAndCodes { static NSDictionary *errorDescriptionsAndCodes = nil; return errorDescriptionsAndCodes ?: (errorDescriptionsAndCodes = @{ @(JWTUnexpectedError): @"JWTUnexpectedError", @(JWTInvalidFormatError): @"JWTInvalidFormatError", @(JWTUnsupportedAlgorithmError): @"JWTUnsupportedAlgorithmError", @(JWTAlgorithmNameMismatchError): @"JWTAlgorithmNameMismatchError", @(JWTInvalidSignatureError): @"JWTInvalidSignatureError", @(JWTNoPayloadError): @"JWTNoPayloadError", @(JWTNoHeaderError): @"JWTNoHeaderError", @(JWTEncodingHeaderError): @"JWTEncodingHeaderError", @(JWTEncodingPayloadError): @"JWTEncodingPayloadError", @(JWTEncodingSigningError): @"JWTEncodingSigningError", @(JWTClaimsSetVerificationFailed): @"JWTClaimsSetVerificationFailed", @(JWTInvalidSegmentSerializationError): @"JWTInvalidSegmentSerializationError", @(JWTUnspecifiedAlgorithmError): @"JWTUnspecifiedAlgorithmError", @(JWTBlacklistedAlgorithmError): @"JWTBlacklistedAlgorithmError", @(JWTDecodingHeaderError): @"JWTDecodingHeaderError", @(JWTDecodingPayloadError): @"JWTDecodingPayloadError", @(JWTDecodingHoldersChainEmptyError): @"JWTDecodingHoldersChainEmptyError", @(JWTHolderSecretDataNotSetError): @"JWTHolderSecretDataNotSetError" }); } + (NSString *)userDescriptionForCode:(JWTError)code { NSString *resultString = [self userDescriptionsAndCodes][@(code)]; return resultString ?: @"Unexpected error"; } + (NSString *)errorDescriptionForCode:(JWTError)code { NSString *resultString = [self errorDescriptionsAndCodes][@(code)]; return resultString ?: @"JWTUnexpectedError"; } + (NSError *)errorWithCode:(JWTError)code { return [self errorWithCode:code withUserDescription:[self userDescriptionForCode:code] withErrorDescription:[self errorDescriptionForCode:code]]; } + (NSError *)errorWithCode:(NSInteger)code withUserDescription:(NSString *)userDescription withErrorDescription:(NSString *)errorDescription { return [NSError errorWithDomain:JWTErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey: userDescription, @"errorDescription": errorDescription}]; } @end ================================================ FILE: Sources/JWT/include/JWTAlgorithm.h ================================================ // // JWTAlgorithm.h // JWT // // Created by Klaas Pieter Annema on 31-05-13. // Copyright (c) 2013 Karma. All rights reserved. // #import #import "JWTDeprecations.h" @protocol JWTAlgorithm @required /** Signs data using provided secret data. @param hash The data to sign. @param key The secret to use for signing. @param error The error. */ - (NSData *)signHash:(NSData *)hash key:(NSData *)key error:(NSError *__autoreleasing*)error; /** Verifies data using key. @param hash The data to verify. @param signature The secret to use for verifying. @param key The key to verify data. @param error The error. */ - (BOOL)verifyHash:(NSData *)hash signature:(NSData *)signature key:(NSData *)key error:(NSError *__autoreleasing*)error; //@required @property (nonatomic, readonly, copy) NSString *name; @optional /** Encodes and encrypts the provided payload using the provided secret key @param theString The string to encode @param theSecret The secret to use for encryption @return An NSData object containing the encrypted payload, or nil if something went wrong. */ - (NSData *)encodePayload:(NSString *)theString withSecret:(NSString *)theSecret __deprecated_and_will_be_removed_in_release_version(JWTVersion_3_0_0); /** Verifies the provided signature using the signed input and verification key @param input The header and payload encoded string @param signature The JWT provided signature @param verificationKey The key to use for verifying the signature @return YES if the provided signature is valid, NO otherwise */ - (BOOL)verifySignedInput:(NSString *)input withSignature:(NSString *)signature verificationKey:(NSString *)verificationKey __deprecated_and_will_be_removed_in_release_version(JWTVersion_3_0_0); @optional /** Encodes and encrypts the provided payload using the provided secret key @param theStringData The data to encode @param theSecretData The secret data to use for encryption @return An NSData object containing the encrypted payload, or nil if something went wrong. */ - (NSData *)encodePayloadData:(NSData *)theStringData withSecret:(NSData *)theSecretData __deprecated_and_will_be_removed_in_release_version(JWTVersion_3_0_0); /** Verifies the provided signature using the signed input and verification key (as data) @param input The header and payload encoded string @param signature The JWT provided signature @param verificationKeyData The key data to use for verifying the signature @return YES if the provided signature is valid, NO otherwise */ - (BOOL)verifySignedInput:(NSString *)input withSignature:(NSString *)signature verificationKeyData:(NSData *)verificationKeyData __deprecated_and_will_be_removed_in_release_version(JWTVersion_3_0_0); @end ================================================ FILE: Sources/JWT/include/JWTAlgorithmAsymmetricBase.h ================================================ // // JWTAlgorithmAsymmetricBase.h // Base64 // // Created by Lobanov Dmitry on 12.03.2018. // #import #import "JWTRSAlgorithm.h" #import "JWTAlgorithmErrorDescription.h" extern NSString *const JWTAlgorithmAsymmetricFamilyErrorDomain; typedef NS_ENUM(NSInteger, JWTAlgorithmAsymmetricFamilyError) { JWTAlgorithmAsymmetricFamilyErrorInternalSecurityAPI = -98, JWTAlgorithmAsymmetricFamilyErrorAlgorithmIsNotSupported = -50, JWTAlgorithmAsymmetricFamilyErrorUnexpected = -20 }; @interface JWTAlgorithmAsymmetricFamilyErrorDescription : JWTAlgorithmErrorDescription @end @interface JWTAlgorithmAsymmetricBase : NSObject @end @interface JWTAlgorithmAsymmetricBase (JWTAsymmetricKeysAlgorithm) @end @interface JWTAlgorithmAsymmetricBase (Create) // default. + (instancetype)withRS; + (instancetype)withES; + (instancetype)withPS API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0)); - (instancetype)with256; - (instancetype)with384; - (instancetype)with512; @end ================================================ FILE: Sources/JWT/include/JWTAlgorithmDataHolder+FluentStyle.h ================================================ // // JWTAlgorithmDataHolder+FluentStyle.h // JWT // // Created by Dmitry Lobanov on 07/06/2019. // Copyright © 2019 JWTIO. All rights reserved. // #import "JWTAlgorithmDataHolder.h" #import "JWTDeprecations.h" #if DEPLOYMENT_RUNTIME_SWIFT #else NS_ASSUME_NONNULL_BEGIN // Fluent ( Objective-C exclusive ). @interface JWTAlgorithmBaseDataHolder (FluentStyle) /** Sets jwtSecret and returns the JWTAlgorithmBaseDataHolder to allow for method chaining */ @property (copy, nonatomic, readonly) JWTAlgorithmBaseDataHolder *(^secret)(NSString *secret) NS_SWIFT_UNAVAILABLE(""); /** Sets jwtSecretData and returns the JWTAlgorithmBaseDataHolder to allow for method chaining */ @property (copy, nonatomic, readonly) JWTAlgorithmBaseDataHolder *(^secretData)(NSData *secretData) NS_SWIFT_UNAVAILABLE(""); /** Sets jwtAlgorithm and returns the JWTAlgorithmBaseDataHolder to allow for method chaining */ @property (copy, nonatomic, readonly) JWTAlgorithmBaseDataHolder *(^algorithm)(idalgorithm) NS_SWIFT_UNAVAILABLE(""); /** Sets jwtAlgorithmName and returns the JWTAlgorithmBaseDataHolder to allow for method chaining. See list of names in appropriate headers. */ @property (copy, nonatomic, readonly) JWTAlgorithmBaseDataHolder *(^algorithmName)(NSString *algorithmName) NS_SWIFT_UNAVAILABLE(""); /** Sets stringCoder and returns the JWTAlgorithmBaseDataHolder to allow for method chaining. See list of names in appropriate headers. */ @property (copy, nonatomic, readonly) JWTAlgorithmBaseDataHolder *(^stringCoder)(id stringCoder) NS_SWIFT_UNAVAILABLE(""); @end @interface JWTAlgorithmRSFamilyDataHolder (FluentStyle) /** Sets jwtPrivateKeyCertificatePassphrase and returns the JWTAlgorithmRSFamilyDataHolder to allow for method chaining */ @property (copy, nonatomic, readonly) JWTAlgorithmRSFamilyDataHolder *(^privateKeyCertificatePassphrase)(NSString *privateKeyCertificatePassphrase) NS_SWIFT_UNAVAILABLE(""); @property (copy, nonatomic, readonly) JWTAlgorithmRSFamilyDataHolder *(^keyExtractorType)(NSString *keyExtractorType) NS_SWIFT_UNAVAILABLE(""); // BUG: // If you set sign/verify keys, you should also set .secretData([NSData data]); // Yes, this is a bug. // Please, set it. @property (copy, nonatomic, readonly) JWTAlgorithmRSFamilyDataHolder *(^signKey)(id signKey) NS_SWIFT_UNAVAILABLE(""); @property (copy, nonatomic, readonly) JWTAlgorithmRSFamilyDataHolder *(^verifyKey)(id verifyKey) NS_SWIFT_UNAVAILABLE(""); @end NS_ASSUME_NONNULL_END #endif ================================================ FILE: Sources/JWT/include/JWTAlgorithmDataHolder.h ================================================ // // JWTAlgorithmDataHolder.h // JWT // // Created by Lobanov Dmitry on 31.08.16. // Copyright © 2016 Karma. All rights reserved. // #import #import "JWTAlgorithm.h" #import "JWTDeprecations.h" #import "JWTBase64Coder.h" // TODO: available in 3.0 // All methods with secret as NSString in algorithms will be deprecated or removed. @protocol JWTAlgorithmDataHolderProtocol /** The verification key to use when encoding/decoding a JWT in data form */ @property (copy, nonatomic, readwrite) NSData *internalSecretData; /** The to use for encoding a JWT */ @property (strong, nonatomic, readwrite) id internalAlgorithm; /** The string coder. It converts data to string and vice versa. Used only for secret <-> secretData conversions. */ @property (strong, nonatomic, readwrite) id internalStringCoder; @end @interface JWTAlgorithmBaseDataHolder : NSObject #pragma mark - Getters /** The verification key to use when encoding/decoding a JWT */ @property (copy, nonatomic, readonly) NSString *internalSecret; /** The algorithm name to use for decoding the JWT. Required unless force decode is true */ @property (copy, nonatomic, readonly) NSString *internalAlgorithmName; @end // Available in Swift and Objective-C. @interface JWTAlgorithmBaseDataHolder (Setters) - (instancetype)secretData:(NSData *)secretData; - (instancetype)secret:(NSString *)secret; - (instancetype)algorithm:(id)algorithm; - (instancetype)algorithmName:(NSString *)algorithmName; - (instancetype)stringCoder:(id)stringCoder; @end @protocol JWTAlgorithmDataHolderCreateProtocol + (instancetype)createWithAlgorithm256; + (instancetype)createWithAlgorithm384; + (instancetype)createWithAlgorithm512; @end @interface JWTAlgorithmNoneDataHolder : JWTAlgorithmBaseDataHolder @end /* Default stringCoder is [JWTBase64Coder withPlainString]. You could set secretData by secret setter ( holder.secret(secretString) ) in plain format e.g. "secret". */ @interface JWTAlgorithmHSFamilyDataHolder : JWTAlgorithmBaseDataHolder @end @protocol JWTCryptoKeyProtocol; /* JWTAlgorithmRSFamilyDataHolder actually is JWTAlgorithmAsymmetricTypeDataHolder. It will be renamed later. */ @interface JWTAlgorithmRSFamilyDataHolder : JWTAlgorithmBaseDataHolder /* Default stringCoder is [JWTBase64Coder withBase64String]. You could set secretData by secret setter ( holder.secret(secretString) ) in base64 format e.g. put pem file content in it (ugly string with equal sign at the end for example). */ @end @interface JWTAlgorithmRSFamilyDataHolder (Getters) /** The passphrase for the PKCS12 blob, which represents the certificate containing the private key for the RS algorithms. */ @property (copy, nonatomic, readonly) NSString *internalPrivateKeyCertificatePassphrase; @property (copy, nonatomic, readonly) NSString *internalKeyExtractorType; @property (strong, nonatomic, readonly) id internalSignKey; @property (strong, nonatomic, readonly) id internalVerifyKey; @end // Available in Swift and Objective-C. @interface JWTAlgorithmRSFamilyDataHolder (Setters) - (instancetype)privateKeyCertificatePassphrase:(NSString *)passphrase; - (instancetype)keyExtractorType:(NSString *)type; - (instancetype)signKey:(id)key; - (instancetype)verifyKey:(id)key; @end ================================================ FILE: Sources/JWT/include/JWTAlgorithmDataHolderChain.h ================================================ // // JWTAlgorithmDataHolderChain.h // JWT // // Created by Lobanov Dmitry on 02.10.16. // Copyright © 2016 Karma. All rights reserved. // #import #import "JWTAlgorithmDataHolder.h" @interface JWTAlgorithmDataHolderChain : NSObject @property (strong, nonatomic, readonly) NSArray *holders; #pragma mark - Initialization - (instancetype)initWithHolders:(NSArray *)holders; - (instancetype)initWithHolder:(id)holder; #pragma mark - Appending - (instancetype)chainByAppendingChain:(JWTAlgorithmDataHolderChain *)chain; - (instancetype)chainByAppendingHolders:(NSArray *)holders; - (instancetype)chainByAppendingHolder:(id)holder; #pragma mark - Create + (instancetype)chainWithHolders:(NSArray *)holders; + (instancetype)chainWithHolder:(id)holder; @end @interface JWTAlgorithmDataHolderChain (HoldersPopulation) - (NSArray *)singleAlgorithm:(id)algorithm withManySecretData:(NSArray *)secretsData; - (NSArray *)singleSecretData:(NSData *)secretData withManyAlgorithms:(NSArray *)algorithms; - (instancetype)chainByPopulatingAlgorithm:(id)algorithm withManySecretData:(NSArray *)secretsData; - (instancetype)chainByPopulatingSecretData:(NSData *)secretData withManyAlgorithms:(NSArray *)algorithms; @end ================================================ FILE: Sources/JWT/include/JWTAlgorithmESBase.h ================================================ // // JWTAlgorithmESBase.h // Pods // // Created by Lobanov Dmitry on 12.02.17. // // #import #import "JWTRSAlgorithm.h" extern NSString *const JWTAlgorithmNameES256; extern NSString *const JWTAlgorithmNameES384; extern NSString *const JWTAlgorithmNameES512; @interface JWTAlgorithmESBase : NSObject @end @interface JWTAlgorithmESBase (JWTAsymmetricKeysAlgorithm) @end @interface JWTAlgorithmESBase (Create) + (instancetype)algorithm256; + (instancetype)algorithm384; + (instancetype)algorithm512; @end ================================================ FILE: Sources/JWT/include/JWTAlgorithmErrorDescription+Subclass.h ================================================ // // JWTAlgorithmErrorDescription+Subclass.h // JWT // // Created by Dmitry on 7/29/18. // Copyright © 2018 JWTIO. All rights reserved. // #import "JWTAlgorithmErrorDescription.h" @interface JWTAlgorithmErrorDescription (Subclass) + (NSString *)errorDomain; // Default error code. // UnexpectedError for example. + (NSInteger)defaultErrorCode; // Well, the code for internal error wrapper. // in Swift equivalent is: // case .internalError(let internalError): + (NSInteger)externalCodeForInternalError; // Mapping errorCode -> NSLocalizedDescriptionKey + (NSDictionary *)codesAndUserDescriptions; // Mapping errorCode -> Description. // in Swift equivalent is: // StringConvertable or enum with String value. + (NSDictionary *)codesAndDescriptions; @end ================================================ FILE: Sources/JWT/include/JWTAlgorithmErrorDescription.h ================================================ // // JWTAlgorithmErrorDescription.h // JWT // // Created by Dmitry on 7/29/18. // Copyright © 2018 JWTIO. All rights reserved. // #import @interface JWTAlgorithmErrorDescription : NSObject + (NSError *)errorWithCode:(NSInteger)code; + (NSError *)errorWithExternalError:(NSError *)error; @end ================================================ FILE: Sources/JWT/include/JWTAlgorithmFactory.h ================================================ // // JWTAlgorithmFactory.h // JWT // // Created by Lobanov Dmitry on 07.10.15. // Copyright © 2015 Karma. All rights reserved. // #import #import "JWTAlgorithm.h" @interface JWTAlgorithmHolder : NSObject @property (strong, nonatomic, readwrite) id algorithm; - (instancetype)initWithAlgorithm:(id)algorithm; // For backward compatibilty - (NSData *)encodePayload:(NSString *)theString withSecret:(NSString *)theSecret; - (BOOL)verifySignedInput:(NSString *)input withSignature:(NSString *)signature verificationKey:(NSString *)verificationKey; - (NSData *)encodePayloadData:(NSData *)theStringData withSecret:(NSData *)theSecretData; - (BOOL)verifySignedInput:(NSString *)input withSignature:(NSString *)signature verificationKeyData:(NSData *)verificationKeyData; @end @interface JWTAlgorithmFactory : NSObject @property (nonatomic, readonly, class) NSArray > *algorithms; + (id)algorithmByName:(NSString *)name; @end ================================================ FILE: Sources/JWT/include/JWTAlgorithmHSBase.h ================================================ // // JWTAlgorithmHSBase.h // JWT // // Created by Lobanov Dmitry on 13.03.16. // Copyright © 2016 Karma. All rights reserved. // #import #import "JWTAlgorithm.h" extern NSString *const JWTAlgorithmNameHS256; extern NSString *const JWTAlgorithmNameHS384; extern NSString *const JWTAlgorithmNameHS512; @interface JWTAlgorithmHSBase : NSObject @property (assign, nonatomic, readonly) size_t ccSHANumberDigestLength; @property (assign, nonatomic, readonly) uint32_t ccHmacAlgSHANumber; @end @interface JWTAlgorithmHSBase (Create) + (instancetype)algorithm256; + (instancetype)algorithm384; + (instancetype)algorithm512; @end ================================================ FILE: Sources/JWT/include/JWTAlgorithmNone.h ================================================ // // JWTAlgorithmNone.h // JWT // // Created by Lobanov Dmitry on 16.10.15. // Copyright © 2015 Karma. All rights reserved. // #import #import "JWTAlgorithm.h" extern NSString *const JWTAlgorithmNameNone; @interface JWTAlgorithmNone : NSObject @end ================================================ FILE: Sources/JWT/include/JWTAlgorithmRSBase.h ================================================ // // JWTAlgorithmRSBase.h // JWT // // Created by Lobanov Dmitry on 13.03.16. // Copyright © 2016 Karma. All rights reserved. // #import #import "JWTRSAlgorithm.h" #import "JWTAlgorithmErrorDescription.h" extern NSString *const JWTAlgorithmRSFamilyErrorDomain; typedef NS_ENUM(NSInteger, JWTAlgorithmRSFamilyError) { JWTAlgorithmRSFamilyErrorIncorrectHashComputation = -100, JWTAlgorithmRSFamilyErrorIncorrectKeySize, JWTAlgorithmRSFamilyErrorInternalSecurityAPI = -98, JWTAlgorithmRSFamilyErrorUnexpected = -20 }; // Deprecated. @interface JWTAlgorithmRSFamilyErrorDescription : JWTAlgorithmErrorDescription @end extern NSString *const JWTAlgorithmNameRS256; extern NSString *const JWTAlgorithmNameRS384; extern NSString *const JWTAlgorithmNameRS512; @interface JWTAlgorithmRSBase : NSObject @property (assign, nonatomic, readonly) size_t ccSHANumberDigestLength; @property (assign, nonatomic, readonly) uint32_t secPaddingPKCS1SHANumber; - (unsigned char *)CC_SHANumberWithData:(const void *)data withLength:(uint32_t)len withHashBytes:(unsigned char *)hashBytes; @end @interface JWTAlgorithmRSBase (Create) + (instancetype)algorithm256; + (instancetype)algorithm384; + (instancetype)algorithm512; + (instancetype)mutableAlgorithm __deprecated; @end /* // when you can't live without mutability, uncomment. @class JWTAlgorithmRSFamilyMemberMutable; */ ================================================ FILE: Sources/JWT/include/JWTBase64Coder.h ================================================ // // JWTBase64Coder.h // Pods // // Created by Lobanov Dmitry on 05.10.16. // // #import @protocol JWTStringCoderProtocol - (NSString *)stringWithData:(NSData *)data; - (NSData *)dataWithString:(NSString *)string; @end @interface JWTBase64Coder : NSObject + (instancetype)withBase64String; + (instancetype)withPlainString; + (NSString *)base64UrlEncodedStringWithData:(NSData *)data; + (NSData *)dataWithBase64UrlEncodedString:(NSString *)urlEncodedString; @end @interface JWTBase64Coder (JWTStringCoderProtocol) @end @interface JWTStringCoderForEncoding : NSObject @property (assign, nonatomic, readwrite) NSStringEncoding stringEncoding; + (instancetype)utf8Encoding; @end @interface JWTStringCoderForEncoding (JWTStringCoderProtocol) @end ================================================ FILE: Sources/JWT/include/JWTBuilder+FluentStyle.h ================================================ // // JWTBuilder+FluentStyle.h // JWT // // Created by Dmitry Lobanov on 15/06/2019. // Copyright © 2019 JWTIO. All rights reserved. // #import "JWTCoding+VersionTwo.h" #import "JWTDeprecations.h" #if DEPLOYMENT_RUNTIME_SWIFT #else NS_ASSUME_NONNULL_BEGIN // Fluent ( Objective-C exclusive ). @interface JWTBuilder (FluentStyle) /** Sets jwtMessage and returns the JWTBuilder to allow for method chaining */ @property (copy, nonatomic, readonly) JWTBuilder *(^message)(NSString *message) NS_SWIFT_UNAVAILABLE(""); /** Sets jwtPayload and returns the JWTBuilder to allow for method chaining */ @property (copy, nonatomic, readonly) JWTBuilder *(^payload)(NSDictionary *payload) NS_SWIFT_UNAVAILABLE(""); /** Sets jwtHeaders and returns the JWTBuilder to allow for method chaining */ @property (copy, nonatomic, readonly) JWTBuilder *(^headers)(NSDictionary *headers) NS_SWIFT_UNAVAILABLE(""); /** Sets jwtClaimsSet and returns the JWTBuilder to allow for method chaining */ @property (copy, nonatomic, readonly) JWTBuilder *(^claimsSet)(JWTClaimsSet *claimsSet) NS_SWIFT_UNAVAILABLE(""); /** Sets jwtSecret and returns the JWTBuilder to allow for method chaining */ @property (copy, nonatomic, readonly) JWTBuilder *(^secret)(NSString *secret) NS_SWIFT_UNAVAILABLE(""); /** Sets jwtSecretData and returns the JWTBuilder to allow for method chaining */ @property (copy, nonatomic, readonly) JWTBuilder *(^secretData)(NSData *secretData) NS_SWIFT_UNAVAILABLE(""); /** Sets jwtPrivateKeyCertificatePassphrase and returns the JWTBuilder to allow for method chaining */ @property (copy, nonatomic, readonly) JWTBuilder *(^privateKeyCertificatePassphrase)(NSString *privateKeyCertificatePassphrase) NS_SWIFT_UNAVAILABLE(""); /** Sets jwtAlgorithm and returns the JWTBuilder to allow for method chaining */ @property (copy, nonatomic, readonly) JWTBuilder *(^algorithm)(idalgorithm) NS_SWIFT_UNAVAILABLE(""); /** Sets jwtAlgorithmName and returns the JWTBuilder to allow for method chaining. See list of names in appropriate headers. */ @property (copy, nonatomic, readonly) JWTBuilder *(^algorithmName)(NSString *algorithmName) NS_SWIFT_UNAVAILABLE(""); /** Sets jwtOptions and returns the JWTBuilder to allow for method chaining */ @property (copy, nonatomic, readonly) JWTBuilder *(^options)(NSNumber *options) NS_SWIFT_UNAVAILABLE(""); /** Sets algorithmWhitelist and returns the JWTBuilder to allow for method chaining */ @property (copy, nonatomic, readonly) JWTBuilder *(^whitelist)(NSArray *whitelist) NS_SWIFT_UNAVAILABLE(""); @end NS_ASSUME_NONNULL_END #endif ================================================ FILE: Sources/JWT/include/JWTClaim.h ================================================ // // JWTClaim.h // JWT // // Created by Lobanov Dmitry on 13.02.16. // Copyright © 2016 Karma. All rights reserved. // #import @interface JWTClaim : NSObject + (NSString *)name; + (instancetype)claimByName:(NSString *)name; + (BOOL)verifyValue:(NSObject *)value withTrustedValue:(NSObject *)trustedValue; - (BOOL)verifyValue:(NSObject *)value withTrustedValue:(NSObject *)trustedValue; @end ================================================ FILE: Sources/JWT/include/JWTClaimBase.h ================================================ // // JWTClaimBase.h // JWT // // Created by Dmitry Lobanov on 10.08.2020. // Copyright © 2020 JWTIO. All rights reserved. // #import #import "JWTClaimsSetsProtocols.h" NS_ASSUME_NONNULL_BEGIN @interface JWTClaimBase : NSObject @end NS_ASSUME_NONNULL_END ================================================ FILE: Sources/JWT/include/JWTClaimSerializerBase.h ================================================ // // JWTClaimSerializerBase.h // JWT // // Created by Dmitry Lobanov on 30.05.2021. // Copyright © 2021 JWTIO. All rights reserved. // #import #import "JWTClaimsSetsProtocols.h" NS_ASSUME_NONNULL_BEGIN @interface JWTClaimSerializerBase : NSObject @end NS_ASSUME_NONNULL_END ================================================ FILE: Sources/JWT/include/JWTClaimSerializerVariations.h ================================================ // // JWTClaimSerializerVariations.h // JWT // // Created by Dmitry Lobanov on 30.05.2021. // Copyright © 2021 JWTIO. All rights reserved. // #import #import "JWTClaimSerializerBase.h" NS_ASSUME_NONNULL_BEGIN @interface JWTClaimSerializerVariations : NSObject /// Discussion /// @return JWTClaimSerializerBaseConcreteDateAndTimestamp /// + (id)dateAndTimestampTransform; /// Discussion /// @return JWTClaimSerializerBase /// + (id)identityTransform; @end /// Discussion /// This serializer converts NSDate to a json value via timeIntervalSince1970. /// /// Conversion /// /// JSON Timestamp /// Claim NSDate /// /// Encoding and Decoding /// Decode JSON -> Claim `dateWithTimeIntervalSince1970` /// Encode Claim -> JSON `timeIntervalSince1970` /// /// Examples /// /// JSON /// { /// ... "time": 12362387432, /// } /// /// Date /// NSDate *date = [NSDate dateWithTimeIntervalSince1970:12362387432]; /// @interface JWTClaimSerializerBaseConcreteDateAndTimestamp : JWTClaimSerializerBase @end NS_ASSUME_NONNULL_END ================================================ FILE: Sources/JWT/include/JWTClaimVariations.h ================================================ // // JWTClaimVariations.h // JWT // // Created by Dmitry Lobanov on 10.08.2020. // Copyright © 2020 JWTIO. All rights reserved. // #import #import "JWTClaimBase.h" NS_ASSUME_NONNULL_BEGIN extern NSString *JWTRegisteredClaimNameIssuer; extern NSString *JWTRegisteredClaimNameSubject; extern NSString *JWTRegisteredClaimNameAudience; extern NSString *JWTRegisteredClaimNameExpirationTime; extern NSString *JWTRegisteredClaimNameNotBefore; extern NSString *JWTRegisteredClaimNameIssuedAt; extern NSString *JWTRegisteredClaimNameJWTID; extern NSString *JWTRegisteredClaimNameType; extern NSString *JWTRegisteredClaimNameScope; @interface JWTClaimVariations : NSObject + (id)issuer; + (id)subject; + (id)audience; + (id)expirationTime; + (id)notBefore; + (id)issuedAt; + (id)jwtID; + (id)type; + (id)scope; @end @interface JWTClaimsNames : NSObject @property(copy, nonatomic, readonly, class) NSString *issuer; @property(copy, nonatomic, readonly, class) NSString *subject; @property(copy, nonatomic, readonly, class) NSString *audience; @property(copy, nonatomic, readonly, class) NSString *expirationTime; @property(copy, nonatomic, readonly, class) NSString *notBefore; @property(copy, nonatomic, readonly, class) NSString *issuedAt; @property(copy, nonatomic, readonly, class) NSString *jwtID; @property(copy, nonatomic, readonly, class) NSString *type; @property(copy, nonatomic, readonly, class) NSString *scope; @end NS_ASSUME_NONNULL_END ================================================ FILE: Sources/JWT/include/JWTClaimVerifierBase.h ================================================ // // JWTClaimVerifierBase.h // JWT // // Created by Dmitry Lobanov on 30.05.2021. // Copyright © 2021 JWTIO. All rights reserved. // #import #import "JWTClaimsSetsProtocols.h" NS_ASSUME_NONNULL_BEGIN @interface JWTClaimVerifierBase : NSObject @end NS_ASSUME_NONNULL_END ================================================ FILE: Sources/JWT/include/JWTClaimVerifierVariations.h ================================================ // // JWTClaimVerifierVariations.h // JWT // // Created by Dmitry Lobanov on 30.05.2021. // Copyright © 2021 JWTIO. All rights reserved. // #import #import "JWTClaimVerifierBase.h" NS_ASSUME_NONNULL_BEGIN @interface JWTClaimVerifierVariations : NSObject + (id)issuer; + (id)subject; + (id)audienceEqualSingle; + (id)audienceInSet; + (id)expirationTime; + (id)notBefore; + (id)issuedAt; + (id)jwtID; + (id)type; + (id)scope; @end @interface JWTClaimVerifierBaseConcreteEquality : JWTClaimVerifierBase @property (assign, nonatomic, readwrite) BOOL equal; @end @interface JWTClaimVerifierBaseConcreteComparison : JWTClaimVerifierBase @property (assign, nonatomic, readwrite) NSComparisonResult expectedComparison; @property (assign, nonatomic, readwrite) BOOL trustedValueAtLeft; @property (assign, nonatomic, readwrite) BOOL notEqual; @end @interface JWTClaimVerifierBaseConcreteEqualityForString : JWTClaimVerifierBaseConcreteEquality @end @interface JWTClaimVerifierBaseConcreteInclusionInSet : JWTClaimVerifierBase @end NS_ASSUME_NONNULL_END ================================================ FILE: Sources/JWT/include/JWTClaimsProviderBase.h ================================================ // // JWTClaimsProviderBase.h // JWT // // Created by Dmitry Lobanov on 22.05.2021. // Copyright © 2021 JWTIO. All rights reserved. // #import #import "JWTClaimsSetsProtocols.h" NS_ASSUME_NONNULL_BEGIN @interface JWTClaimsProviderBase : NSObject @end NS_ASSUME_NONNULL_END ================================================ FILE: Sources/JWT/include/JWTClaimsSet.h ================================================ // // JWTClaimsSet.h // JWT // // Created by Klaas Pieter Annema on 31-05-13. // Copyright (c) 2013 Karma. All rights reserved. // #import @interface JWTClaimsSet : NSObject @property (nonatomic, readwrite, copy) NSString *issuer; @property (nonatomic, readwrite, copy) NSString *subject; @property (nonatomic, readwrite, copy) NSString *audience; @property (nonatomic, readwrite, copy) NSDate *expirationDate; @property (nonatomic, readwrite, copy) NSDate *notBeforeDate; @property (nonatomic, readwrite, copy) NSDate *issuedAt; @property (nonatomic, readwrite, copy) NSString *identifier; @property (nonatomic, readwrite, copy) NSString *type; @property (nonatomic, readwrite, copy) NSString *scope; @end ================================================ FILE: Sources/JWT/include/JWTClaimsSetBase.h ================================================ // // JWTClaimsSetBase.h // JWT // // Created by Dmitry Lobanov on 10.08.2020. // Copyright © 2020 JWTIO. All rights reserved. // #import #import "JWTClaimsSetsProtocols.h" NS_ASSUME_NONNULL_BEGIN @interface JWTClaimsSetBase : NSObject @end NS_ASSUME_NONNULL_END ================================================ FILE: Sources/JWT/include/JWTClaimsSetCoordinatorBase.h ================================================ // // JWTClaimsSetCoordinatorBase.h // JWT // // Created by Dmitry Lobanov on 31.05.2021. // Copyright © 2021 JWTIO. All rights reserved. // #import #import "JWTClaimsSetsProtocols.h" NS_ASSUME_NONNULL_BEGIN @interface JWTClaimsSetCoordinatorBase : NSObject @property (strong, nonatomic, readwrite) id claimsProvider; @property (copy, nonatomic, readwrite) id claimsSetStorage; @property (strong, nonatomic, readwrite) id claimsSetSerializer; @property (strong, nonatomic, readwrite) id claimsSetVerifier; - (instancetype)configureClaimsSet:(JWTClaimsSetDSLBase *(^)(JWTClaimsSetDSLBase *claimsSetDSL))claimsSet; #if DEPLOYMENT_RUNTIME_SWIFT #else @property (copy, nonatomic, readonly) id (^configureClaimsSet)(JWTClaimsSetDSLBase *(^)(JWTClaimsSetDSLBase *claimsSetDSL)) NS_SWIFT_UNAVAILABLE(""); #endif @end NS_ASSUME_NONNULL_END ================================================ FILE: Sources/JWT/include/JWTClaimsSetDSLBase.h ================================================ // // JWTClaimsSetDSLBase.h // JWT // // Created by Dmitry Lobanov on 31.05.2021. // Copyright © 2021 JWTIO. All rights reserved. // #import #import "JWTClaimsSetsProtocols.h" NS_ASSUME_NONNULL_BEGIN @interface JWTClaimsSetDSLBase : NSObject @property (strong, nonatomic, readonly) id claimsProvider; @property (copy, nonatomic, readonly) id claimsSetStorage; - (instancetype)initWithClaimsProvider:(id )claimsProvider claimsSetStorage:(id )claimsSetStorage; @end @interface JWTClaimsSetDSLBase (DSL) - (nullable NSObject *)dslValueForName:(NSString *)name; - (void)dslSetValue:(NSObject *)value forName:(NSString *)name; @property (copy, nonatomic, readwrite) NSString *issuer; @property (copy, nonatomic, readwrite) NSString *subject; @property (copy, nonatomic, readwrite) NSString *audience; @property (copy, nonatomic, readwrite) NSDate *expirationDate; @property (copy, nonatomic, readwrite) NSDate *notBeforeDate; @property (copy, nonatomic, readwrite) NSDate *issuedAt; @property (copy, nonatomic, readwrite) NSString *identifier; @property (copy, nonatomic, readwrite) NSString *type; @property (copy, nonatomic, readwrite) NSString *scope; @end NS_ASSUME_NONNULL_END ================================================ FILE: Sources/JWT/include/JWTClaimsSetSerializer.h ================================================ // // JWTClaimsSetSerializer.h // JWT // // Created by Klaas Pieter Annema on 31-05-13. // Copyright (c) 2013 Karma. All rights reserved. // #import #import "JWTClaimsSet.h" @interface JWTClaimsSetSerializer : NSObject + (NSArray *)claimsSetKeys; + (NSDictionary *)dictionaryWithClaimsSet:(JWTClaimsSet *)theClaimsSet; + (JWTClaimsSet *)claimsSetWithDictionary:(NSDictionary *)theDictionary; @end ================================================ FILE: Sources/JWT/include/JWTClaimsSetSerializerBase.h ================================================ // // JWTClaimsSetSerializerBase.h // JWT // // Created by Dmitry Lobanov on 10.08.2020. // Copyright © 2020 JWTIO. All rights reserved. // #import #import "JWTClaimsSetsProtocols.h" #import "JWTClaimSerializerBase.h" NS_ASSUME_NONNULL_BEGIN @interface JWTClaimsSetSerializerBase : NSObject @property (strong, nonatomic, readwrite) id claimsProvider; @property (copy, nonatomic, readwrite) id claimsSetStorage; @property (assign, nonatomic, readwrite) BOOL skipClaimsProviderLookupCheck; @end NS_ASSUME_NONNULL_END ================================================ FILE: Sources/JWT/include/JWTClaimsSetVerifier.h ================================================ // // JWTClaimsSetVerifier.h // JWT // // Created by Lobanov Dmitry on 13.02.16. // Copyright © 2016 Karma. All rights reserved. // #import #import "JWTClaimsSet.h" @interface JWTClaimsSetVerifier : NSObject + (BOOL)verifyClaimsSet:(JWTClaimsSet *)theClaimsSet withTrustedClaimsSet:(JWTClaimsSet *)trustedClaimsSet; @end ================================================ FILE: Sources/JWT/include/JWTClaimsSetVerifierBase.h ================================================ // // JWTClaimsSetVerifierBase.h // JWT // // Created by Dmitry Lobanov on 10.08.2020. // Copyright © 2020 JWTIO. All rights reserved. // #import #import "JWTClaimsSetsProtocols.h" #import "JWTClaimVerifierBase.h" NS_ASSUME_NONNULL_BEGIN @interface JWTClaimsSetVerifierBase : NSObject @property (strong, nonatomic, readwrite) id claimsProvider; @property (nonatomic, readwrite) id serializer; @end NS_ASSUME_NONNULL_END ================================================ FILE: Sources/JWT/include/JWTClaimsSetsProtocols.h ================================================ // // JWTClaimsSetsProtocols.h // JWT // // Created by Dmitry Lobanov on 09.08.2020. // Copyright © 2020 JWTIO. All rights reserved. // #import @class JWTClaimsSetDSLBase; NS_ASSUME_NONNULL_BEGIN @protocol JWTClaimProtocol @property (copy, nonatomic, readonly, class) NSString *name; @property (copy, nonatomic, readonly) NSString *name; @property (nonatomic, readonly) NSObject *value; - (instancetype)copyWithValue:(NSObject *)value; - (instancetype)copyWithName:(NSString *)name; @end @protocol JWTClaimVerifierProtocol - (BOOL)verifyValue:(NSObject *)value withTrustedValue:(NSObject *)trustedValue; @end @protocol JWTClaimSerializerProtocol - (NSObject *)serializedClaimValue:(id)claim; - (NSObject *)deserializedClaimValue:(NSObject *)value forName:(NSString *)name; @end @protocol JWTClaimsSetProtocol @property (copy, nonatomic, readonly) NSArray >* claims; - (instancetype)copyWithClaims:(NSArray >*)claims; - (id)claimByName:(NSString *)name; - (void)appendClaim:(id)claim; - (void)removeClaimByName:(NSString *)name; @property (assign, nonatomic, readonly) BOOL isEmpty; @end @protocol JWTClaimsProviderProtocol @property (copy, nonatomic, readonly) NSArray *availableClaimsNames; - (id)claimByName:(NSString *)name; - (void)registerClaim:(id)claim forClaimName:(NSString *)name; - (void)unregisterClaimForClaimName:(NSString *)name; @end @protocol JWTClaimsSetSerializerProtocol @property (strong, nonatomic, readwrite) id claimsProvider; @property (copy, nonatomic, readwrite) id claimsSetStorage; - (void)registerSerializer:(id)serializer forClaimName:(NSString *)name; - (void)unregisterSerializerForClaimName:(NSString *)name; - (nullable NSDictionary *)dictionaryFromClaimsSet:(id)claimsSet; - (nullable id)claimsSetFromDictionary:(NSDictionary *)dictionary; @end @protocol JWTClaimsSetVerifierProtocol @property (strong, nonatomic, readwrite) id claimsProvider; - (void)registerVerifier:(id)verifier forClaimName:(NSString *)name; - (void)unregisterVerifierForClaimName:(NSString *)name; - (BOOL)verifyClaimsSet:(id)theClaimsSet withTrustedClaimsSet:(id)trustedClaimsSet; @end @protocol JWTClaimsSetCoordinatorProtocol @property (strong, nonatomic, readwrite) id claimsProvider; @property (copy, nonatomic, readwrite) id claimsSetStorage; @property (strong, nonatomic, readwrite) id claimsSetSerializer; @property (strong, nonatomic, readwrite) id claimsSetVerifier; @property (strong, nonatomic, readonly) JWTClaimsSetDSLBase *dslDesrciption; - (instancetype)configureClaimsSet:(JWTClaimsSetDSLBase *(^)(JWTClaimsSetDSLBase *claimsSetDSL))claimsSet; #if DEPLOYMENT_RUNTIME_SWIFT #else @property (copy, nonatomic, readonly) id (^configureClaimsSet)(JWTClaimsSetDSLBase *(^)(JWTClaimsSetDSLBase *claimsSetDSL)) NS_SWIFT_UNAVAILABLE(""); #endif - (void)registerClaim:(id)claim serializer:(id)serializer verifier:(id)verifier forClaimName:(NSString *)name; - (void)unregisterClaimWithSerializerAndVerifierForClaimName:(NSString *)name; @end NS_ASSUME_NONNULL_END ================================================ FILE: Sources/JWT/include/JWTCoding+ResultTypes.h ================================================ // // JWTCoding+ResultTypes.h // JWT // // Created by Lobanov Dmitry on 30.11.16. // Copyright © 2016 JWTIO. All rights reserved. // #import "JWTCoding.h" #import "JWTDeprecations.h" @protocol JWTClaimsSetProtocol; @interface JWTCodingResultComponents : NSObject @property (copy, nonatomic, readonly, class) NSString *headers; @property (copy, nonatomic, readonly, class) NSString *payload; @end @interface JWT (ResultTypes) @end /* ResultType /\ / \ / \ Success Error Protocols: Mutable and Immutable (?!?) */ // Public @protocol JWTCodingResultTypeSuccessEncodedProtocol @property (copy, nonatomic, readonly) NSString *encoded; - (instancetype)initWithEncoded:(NSString *)encoded; @property (copy, nonatomic, readonly) NSString *token; - (instancetype)initWithToken:(NSString *)token; @end // Public @protocol JWTCodingResultTypeSuccessDecodedProtocol @property (copy, nonatomic, readonly) NSDictionary *headers; @property (copy, nonatomic, readonly) NSDictionary *payload; /// This is a dictionary that contains header and payload. /// /// @discussion /// You may access to its guts via `JWTCodingResultComponents`. /// /// dictionary = { /// JWTCodingResultComponents.headers : headers, /// JWTCodingResultComponents.payload : payload /// } /// @property (copy, nonatomic, readonly) NSDictionary *headerAndPayloadDictionary; @property (copy, nonatomic, readonly) id claimsSetStorage; - (instancetype)initWithHeadersAndPayload:(NSDictionary *)headersAndPayloadDictionary; - (instancetype)initWithHeaders:(NSDictionary *)headers withPayload:(NSDictionary *)payload; - (instancetype)initWithClaimsSetStorage:(id)claimsSetStorage; @end // Public @interface JWTCodingResultTypeSuccess : NSObject @end // Public @protocol JWTCodingResultTypeErrorProtocol @property (copy, nonatomic, readonly) NSError *error; - (instancetype)initWithError:(NSError *)error; @end @interface JWTCodingResultTypeError : NSObject @end @interface JWTCodingResultType : NSObject - (instancetype)initWithSuccessResult:(JWTCodingResultTypeSuccess *)success; - (instancetype)initWithErrorResult:(JWTCodingResultTypeError *)error; @property (strong, nonatomic, readonly) JWTCodingResultTypeSuccess *successResult; @property (strong, nonatomic, readonly) JWTCodingResultTypeError *errorResult; @end ================================================ FILE: Sources/JWT/include/JWTCoding+VersionOne.h ================================================ // // JWTCoding+VersionOne.h // JWT // // Created by Lobanov Dmitry on 27.11.16. // Copyright © 2016 JWTIO. All rights reserved. // #import "JWTCoding.h" @protocol JWTAlgorithm; @class JWTClaimsSet; @interface JWT (VersionOne) #pragma mark - Encode + (NSString *)encodeClaimsSet:(JWTClaimsSet *)theClaimsSet withSecret:(NSString *)theSecret; + (NSString *)encodeClaimsSet:(JWTClaimsSet *)theClaimsSet withSecret:(NSString *)theSecret algorithm:(id)theAlgorithm; + (NSString *)encodePayload:(NSDictionary *)thePayload withSecret:(NSString *)theSecret; + (NSString *)encodePayload:(NSDictionary *)thePayload withSecret:(NSString *)theSecret algorithm:(id)theAlgorithm; + (NSString *)encodePayload:(NSDictionary *)thePayload withSecret:(NSString *)theSecret withHeaders:(NSDictionary *)theHeaders algorithm:(id)theAlgorithm; + (NSString *)encodePayload:(NSDictionary *)thePayload withSecret:(NSString *)theSecret withHeaders:(NSDictionary *)theHeaders algorithm:(id)theAlgorithm withError:(NSError * __autoreleasing *)theError; //Will be deprecated in later releases #pragma mark - Decode /** Decodes a JWT and returns the decoded Header and Payload @param theMessage The encoded JWT @param theSecret The verification key to use for validating the JWT signature @param theTrustedClaimsSet The JWTClaimsSet to use for verifying the JWT values @param theError Error pointer, if there is an error decoding the message, upon return contains an NSError object that describes the problem. @param theAlgorithmName The name of the algorithm to use for verifying the signature. Required, unless skipping verification @param theForcedOption BOOL indicating if verifying the JWT signature should be skipped. Should only be used for debugging @return A dictionary containing the header and payload dictionaries. Keyed to "header" and "payload", respectively. Or nil if an error occurs. */ + (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withTrustedClaimsSet:(JWTClaimsSet *)theTrustedClaimsSet withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName withForcedOption:(BOOL)theForcedOption; /** Decodes a JWT and returns the decoded Header and Payload @param theMessage The encoded JWT @param theSecret The verification key to use for validating the JWT signature @param theTrustedClaimsSet The JWTClaimsSet to use for verifying the JWT values @param theError Error pointer, if there is an error decoding the message, upon return contains an NSError object that describes the problem. @param theAlgorithmName The name of the algorithm to use for verifying the signature. Required. @return A dictionary containing the header and payload dictionaries. Keyed to "header" and "payload", respectively. Or nil if an error occurs. */ + (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withTrustedClaimsSet:(JWTClaimsSet *)theTrustedClaimsSet withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName; /** Decodes a JWT and returns the decoded Header and Payload. Uses the JWTAlgorithmHS512 for decoding @param theMessage The encoded JWT @param theSecret The verification key to use for validating the JWT signature @param theTrustedClaimsSet The JWTClaimsSet to use for verifying the JWT values @param theError Error pointer, if there is an error decoding the message, upon return contains an NSError object that describes the problem. @param theForcedOption BOOL indicating if verifying the JWT signature should be skipped. Should only be used for debugging @return A dictionary containing the header and payload dictionaries. Keyed to "header" and "payload", respectively. Or nil if an error occurs. */ + (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withTrustedClaimsSet:(JWTClaimsSet *)theTrustedClaimsSet withError:(NSError *__autoreleasing *)theError withForcedOption:(BOOL)theForcedOption; /** Decodes a JWT and returns the decoded Header and Payload @param theMessage The encoded JWT @param theSecret The verification key to use for validating the JWT signature @param theError Error pointer, if there is an error decoding the message, upon return contains an NSError object that describes the problem. @param theAlgorithmName The name of the algorithm to use for verifying the signature. Required, unless skipping verification @param skipVerification BOOL indicating if verifying the JWT signature should be skipped. Should only be used for debugging @return A dictionary containing the header and payload dictionaries. Keyed to "header" and "payload", respectively. Or nil if an error occurs. */ + (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName skipVerification:(BOOL)skipVerification; /** Decodes a JWT and returns the decoded Header and Payload @param theMessage The encoded JWT @param theSecret The verification key to use for validating the JWT signature @param theError Error pointer, if there is an error decoding the message, upon return contains an NSError object that describes the problem. @param theAlgorithmName The name of the algorithm to use for verifying the signature. Required. @return A dictionary containing the header and payload dictionaries. Keyed to "header" and "payload", respectively. Or nil if an error occurs. */ + (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withError:(NSError *__autoreleasing *)theError withForcedAlgorithmByName:(NSString *)theAlgorithmName; /** Decodes a JWT and returns the decoded Header and Payload Uses the JWTAlgorithmHS512 for decoding @param theMessage The encoded JWT @param theSecret The verification key to use for validating the JWT signature @param theError Error pointer, if there is an error decoding the message, upon return contains an NSError object that describes the problem. @param theForcedOption BOOL indicating if verifying the JWT signature should be skipped. @return A dictionary containing the header and payload dictionaries. Keyed to "header" and "payload", respectively. Or nil if an error occurs. */ + (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withError:(NSError *__autoreleasing *)theError withForcedOption:(BOOL)theForcedOption; /** Decodes a JWT and returns the decoded Header and Payload. Uses the JWTAlgorithmHS512 for decoding @param theMessage The encoded JWT @param theSecret The verification key to use for validating the JWT signature @param theError Error pointer, if there is an error decoding the message, upon return contains an NSError object that describes the problem. @return A dictionary containing the header and payload dictionaries. Keyed to "header" and "payload", respectively. Or nil if an error occurs. */ + (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret withError:(NSError * __autoreleasing *)theError; /** Decodes a JWT and returns the decoded Header and Payload. Uses the JWTAlgorithmHS512 for decoding @param theMessage The encoded JWT @param theSecret The verification key to use for validating the JWT signature @return A dictionary containing the header and payload dictionaries. Keyed to "header" and "payload", respectively. Or nil if an error occurs. */ + (NSDictionary *)decodeMessage:(NSString *)theMessage withSecret:(NSString *)theSecret; @end ================================================ FILE: Sources/JWT/include/JWTCoding+VersionThree.h ================================================ // // JWTCoding+VersionThree.h // JWT // // Created by Lobanov Dmitry on 27.11.16. // Copyright © 2016 JWTIO. All rights reserved. // #import "JWTCoding.h" // encode and decode options @protocol JWTAlgorithm; @class JWTCodingBuilder; @class JWTEncodingBuilder; @class JWTDecodingBuilder; @class JWTAlgorithmDataHolderChain; @protocol JWTAlgorithmDataHolderProtocol; @class JWTCodingResultType; @protocol JWTClaimsSetCoordinatorProtocol; @protocol JWTStringCoderProtocol; @interface JWT (VersionThree) + (JWTEncodingBuilder *)encodeWithHolders:(NSArray *)holders; + (JWTEncodingBuilder *)encodeWithChain:(JWTAlgorithmDataHolderChain *)chain; + (JWTDecodingBuilder *)decodeWithHolders:(NSArray *)holders; + (JWTDecodingBuilder *)decodeWithChain:(JWTAlgorithmDataHolderChain *)chain; @end @interface JWTCodingBuilder : NSObject #pragma mark - Create // each element should conform to JWTAlgorithmDataHolderProtocol + (instancetype)createWithHolders:(NSArray *)holders; + (instancetype)createWithChain:(JWTAlgorithmDataHolderChain *)chain; + (instancetype)createWithEmptyChain; #pragma mark - Internal @property (nonatomic, readonly) JWTAlgorithmDataHolderChain *internalChain; @property (copy, nonatomic, readonly) NSNumber *internalOptions; @property (strong, nonatomic, readonly) id internalTokenCoder; @end @interface JWTCodingBuilder (Sugar) - (instancetype)and; - (instancetype)with; @end @interface JWTCodingBuilder (Coding) @property (nonatomic, readonly) JWTCodingResultType *result; @end @interface JWTEncodingBuilder : JWTCodingBuilder #pragma mark - Create + (instancetype)encodePayload:(NSDictionary *)payload; + (instancetype)encodeClaimsSetWithCoordinator:(id)coordinator; #pragma mark - Internal @property (copy, nonatomic, readonly) NSDictionary *internalPayload; @property (copy, nonatomic, readonly) NSDictionary *internalHeaders; @property (nonatomic, readonly) id internalClaimsSetCoordinator; @end @interface JWTEncodingBuilder (Coding) @property (nonatomic, readonly) JWTCodingResultType *encode; @end @interface JWTDecodingBuilder : JWTCodingBuilder #pragma mark - Create + (instancetype)decodeMessage:(NSString *)message; #pragma mark - Internal @property (copy, nonatomic, readonly) NSString *internalMessage; @property (nonatomic, readonly) id internalClaimsSetCoordinator; @end @interface JWTDecodingBuilder (Coding) @property (nonatomic, readonly) JWTCodingResultType *decode; @end #pragma mark - Setters @interface JWTCodingBuilder (Setters) - (instancetype)chain:(JWTAlgorithmDataHolderChain *)chain; - (instancetype)options:(NSNumber *)options; - (instancetype)addHolder:(id)holder; - (instancetype)tokenCoder:(id)tokenCoder; @end @interface JWTEncodingBuilder (Setters) - (instancetype)payload:(NSDictionary *)payload; - (instancetype)headers:(NSDictionary *)headers; - (instancetype)claimsSetCoordinator:(id)claimsSetCoordinator; @end @interface JWTDecodingBuilder (Setters) - (instancetype)message:(NSString *)message; - (instancetype)claimsSetCoordinator:(id)claimsSetCoordinator; @end ================================================ FILE: Sources/JWT/include/JWTCoding+VersionTwo.h ================================================ // // JWTCoding+VersionTwo.h // JWT // // Created by Lobanov Dmitry on 27.11.16. // Copyright © 2016 JWTIO. All rights reserved. // #import "JWTCoding.h" @protocol JWTAlgorithm; @class JWTClaimsSet; @class JWTBuilder; @interface JWT (VersionTwo) #pragma mark - Builder + (JWTBuilder *)encodePayload:(NSDictionary *)payload; + (JWTBuilder *)encodeClaimsSet:(JWTClaimsSet *)claimsSet; + (JWTBuilder *)decodeMessage:(NSString *)message; @end @interface JWTBuilder : NSObject + (JWTBuilder *)encodePayload:(NSDictionary *)payload; + (JWTBuilder *)encodeClaimsSet:(JWTClaimsSet *)claimsSet; + (JWTBuilder *)decodeMessage:(NSString *)message; /** The JWT in it's encoded form. Will be decoded and verified */ @property (copy, nonatomic, readonly) NSString *jwtMessage; /** The payload dictionary to encode */ @property (copy, nonatomic, readonly) NSDictionary *jwtPayload; /** The header dictionary to encode */ @property (copy, nonatomic, readonly) NSDictionary *jwtHeaders; /** The expected JWTClaimsSet to compare against a decoded JWT */ @property (copy, nonatomic, readonly) JWTClaimsSet *jwtClaimsSet; /** The algorithm data holders. They contain necessary information about algorithms. */ @property (copy, nonatomic, readonly) NSArray *jwtDataHolders; /** The verification key to use when encoding/decoding a JWT */ @property (copy, nonatomic, readonly) NSString *jwtSecret; /** The verification key to use when encoding/decoding a JWT in data form */ @property (copy, nonatomic, readonly) NSData *jwtSecretData; /** The passphrase for the PKCS12 blob, which represents the certificate containing the private key for the RS algorithms. */ @property (copy, nonatomic, readonly) NSString *jwtPrivateKeyCertificatePassphrase; /** Contains the error that occured during an operation, or nil if no error occured */ @property (copy, nonatomic, readonly) NSError *jwtError; /** The to use for encoding a JWT */ @property (strong, nonatomic, readonly) id jwtAlgorithm; /** The algorithm name to use for decoding the JWT. Required unless force decode is true */ @property (copy, nonatomic, readonly) NSString *jwtAlgorithmName; /** The force decode option. If set to true, a JWT won't be validated before decoding. Should only be used for debugging */ @property (copy, nonatomic, readonly) NSNumber *jwtOptions; /* Optional algorithm name whitelist. If non-null, a JWT can only be decoded using an algorithm specified on this list. */ @property (copy, nonatomic, readonly) NSSet *algorithmWhitelist; /** Creates the encoded JWT string based on the currently set properties, or nil if an error occured */ @property (copy, nonatomic, readonly) NSString *encode; /** Decodes and returns the JWT as a dictionary, based on the JWTBuilder's currently set properties, or nil, if an error occured. */ @property (copy, nonatomic, readonly) NSDictionary *decode; //@property (copy, nonatomic, readonly) JWTBuilder * (^addDataHolder)(JWTAlgorithmBaseDataHolder *dataHolder) __available_in_release_version(JWTVersion_3_0_0); //@property (copy, nonatomic, readonly) JWTBuilder * (^constructDataHolder)(id (^block)()) __available_in_release_version(JWTVersion_3_0_0); @end @interface JWTBuilder (Setters) - (instancetype)message:(NSString *)message; - (instancetype)payload:(NSDictionary *)payload; - (instancetype)headers:(NSDictionary *)headers; - (instancetype)claimSet:(JWTClaimsSet *)claimSet; - (instancetype)secret:(NSString *)secret; - (instancetype)secretData:(NSData *)secretData; - (instancetype)privateKeyCertificatePassphrase:(NSString *)privateKeyCertificatePassphrase; - (instancetype)algorithm:(id)algorithm; - (instancetype)algorithmName:(NSString *)algorithmName; - (instancetype)options:(NSNumber *)options; - (instancetype)whitelist:(NSArray *)whitelist; @end ================================================ FILE: Sources/JWT/include/JWTCoding.h ================================================ // // JWT.h // JWT // // Created by Klaas Pieter Annema on 31-05-13. // Copyright (c) 2013 Karma. All rights reserved. // #import /** @discussion JWT is a general interface for decoding and encoding. Now it is too complex and fat to support. Possible solution: split interface into several pieces. JWT_1_0 -> JWT with plain old functions. JWT_2_0 -> JWT with builder usage. JWT_3_0 -> JWT with splitted apart algorithm data and payload data. */ @interface JWT : NSObject @end typedef NS_OPTIONS(NSInteger, JWTCodingDecodingOptions) { JWTCodingDecodingOptionsNone = 0, JWTCodingDecodingOptionsSkipVerification = 1 }; ================================================ FILE: Sources/JWT/include/JWTCodingBuilder+FluentStyle.h ================================================ // // JWTCodingBuilder+FluentStyle.h // JWT // // Created by Dmitry Lobanov on 07/06/2019. // Copyright © 2019 JWTIO. All rights reserved. // #import #import "JWTCoding+VersionThree.h" #import "JWTDeprecations.h" #if DEPLOYMENT_RUNTIME_SWIFT #else NS_ASSUME_NONNULL_BEGIN // Fluent ( Objective-C exclusive ). @interface JWTCodingBuilder (FluentStyle) @property (copy, nonatomic, readonly) JWTCodingBuilder *(^chain)(JWTAlgorithmDataHolderChain *chain) NS_SWIFT_UNAVAILABLE(""); @property (copy, nonatomic, readonly) JWTCodingBuilder *(^constructChain)(JWTAlgorithmDataHolderChain *(^block)(void)) NS_SWIFT_UNAVAILABLE(""); @property (copy, nonatomic, readonly) JWTCodingBuilder *(^modifyChain)(JWTAlgorithmDataHolderChain *(^block)(JWTAlgorithmDataHolderChain * chain)) NS_SWIFT_UNAVAILABLE(""); @property (copy, nonatomic, readonly) JWTCodingBuilder *(^options)(NSNumber *options) NS_SWIFT_UNAVAILABLE(""); @property (copy, nonatomic, readonly) JWTCodingBuilder *(^addHolder)(id holder) NS_SWIFT_UNAVAILABLE(""); @property (copy, nonatomic, readonly) JWTCodingBuilder *(^tokenCoder)(id tokenCoder) NS_SWIFT_UNAVAILABLE(""); @end @interface JWTEncodingBuilder (FluentStyle) @property (copy, nonatomic, readonly) JWTEncodingBuilder *(^payload)(NSDictionary *payload) NS_SWIFT_UNAVAILABLE(""); @property (copy, nonatomic, readonly) JWTEncodingBuilder *(^headers)(NSDictionary *headers) NS_SWIFT_UNAVAILABLE(""); @property (copy, nonatomic, readonly) JWTEncodingBuilder *(^claimsSetCoordinator)(id claimsSetCoordinator) NS_SWIFT_UNAVAILABLE(""); @end @interface JWTDecodingBuilder (FluentStyle) @property (copy, nonatomic, readonly) JWTDecodingBuilder *(^message)(NSString *message) NS_SWIFT_UNAVAILABLE(""); @property (copy, nonatomic, readonly) JWTDecodingBuilder *(^claimsSetCoordinator)(id claimsSetCoordinator) NS_SWIFT_UNAVAILABLE(""); @end NS_ASSUME_NONNULL_END #endif ================================================ FILE: Sources/JWT/include/JWTCryptoKey.h ================================================ // // JWTCryptoKey.h // JWT // // Created by Lobanov Dmitry on 04.02.17. // Copyright © 2017 JWTIO. All rights reserved. // #import #import @protocol JWTCryptoKeyProtocol @property (copy, nonatomic, readonly) NSString *tag; @property (assign, nonatomic, readonly) SecKeyRef key; @property (copy, nonatomic, readonly) NSData *rawKey; @end @protocol JWTCryptoKey__Generator__Protocol - (instancetype)initWithData:(NSData *)data parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error; //NS_DESIGNATED_INITIALIZER - (instancetype)initWithBase64String:(NSString *)base64String parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error; - (instancetype)initWithPemEncoded:(NSString *)encoded parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error; - (instancetype)initWithPemAtURL:(NSURL *)url parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error; @end @protocol JWTCryptoKey__Raw__Generator__Protocol - (instancetype)initWithSecKeyRef:(SecKeyRef)key; @end @interface JWTCryptoKeyBuilder : NSObject @property (assign, nonatomic, readonly) NSString *keyType; - (instancetype)keyTypeRSA; - (instancetype)keyTypeEC; @end /* Don't use it directly, use subclasses instead! */ @interface JWTCryptoKey : NSObject @end // Check that Security key is retrieved. // Could be used as additional step in key data verification. @interface JWTCryptoKey (Check) - (instancetype)checkedWithError:(NSError *__autoreleasing*)error; @end @interface JWTCryptoKey (Parameters) + (NSString *)parametersKeyBuilder; @end @class JWTBase64Coder; @interface JWTCryptoKey (ExternalRepresentation) - (NSString *)externalRepresentationForCoder:(JWTBase64Coder *)coder error:(NSError *__autoreleasing *)error; @end @interface JWTCryptoKeyPublic : JWTCryptoKey - (instancetype)initWithCertificateData:(NSData *)certificateData parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error; //NS_DESIGNATED_INITIALIZER; - (instancetype)initWithCertificateBase64String:(NSString *)certificateString parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error; @end @interface JWTCryptoKeyPrivate : JWTCryptoKey - (instancetype)initWithP12Data:(NSData *)p12Data withPassphrase:(NSString *)passphrase parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error; //NS_DESIGNATED_INITIALIZER; - (instancetype)initWithP12AtURL:(NSURL *)url withPassphrase:(NSString *)passphrase parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error; @end ================================================ FILE: Sources/JWT/include/JWTCryptoKeyExtractor+FluentStyle.h ================================================ // // JWTCryptoKeyExtractor+FluentStyle.h // JWT // // Created by Dmitry Lobanov on 07/06/2019. // Copyright © 2019 JWTIO. All rights reserved. // #import "JWTCryptoKeyExtractor.h" #import "JWTDeprecations.h" #if DEPLOYMENT_RUNTIME_SWIFT #else NS_ASSUME_NONNULL_BEGIN // Fluent ( Objective-C exclusive ). @interface JWTCryptoKeyExtractor (FluentStyle) @property (copy, nonatomic, readonly) JWTCryptoKeyExtractor * (^keyBuilder)(JWTCryptoKeyBuilder *keyBuilder) NS_SWIFT_UNAVAILABLE(""); @end NS_ASSUME_NONNULL_END #endif ================================================ FILE: Sources/JWT/include/JWTCryptoKeyExtractor.h ================================================ // // JWTCryptoKeyExtractor.h // JWT // // Created by Lobanov Dmitry on 04.02.17. // Copyright © 2017 JWTIO. All rights reserved. // #import #import @protocol JWTCryptoKeyProtocol; @class JWTCryptoKeyBuilder; @protocol JWTCryptoKeyExtractorProtocol @optional - (id)keyFromString:(NSString *)string parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error; - (id)keyFromData:(NSData *)data parameters:(NSDictionary *)parameters error:(NSError *__autoreleasing*)error; @end @interface JWTCryptoKeyExtractor : NSObject @property (copy, nonatomic, readonly) NSString *type; @property (copy, nonatomic, readonly, class) NSString *type; @property (copy, nonatomic, readonly, class) NSString *parametersKeyCertificatePassphrase; #pragma mark - Getters @property (strong, nonatomic, readonly) JWTCryptoKeyBuilder *internalKeyBuilder; @end @interface JWTCryptoKeyExtractor (Setters) - (instancetype)configuredByKeyBuilder:(JWTCryptoKeyBuilder *)keyBuilder; @end @interface JWTCryptoKeyExtractor (ClassCluster) + (instancetype)publicKeyWithCertificate; + (instancetype)privateKeyInP12; + (instancetype)publicKeyWithPEMBase64; + (instancetype)privateKeyWithPEMBase64; + (instancetype)createWithType:(NSString *)type; @end ================================================ FILE: Sources/JWT/include/JWTCryptoSecurity+ErrorHandling.h ================================================ // // JWTCryptoSecurity+ErrorHandling.h // JWT // // Created by Dmitry Lobanov on 08.08.2018. // Copyright © 2018 JWTIO. All rights reserved. // #import #import "JWTCryptoSecurity.h" @interface JWTCryptoSecurity (ErrorHandling) + (NSError *)securityErrorWithOSStatus:(OSStatus)status; @end ================================================ FILE: Sources/JWT/include/JWTCryptoSecurity+ExternalRepresentation.h ================================================ // // JWTCryptoSecurity+ExternalRepresentation.h // JWT // // Created by Dmitry Lobanov on 08.08.2018. // Copyright © 2018 JWTIO. All rights reserved. // #import #import "JWTCryptoSecurity.h" @interface JWTCryptoSecurity (ExternalRepresentation) + (NSData *)externalRepresentationForKey:(SecKeyRef)key error:(NSError *__autoreleasing*)error; @end ================================================ FILE: Sources/JWT/include/JWTCryptoSecurity+Extraction.h ================================================ // // JWTCryptoSecurity+Extraction.h // JWT // // Created by Dmitry on 7/31/18. // Copyright © 2018 JWTIO. All rights reserved. // #import "JWTCryptoSecurity.h" // content is Base64 string, all '\n' are removed. @interface JWTCryptoSecurityComponent : NSObject @property (copy, nonatomic, readwrite) NSString *content; @property (copy, nonatomic, readwrite) NSString *type; - (instancetype)initWithContent:(NSString *)content type:(NSString *)type; @end @interface JWTCryptoSecurityComponents : NSObject @property (copy, nonatomic, readonly, class) NSString *Certificate; @property (copy, nonatomic, readonly, class) NSString *PrivateKey; @property (copy, nonatomic, readonly, class) NSString *PublicKey; @property (copy, nonatomic, readonly, class) NSString *Key; // Public or Private @property (copy, nonatomic, readonly) NSArray *components; + (NSArray *)components:(NSArray *)components ofType:(NSString *)type; - (NSArray *)componentsOfType:(NSString *)type; @end @interface JWTCryptoSecurity (Extraction) + (JWTCryptoSecurityComponents *)componentsFromFile:(NSURL *)url; + (JWTCryptoSecurityComponents *)componentsFromFileContent:(NSString *)content; @end ================================================ FILE: Sources/JWT/include/JWTCryptoSecurity.h ================================================ // // JWTCryptoSecurity.h // JWT // // Created by Lobanov Dmitry on 04.02.17. // Copyright © 2017 JWTIO. All rights reserved. // #import #import #import "JWTDeprecations.h" // Thanks for https://github.com/TakeScoop/SwiftyRSA! @interface JWTCryptoSecurityKeysTypes : NSObject + (NSString *)RSA; + (NSString *)EC; @end @interface JWTCryptoSecurity : NSObject + (NSString *)keyTypeRSA __deprecated_with_replacement("JWTCryptoSecurityKeysTypes.RSA"); + (NSString *)keyTypeEC __deprecated_with_replacement("JWTCryptoSecurityKeysTypes.EC"); @end @interface JWTCryptoSecurity (KeysManipulation) + (SecKeyRef)addKeyWithData:(NSData *)data asPublic:(BOOL)public tag:(NSString *)tag type:(NSString *)type error:(NSError *__autoreleasing*)error; + (SecKeyRef)addKeyWithData:(NSData *)data asPublic:(BOOL)public tag:(NSString *)tag error:(NSError *__autoreleasing*)error; + (SecKeyRef)keyByTag:(NSString *)tag error:(NSError *__autoreleasing*)error; + (BOOL)removeKeyByTag:(NSString *)tag error:(NSError *__autoreleasing*)error; @end @interface JWTCryptoSecurity (Certificates) + (OSStatus)extractIdentityAndTrustFromPKCS12:(CFDataRef)inPKCS12Data password:(CFStringRef)password identity:(SecIdentityRef *)outIdentity trust:(SecTrustRef *)outTrust __deprecated_with_replacement("[JWTCryptoSecurity extractIdentityAndTrustFromPKCS12:(CFDataRef)inPKCS12Data password:(CFStringRef)password identity:(SecIdentityRef *)outIdentity trust:(SecTrustRef *)outTrust error:(CFErrorRef *)error]"); + (OSStatus)extractIdentityAndTrustFromPKCS12:(CFDataRef)inPKCS12Data password:(CFStringRef)password identity:(SecIdentityRef *)outIdentity trust:(SecTrustRef *)outTrust error:(CFErrorRef *)error; + (SecKeyRef)publicKeyFromCertificate:(NSData *)certificateData; @end @interface JWTCryptoSecurity (PublicKey) + (NSData *)dataByRemovingPublicKeyHeader:(NSData *)data error:(NSError *__autoreleasing*)error; + (NSData *)dataByExtractingKeyFromANS1:(NSData *)data error:(NSError *__autoreleasing*)error; @end ================================================ FILE: Sources/JWT/include/JWTDeprecations.h ================================================ // // JWTDeprecations.h // JWT // // Created by Lobanov Dmitry on 31.08.16. // Copyright © 2016 Karma. All rights reserved. // #ifndef JWTDeprecations_h #define JWTDeprecations_h #import #define JWT_STR(str) #str #define JWTVersion_2_1_0 2.1 #define JWTVersion_2_2_0 2.2 #define JWTVersion_3_0_0 3.0 #define __first_deprecated_in_release_version(version) __deprecated_msg("first deprecated in release version: " JWT_STR(version)) #define __deprecated_and_will_be_removed_in_release_version(version) __deprecated_msg("deprecated. will be removed in release version: "JWT_STR(version)) #define __available_in_release_version(version) __deprecated_msg("will be introduced in release version: " JWT_STR(version)) #define __jwt_technical_debt(debt) __deprecated_msg("Don't forget to inspect it later." JWT_STR(debt)) #define __deprecated_with_replacement(msg) __deprecated_msg("Use " JWT_STR(msg)) #endif /* JWTDeprecations_h */ #ifndef JWT_macOS #define JWT_macOS(VALUE) VALUE #endif #ifndef JWT_iOS #define JWT_iOS(VALUE) VALUE #endif #ifndef JWT_tvOS #define JWT_tvOS(VALUE) VALUE #endif #ifndef JWT_watchOS #define JWT_watchOS(VALUE) VALUE #endif #ifndef JWT_COMPILE_TIME_AVAILABILITY #define JWT_COMPILE_TIME_AVAILABILITY(macOS, iOS, tvOS, watchOS) defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && (__MAC_OS_X_VERSION_MIN_REQUIRED >= macOS) \ || defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= iOS) \ || defined(__TV_OS_VERSION_MIN_REQUIRED) && (__TV_OS_VERSION_MIN_REQUIRED >= tvOS) \ || defined(__WATCH_OS_VERSION_MIN_REQUIRED) && (__WATCH_OS_VERSION_MIN_REQUIRED >= watchOS) #endif ================================================ FILE: Sources/JWT/include/JWTErrorDescription.h ================================================ // // JWTErrorDescription.h // JWT // // Created by Lobanov Dmitry on 27.11.16. // Copyright © 2016 JWTIO. All rights reserved. // #import extern NSString *JWTErrorDomain; typedef NS_ENUM(NSInteger, JWTError) { JWTUnexpectedError = -99, JWTInvalidFormatError, JWTUnsupportedAlgorithmError, JWTAlgorithmNameMismatchError, JWTInvalidSignatureError, JWTNoPayloadError, JWTNoHeaderError, JWTEncodingHeaderError, JWTEncodingPayloadError, JWTEncodingSigningError, JWTClaimsSetVerificationFailed, JWTInvalidSegmentSerializationError, JWTUnspecifiedAlgorithmError, JWTBlacklistedAlgorithmError, JWTDecodingHeaderError, JWTDecodingPayloadError, JWTDecodingHoldersChainEmptyError, JWTHolderSecretDataNotSetError }; @interface JWTErrorDescription : NSObject + (NSError *)errorWithCode:(JWTError)code; @end ================================================ FILE: Sources/JWT/include/JWTRSAlgorithm.h ================================================ // // Created by Marcelo Schroeder on 12/03/2016. // Copyright (c) 2016 Karma. All rights reserved. // #import #import "JWTAlgorithm.h" @protocol JWTCryptoKeyProtocol; @protocol JWTAsymmetricKeysAlgorithm @optional @property(nonatomic, readwrite, copy) NSString *keyExtractorType; @property(nonatomic, readwrite, strong) id signKey; @property(nonatomic, readwrite, strong) id verifyKey; @end @protocol JWTRSAlgorithm @required @property(nonatomic, readwrite, copy) NSString *privateKeyCertificatePassphrase; @end ================================================ FILE: Tests/JWTTests/Helpers/JWTAssetAccessor.m ================================================ // // JWTAssetAccessor.m // Tests // // Created by Dmitry Lobanov on 05.01.2022. // #import "JWTAssetAccessor.h" #import "resource_bundle_accessor.h" @implementation JWTAssetAccessor (FolderAccess) - (NSString *)stringFromFileWithName:(NSString *)name { __auto_type data = [self dataFromFileWithName:name]; return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; } - (NSData *)dataFromFileWithName:(NSString *)name { __auto_type asset = [self assetFromFileWithName:name]; __auto_type data = asset.data; return data; } - (NSDataAsset *)assetFromFileWithName:(NSString *)name { __auto_type path = [self.folder stringByAppendingPathComponent:name]; __auto_type bundle = SWIFTPM_MODULE_BUNDLE; __auto_type asset = [[NSDataAsset alloc] initWithName:path bundle:bundle]; return asset; } @end @implementation JWTAssetAccessor (Getters) - (NSString *)privateKeyBase64 { return [self stringFromFileWithName:@"private.pem"]; } - (NSString *)publicKeyBase64 { return [self stringFromFileWithName:@"public.pem"]; } - (NSString *)certificateBase64 { return [self stringFromFileWithName:@"certificate.cer"]; } - (NSData *)p12Data { return [self dataFromFileWithName:@"private.p12"]; } - (NSString *)p12Password { return [self stringFromFileWithName:@"p12_password.txt"]; } @end @implementation JWTAssetAccessor - (instancetype)initWithFolder:(NSString *)folder { if (self = [super init]) { self.folder = folder; // check that data exists! if (!self.check) { return nil; } } return self; } - (instancetype)initWithAlgorithmType:(NSString *)type shaSize:(NSNumber *)size { return [self initWithFolder:[type stringByAppendingPathComponent:size.description]]; } + (NSArray *)typeAndSizeFromAlgorithmName:(NSString *)name { if (name.length < 3) { return nil; } __auto_type type = [name substringToIndex:2]; __auto_type size = [name substringFromIndex:2]; if (type == nil || size == nil) { return nil; } return @[type, size]; } - (instancetype)initWithAlgorithName:(NSString *)name { // split name into type and size. // just lowercase everything. return [self initWithFolder:name.lowercaseString]; } @end @implementation JWTAssetAccessor (Validation) - (nullable instancetype)checked { return self.check ? self : nil; } - (BOOL)check { return [self assetFromFileWithName:@"private.pem"] != nil; } @end ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es256/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "provides-namespace" : true } } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es256/certificate.cer.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "ec-prime256v1.cer" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es256/certificate.cer.dataset/ec-prime256v1.cer ================================================ -----BEGIN CERTIFICATE----- MIIB3TCCAYQCCQDhm7YZ2lZMCDAKBggqhkjOPQQDAjB3MQswCQYDVQQGEwJHQjEP MA0GA1UECAwGTG9uZG9uMQ8wDQYDVQQHDAZMb25kb24xGDAWBgNVBAoMD0dsb2Jh bCBTZWN1cml0eTEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDEUMBIGA1UEAwwLZXhh bXBsZS5jb20wHhcNMTgwNzMxMjA1NTQ2WhcNMTgwODMwMjA1NTQ2WjB3MQswCQYD VQQGEwJHQjEPMA0GA1UECAwGTG9uZG9uMQ8wDQYDVQQHDAZMb25kb24xGDAWBgNV BAoMD0dsb2JhbCBTZWN1cml0eTEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDEUMBIG A1UEAwwLZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS6NgwU Xdcx1suUaVt7tBcFmLy0Q5QX74rS+xzFbmNjvnTuP4EF/f4G8GVxWIAD+DGMee5T 3wrFvX/eIkO2cvNEMAoGCCqGSM49BAMCA0cAMEQCIEz5wCyBUEHwSR5WTzHoPNIU 20aaAVscEX04QyA5nuyJAiBSYB04ZDmuqwk0NWFN8vXyCo1dKlHFIyg+txfLMyag 0w== -----END CERTIFICATE----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es256/original.private.pem.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "ec-prime256v1-private.pem" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es256/original.private.pem.dataset/ec-prime256v1-private.pem ================================================ -----BEGIN EC PRIVATE KEY----- MHcCAQEEIPeN6twH/ywfgaKRjU4RRTJG9TzVWF9ZHvjQXCpukBD8oAoGCCqGSM49 AwEHoUQDQgAEujYMFF3XMdbLlGlbe7QXBZi8tEOUF++K0vscxW5jY7507j+BBf3+ BvBlcViAA/gxjHnuU98Kxb1/3iJDtnLzRA== -----END EC PRIVATE KEY----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es256/original.public.pem.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "ec-prime256v1-public.pem" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es256/original.public.pem.dataset/ec-prime256v1-public.pem ================================================ -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEujYMFF3XMdbLlGlbe7QXBZi8tEOU F++K0vscxW5jY7507j+BBf3+BvBlcViAA/gxjHnuU98Kxb1/3iJDtnLzRA== -----END PUBLIC KEY----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es256/p12_password.txt.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "ec-prime256v1-p12-password.txt" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es256/p12_password.txt.dataset/ec-prime256v1-p12-password.txt ================================================ password ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es256/private.p12.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "ec-prime256v1-private.p12" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es256/private.pem.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "ec-prime256v1-private.pem" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es256/private.pem.dataset/ec-prime256v1-private.pem ================================================ -----BEGIN EC PRIVATE KEY----- BLo2DBRd1zHWy5RpW3u0FwWYvLRDlBfvitL7HMVuY2O-dO4_gQX9_gbwZXFYgAP4MYx57lPfCsW9f94iQ7Zy80T3jercB_8sH4GikY1OEUUyRvU81VhfWR740FwqbpAQ_A -----END EC PRIVATE KEY----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es256/public.pem.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "ec-prime256v1-public.pem" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es256/public.pem.dataset/ec-prime256v1-public.pem ================================================ -----BEGIN PUBLIC KEY----- BLo2DBRd1zHWy5RpW3u0FwWYvLRDlBfvitL7HMVuY2O-dO4_gQX9_gbwZXFYgAP4MYx57lPfCsW9f94iQ7Zy80Q -----END PUBLIC KEY----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es384/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "provides-namespace" : true } } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es384/certificate.cer.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "ec-secp384r1.cer" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es384/certificate.cer.dataset/ec-secp384r1.cer ================================================ -----BEGIN CERTIFICATE----- MIICGzCCAaECCQC4+VxcfXk0UTAKBggqhkjOPQQDAjB3MQswCQYDVQQGEwJHQjEP MA0GA1UECAwGTG9uZG9uMQ8wDQYDVQQHDAZMb25kb24xGDAWBgNVBAoMD0dsb2Jh bCBTZWN1cml0eTEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDEUMBIGA1UEAwwLZXhh bXBsZS5jb20wHhcNMTgwNzMxMjA1NTU3WhcNMTgwODMwMjA1NTU3WjB3MQswCQYD VQQGEwJHQjEPMA0GA1UECAwGTG9uZG9uMQ8wDQYDVQQHDAZMb25kb24xGDAWBgNV BAoMD0dsb2JhbCBTZWN1cml0eTEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDEUMBIG A1UEAwwLZXhhbXBsZS5jb20wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATFBX/XSrL3 Bb94PKHu/CyrtkXgyeCnbWUltmG0/qomAdlpa9XMHk/gp5Cf7tKEa8Fp5c7LKAr7 6U702QPDg2N/Y5sv8CwzgYM4L3eqGBTAK0aHYty1nh39YyYG6Hrw46EwCgYIKoZI zj0EAwIDaAAwZQIwRj8hKXv27JaAarWAT8Kp9qtV+XODUwdg61seaaJtW9rUgAmg VL8TzqvucbG1JlxcAjEA+Ygwp2l6sPAPelZDVnhyET260PDQp0vCKf/kq9OHceIg AaxGeQF/bzaEfVdB66U7 -----END CERTIFICATE----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es384/original.private.pem.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "ec-secp384r1-private.pem" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es384/original.private.pem.dataset/ec-secp384r1-private.pem ================================================ -----BEGIN EC PRIVATE KEY----- MIGkAgEBBDA4MOBnImNGKyrmWrpm+zJJYdzylhvpAGaCXAQK7gNpLIGkkK+t/E5J MEPP2F/rFM6gBwYFK4EEACKhZANiAATFBX/XSrL3Bb94PKHu/CyrtkXgyeCnbWUl tmG0/qomAdlpa9XMHk/gp5Cf7tKEa8Fp5c7LKAr76U702QPDg2N/Y5sv8CwzgYM4 L3eqGBTAK0aHYty1nh39YyYG6Hrw46E= -----END EC PRIVATE KEY----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es384/original.public.pem.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "ec-secp384r1-public.pem" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es384/original.public.pem.dataset/ec-secp384r1-public.pem ================================================ -----BEGIN PUBLIC KEY----- MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAExQV/10qy9wW/eDyh7vwsq7ZF4Mngp21l JbZhtP6qJgHZaWvVzB5P4KeQn+7ShGvBaeXOyygK++lO9NkDw4Njf2ObL/AsM4GD OC93qhgUwCtGh2LctZ4d/WMmBuh68OOh -----END PUBLIC KEY----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es384/p12_password.txt.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "ec-secp384r1-p12-password.txt" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es384/p12_password.txt.dataset/ec-secp384r1-p12-password.txt ================================================ password ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es384/private.p12.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "ec-secp384r1-private.p12" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es384/private.pem.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "ec-secp384r1-private.pem" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es384/private.pem.dataset/ec-secp384r1-private.pem ================================================ -----BEGIN EC PRIVATE KEY----- BMUFf9dKsvcFv3g8oe78LKu2ReDJ4KdtZSW2YbT-qiYB2Wlr1cweT-CnkJ_u0oRrwWnlzssoCvvpTvTZA8ODY39jmy_wLDOBgzgvd6oYFMArRodi3LWeHf1jJgboevDjoTgw4GciY0YrKuZaumb7Mklh3PKWG-kAZoJcBAruA2ksgaSQr638TkkwQ8_YX-sUzg -----END EC PRIVATE KEY----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es384/public.pem.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "ec-secp384r1-public.pem" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es384/public.pem.dataset/ec-secp384r1-public.pem ================================================ -----BEGIN PUBLIC KEY----- BMUFf9dKsvcFv3g8oe78LKu2ReDJ4KdtZSW2YbT-qiYB2Wlr1cweT-CnkJ_u0oRrwWnlzssoCvvpTvTZA8ODY39jmy_wLDOBgzgvd6oYFMArRodi3LWeHf1jJgboevDjoQ -----END PUBLIC KEY----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es512/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "provides-namespace" : true } } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es512/certificate.cer.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "ec-secp521r1.cer" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es512/certificate.cer.dataset/ec-secp521r1.cer ================================================ -----BEGIN CERTIFICATE----- MIICZjCCAccCCQChvb7gSTjeHjAKBggqhkjOPQQDAjB3MQswCQYDVQQGEwJHQjEP MA0GA1UECAwGTG9uZG9uMQ8wDQYDVQQHDAZMb25kb24xGDAWBgNVBAoMD0dsb2Jh bCBTZWN1cml0eTEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDEUMBIGA1UEAwwLZXhh bXBsZS5jb20wHhcNMTgwNzMxMjA1NzA3WhcNMTgwODMwMjA1NzA3WjB3MQswCQYD VQQGEwJHQjEPMA0GA1UECAwGTG9uZG9uMQ8wDQYDVQQHDAZMb25kb24xGDAWBgNV BAoMD0dsb2JhbCBTZWN1cml0eTEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDEUMBIG A1UEAwwLZXhhbXBsZS5jb20wgZswEAYHKoZIzj0CAQYFK4EEACMDgYYABABV4DpG pq38eStMgLV7g80lhF07JABVu/1fp+FvCIodZYd1xdHnYIBfN3h7jSRR5atRlMw+ EBVUBMLwy99yAGokdQFM91nnYnLGefYeRV/mF/QLQ+BUp0tLcydJ0N9BLPQUJG/F dl+GjZqConuRy/Q7wDhEFYJCnjPJO89BoNSdNUEpZjAKBggqhkjOPQQDAgOBjAAw gYgCQgErm1sEymoMYg3KSoQAuNvpPyO/Qe+F7TJJWVmLlKkEeqe0WanqMEgN1KP0 ETICemzCaYZ+o/TUEKVNLXfFuGRr3AJCAelJBXK2+CcLAS/A69TGOOV7YOkUaqHh MnnY0SO0Gd0a5/uti1JzFc1PNxnH45yEqjiX82peGAaDQwBtIMYBDUqk -----END CERTIFICATE----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es512/original.private.pem.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "ec-secp521r1-private.pem" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es512/original.private.pem.dataset/ec-secp521r1-private.pem ================================================ -----BEGIN EC PRIVATE KEY----- MIHcAgEBBEIByPhQcUtwTm2SGGHwRbp36v53CgXQTG7dNGnjJ6xHmNi67L+hvYhO ioqRZGGtUgfCZ3IZnSpelkw/HYfAAIjNkbagBwYFK4EEACOhgYkDgYYABABV4DpG pq38eStMgLV7g80lhF07JABVu/1fp+FvCIodZYd1xdHnYIBfN3h7jSRR5atRlMw+ EBVUBMLwy99yAGokdQFM91nnYnLGefYeRV/mF/QLQ+BUp0tLcydJ0N9BLPQUJG/F dl+GjZqConuRy/Q7wDhEFYJCnjPJO89BoNSdNUEpZg== -----END EC PRIVATE KEY----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es512/original.public.pem.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "ec-secp521r1-public.pem" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es512/original.public.pem.dataset/ec-secp521r1-public.pem ================================================ -----BEGIN PUBLIC KEY----- MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAVeA6Rqat/HkrTIC1e4PNJYRdOyQA Vbv9X6fhbwiKHWWHdcXR52CAXzd4e40kUeWrUZTMPhAVVATC8MvfcgBqJHUBTPdZ 52Jyxnn2HkVf5hf0C0PgVKdLS3MnSdDfQSz0FCRvxXZfho2agqJ7kcv0O8A4RBWC Qp4zyTvPQaDUnTVBKWY= -----END PUBLIC KEY----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es512/p12_password.txt.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "ec-secp521r1-p12-password.txt" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es512/p12_password.txt.dataset/ec-secp521r1-p12-password.txt ================================================ password ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es512/private.p12.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "ec-secp521r1-private.p12" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es512/private.pem.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "ec-secp521r1-private.pem" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es512/private.pem.dataset/ec-secp521r1-private.pem ================================================ -----BEGIN EC PRIVATE KEY----- BABV4DpGpq38eStMgLV7g80lhF07JABVu_1fp-FvCIodZYd1xdHnYIBfN3h7jSRR5atRlMw-EBVUBMLwy99yAGokdQFM91nnYnLGefYeRV_mF_QLQ-BUp0tLcydJ0N9BLPQUJG_Fdl-GjZqConuRy_Q7wDhEFYJCnjPJO89BoNSdNUEpZgHI-FBxS3BObZIYYfBFunfq_ncKBdBMbt00aeMnrEeY2Lrsv6G9iE6KipFkYa1SB8JnchmdKl6WTD8dh8AAiM2Rtg -----END EC PRIVATE KEY----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es512/public.pem.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "ec-secp521r1-public.pem" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/es512/public.pem.dataset/ec-secp521r1-public.pem ================================================ -----BEGIN PUBLIC KEY----- BABV4DpGpq38eStMgLV7g80lhF07JABVu_1fp-FvCIodZYd1xdHnYIBfN3h7jSRR5atRlMw-EBVUBMLwy99yAGokdQFM91nnYnLGefYeRV_mF_QLQ-BUp0tLcydJ0N9BLPQUJG_Fdl-GjZqConuRy_Q7wDhEFYJCnjPJO89BoNSdNUEpZg -----END PUBLIC KEY----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs256/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "provides-namespace" : true } } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs256/certificate.cer.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "rsa-2048.cer" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs256/certificate.cer.dataset/rsa-2048.cer ================================================ -----BEGIN CERTIFICATE----- MIIDajCCAlICCQD6TDhyi4F/+jANBgkqhkiG9w0BAQsFADB3MQswCQYDVQQGEwJH QjEPMA0GA1UECAwGTG9uZG9uMQ8wDQYDVQQHDAZMb25kb24xGDAWBgNVBAoMD0ds b2JhbCBTZWN1cml0eTEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDEUMBIGA1UEAwwL ZXhhbXBsZS5jb20wHhcNMTgwNzMxMjA1MDI1WhcNMTgwODMwMjA1MDI1WjB3MQsw CQYDVQQGEwJHQjEPMA0GA1UECAwGTG9uZG9uMQ8wDQYDVQQHDAZMb25kb24xGDAW BgNVBAoMD0dsb2JhbCBTZWN1cml0eTEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDEU MBIGA1UEAwwLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQDJ0wVVrZjnhEF0F+mx1PRFlPSL04jYv3rwxF6/o3Y8WokL8UzC635Xg0ZE 0sm7YBbNWN89JRvK4HfzK0odLo+8o8bM/HxrmPRkgbAszZQV72SdVmVjXqfC+Qip UVNLE4lvzQz7w6pld3lMUdXljDgtUy96HqN4LzZbOUyFy3C2LaDF7msaE+udWsT0 cqUyEpxjNyzU8CGYxZ9E+ldHvwXpV0ILJMtCmFLWx4TlQsCOL5J4vKa1xP6s9Cif x7D9duXppVozqQar7jJqLLHEfm1v46bACKH4Cx9khxfMBVP6F1aWUhAa/t2G2mlf OCrIEheljj/jO708ak5UbDu66hhDAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIJ5 hy/iYbtWri1uV+vrSJ/bwCRO7liYcSEAZA1Ao0PK2LDMI6gqZ0/TBJZR0NR8P9Ep k+MZ+u7g7t/MF4Pn6fXppnsP7Jie63csg+WLSs+hykLUNAcAbW4wYO5XvTRJ1+4a SgoOhWrJODTkIU7fyqDNZhcXqobr+j9DRPd6E+Noj410c/+8ugUKrYJ/SVJbyvmm oEbrpCMuKzboZZmeOIkYYlCs/xkxi8IjDiqpUVWkxvf7ml/PAXRKAsekE77UXETH j82ZwkPk9373cnLbmyJBJoLt5FmuncQsvXDcq+FlLeJ/DvAwGoI4KbtB+SW+e4lC XDKyt5fnEF2owfBI3tA= -----END CERTIFICATE----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs256/p12_password.txt.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "rsa-2048-p12-password.txt" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs256/p12_password.txt.dataset/rsa-2048-p12-password.txt ================================================ password ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs256/private.p12.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "rsa-2048-private.p12" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs256/private.pem.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "rsa-2048-private.pem" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs256/private.pem.dataset/rsa-2048-private.pem ================================================ -----BEGIN RSA PRIVATE KEY----- MIIEpQIBAAKCAQEAydMFVa2Y54RBdBfpsdT0RZT0i9OI2L968MRev6N2PFqJC/FM wut+V4NGRNLJu2AWzVjfPSUbyuB38ytKHS6PvKPGzPx8a5j0ZIGwLM2UFe9knVZl Y16nwvkIqVFTSxOJb80M+8OqZXd5TFHV5Yw4LVMveh6jeC82WzlMhctwti2gxe5r GhPrnVrE9HKlMhKcYzcs1PAhmMWfRPpXR78F6VdCCyTLQphS1seE5ULAji+SeLym tcT+rPQon8ew/Xbl6aVaM6kGq+4yaiyxxH5tb+OmwAih+AsfZIcXzAVT+hdWllIQ Gv7dhtppXzgqyBIXpY4/4zu9PGpOVGw7uuoYQwIDAQABAoIBAQCxutwazEo3rzc4 tgo9aWxHjlogfIMpZM4uEq/hkWCA27WOR8uyZ1GWXWtXFk1CbecGpLnKjdBAw5W+ FaQpuKQpmgxq3fnvgv3NOIvdmJhNDMkM6VVVwbh4sXfYK17vYWAJjYheebunqSOv eu2jPO0HtRa9Mxf/sYvrn7TsqfAy7MDOkPn8bDFYUPS1gM3rVRDjOk0f9N5mDsPp CgB5ji+lo+E4FYjkHwitmB6KQeqpHyZUfGiZWVYW7kuk/FJrdSCgSOSjlf4rLndO 9rfg8OR2nIK1Ol07VjOnEEv35lPPmAkKvfd3NJRLrBgZkVf4/IsQZpToXIzWIj2S zvYpmAdpAoGBAO1Q6+RZHMZ9xNNCXDOJvvaG4/seJjwyRwE8Q3DEJ3dLBwzpzcSl NXQkxJaG1hSKVzjrxhluXOtBj/bZUJ5dzaPfL6KXzecLWuwvHPTHbUk9rKrIRE01 vw9b7O3GuXciOVGacZh2BRvTWYih+9xEIiOzft/ULDI+RFXqcMK5AK0tAoGBANm2 xCqQYCBzRgZ2NjTaDS5DSoDFZ4pyH9fodUe9FKu2lVbWbQAoaoARvpo0EevjuOlk /mg91sSSr5hWVYqKXyHE3XueIhQqHbCDfPgWYx75Gavj+o94xva7H5Gm7dXIKTYb NfutkCFqHeUy2Omhv2YoRDL5ZP8jv/DTACXpBaEvAoGBAMslu1i048oSfXuu0ciY gKz+WYhsjaR4EYpAMScF8xbOVhG6zxcnqXNryhFlCTt6FSI3ylOYwtfsPrW736RB fjhqZJeVxX+jm8iUp//t+2J39igX2UgS2yPluBLvS3JtDI4LXHR7ivH/4SPyLeyn MmZHUDOAp/i2jr7ROoel4KtdAoGAOEtr+d2PHZTw/GbAqXXghp/bueRRW5ka5scy 3DPmDmiNwQB8+td4glkUQedI4wflHmSA7A9hYz7SrL9WKxaQdrji1D4VbcVeG/BD 9hpD0xRyMOIoPcTrHY1RImZZhTfWgCkVEljUte8sf8FgGTk7tnye9ddK6DYkQW8t 0J+qVv0CgYEAokrsy0SqGreBRFvvekSOK9jC+rFCkYcvfK6b7/Y30W6ZjP6Q27LL WJWpS5UKGiydOejk9vt3AhZ+FzWCmQyaHLWYo1Vha9WgPZXU7GPaPFnGjfBou+Wm Kx01RnN0AC4C1sqFV2GnbPZXt4sytSTrr0724pzvWm74To2JAzuGsBw= -----END RSA PRIVATE KEY----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs256/public.pem.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "rsa-2048-public.pem" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs256/public.pem.dataset/rsa-2048-public.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAydMFVa2Y54RBdBfpsdT0 RZT0i9OI2L968MRev6N2PFqJC/FMwut+V4NGRNLJu2AWzVjfPSUbyuB38ytKHS6P vKPGzPx8a5j0ZIGwLM2UFe9knVZlY16nwvkIqVFTSxOJb80M+8OqZXd5TFHV5Yw4 LVMveh6jeC82WzlMhctwti2gxe5rGhPrnVrE9HKlMhKcYzcs1PAhmMWfRPpXR78F 6VdCCyTLQphS1seE5ULAji+SeLymtcT+rPQon8ew/Xbl6aVaM6kGq+4yaiyxxH5t b+OmwAih+AsfZIcXzAVT+hdWllIQGv7dhtppXzgqyBIXpY4/4zu9PGpOVGw7uuoY QwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs256old/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "provides-namespace" : true } } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs256old/certificate.cer.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "rs256-cert.cer" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs256old/certificate.cer.dataset/rs256-cert.cer ================================================ -----BEGIN CERTIFICATE----- MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQsFADBKMR0wGwYDVQQDDBREaWdp dGFsIFNpZ25pbmcgVGVzdDELMAkGA1UEBhMCQVUxHDAaBgkqhkiG9w0BCQEWDXRl c3RAdGVzdC5jb20wHhcNMTYwMzEwMjM0ODQ2WhcNMTcwMzEwMjM0ODQ2WjBKMR0w GwYDVQQDDBREaWdpdGFsIFNpZ25pbmcgVGVzdDELMAkGA1UEBhMCQVUxHDAaBgkq hkiG9w0BCQEWDXRlc3RAdGVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQD2G4yWiZX9H4CsbWWpHT/bfRid7yU569j9f2gSB6kYv9wMsd/Crx2p HwIT5uK9gTJ4+5PYaeweB3Tu7uo9ob4EG83k2VF26ruRflzBaSzE4TotxuNoE83B VKFoR1oPdg3BmT7qPCRshz6b36zXfxVQgBYU2F2nUQKbjqCiFEs6w2VrbG5RQwHL EwmLwDu3WPFOwuO2aPP0dRh1E25DeZlzqNFcYaoAf5wEmwWn79oOmzETWh0uTHTg dCrZSp48ZvXf9iFZgqd5HIt0Ub5x5ZYuSZz5FJ8GRRp/0s4q4FG2T0XHsUkvnoMO KGkPUmkpFk4CKZa5BnnKIDGQMr2ndjaNAgMBAAGjRDBCMA4GA1UdDwEB/wQEAwIH gDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDBDAYBgNVHREEETAPgQ10ZXN0QHRlc3Qu Y29tMA0GCSqGSIb3DQEBCwUAA4IBAQDcOYflkAlubGJlv5T1G7PdcHzMzu6doah/ 9RmRyHS8wehc0GljYIyBkhbBG/iRumi6nnnU3BARv+JdSHbpIVsRaXmImWv5I/GO OfUO6UY7jlsw1mCjQyIIZoOFyUKnbcvrb0bCryD3rcbAflYg8feq3AiQv3CacxOy IbYh3khqbs1jKSAzxEdcsuHRB+by5gpwMfF5ByGdMmMl81mFMUuGlcWsfZp2N4Vz 7MWVRl38OWkwZ0yw/Jpd1kcVwKIrXF3rjA71AN41rzyMvvPaEfdgCyFolixEOoJH Fdidq1Bf0liKxf+MFJOaxSWKGqrvzPoBfmwCFoPahuaUlVZ4lGvr -----END CERTIFICATE----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs256old/p12_password.txt.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "password.txt" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs256old/p12_password.txt.dataset/password.txt ================================================ password ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs256old/private.p12.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "rs256-private.p12" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs256old/private.pem.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "rs256-private.pem" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs256old/private.pem.dataset/rs256-private.pem ================================================ -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA9huMlomV/R+ArG1lqR0/230Yne8lOevY/X9oEgepGL/cDLHf wq8dqR8CE+bivYEyePuT2GnsHgd07u7qPaG+BBvN5NlRduq7kX5cwWksxOE6Lcbj aBPNwVShaEdaD3YNwZk+6jwkbIc+m9+s138VUIAWFNhdp1ECm46gohRLOsNla2xu UUMByxMJi8A7t1jxTsLjtmjz9HUYdRNuQ3mZc6jRXGGqAH+cBJsFp+/aDpsxE1od Lkx04HQq2UqePGb13/YhWYKneRyLdFG+ceWWLkmc+RSfBkUaf9LOKuBRtk9Fx7FJ L56DDihpD1JpKRZOAimWuQZ5yiAxkDK9p3Y2jQIDAQABAoIBAQDEu88Nw5xvxNAS hjz/DE+wwHZ+Qd6LR7qlIkTqLM+C5lQcndBWi6/1MsFxcV8NyAq15b4RANNsSd+y 5K/BZttD44oah5J0sj4Ql2fEgLP2Cml8kIHXAAW5p1KDzo3y0Bc9DKjbjAo963sk FZDQj1lViZ6dOTzcdIjWGxTTm89rf5frVPUJxNFB+VRHWuyRGudXzGw6g0EX0vMx 92PFy3NFFSczgRZS0rx+PEN/kYBThdZoWcBnhfq2YLLW5ID0urs6vs2QqGZK/AQE B3DezX6arlHvyjOtb9oYl9QV5YG1faqgE9YWQvmkxKHvitcTTYA6fgn7KhCqZmno F2WrtkDNAoGBAP5tDiFPGonvZJB4KEmWITqWiYFdlZ9yJ5r1mIRywuJQJ6NCwADd v3qvGnjpI4NUFNHvuPr+PYXGi8wlvKGXO7EkO7DyB5hs7LiKyppUBH/Vb4KopAFo ceG/2B21g0AeF6RuRshWIQwqAzTmz+T4+Kj8WE6e146a3L7TNOM5yOrjAoGBAPeh Ud9hciqlr/8OhnUUIRUC67F3CBjBl7xnDy+00MPe0A1SsKODBQOTQRq/mr75AM8F IwI7wTo0joj4x8LP43YUeOUHUapQoX1AUzAlaZhd5m2wAUOkip15P0mw/GpN9brl s3BRZ7DHNzyIay9htM+8YGzUEPwUdyQmln6js+PPAoGAdx7gKsA6kLJAx1M6qZlc 3W1129fRIeH0oRyz1+9TR1p39HxgIQexiuNI5atiMS7AwLoYRYubinK3KVHRy2Zf UETCncnzvG3jN1PkH/WOVbu8hdQnVXFtQGDt8pr1ZKOyNg5bnZiVyHgzICWg2Hep FJVxUv4TtnTTPZTtgiWf6DkCgYEAsAghp2YiPmbiIbI1quzQR5t36QPw4YhdUTUB +qvS7CpsQ8xQfSwaWFxJn7YtTyy7gm7oYCISTkomOQCBIN+flsUe29DEIQqIgf1E Jamy0vmNYNQJUgiZ8S/L6ZrDFN6unFnFoUZ9K5GylnlzmI8gdbw336UxHcF+oFg+ C3Bb5MkCgYBuPywM9nuF8EbeuHCl/3LRkVaNwRwFjgb7NV47E30+3YoM6qvcDG1q iAi5KixQfk1oW1GGdvMOzOIK+AseKZNxuYwAjynNr6iGyMnPAvaVfv8ZcbmAe1Dx eX8OG0k/j128DnQZd6Be3yl9qH8eOqCv7eZpe0xO0uZjeyA7TFAEhg== -----END RSA PRIVATE KEY----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs256old/public.pem.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "rs256-public.pem" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs256old/public.pem.dataset/rs256-public.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9huMlomV/R+ArG1lqR0/ 230Yne8lOevY/X9oEgepGL/cDLHfwq8dqR8CE+bivYEyePuT2GnsHgd07u7qPaG+ BBvN5NlRduq7kX5cwWksxOE6LcbjaBPNwVShaEdaD3YNwZk+6jwkbIc+m9+s138V UIAWFNhdp1ECm46gohRLOsNla2xuUUMByxMJi8A7t1jxTsLjtmjz9HUYdRNuQ3mZ c6jRXGGqAH+cBJsFp+/aDpsxE1odLkx04HQq2UqePGb13/YhWYKneRyLdFG+ceWW Lkmc+RSfBkUaf9LOKuBRtk9Fx7FJL56DDihpD1JpKRZOAimWuQZ5yiAxkDK9p3Y2 jQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs384/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "provides-namespace" : true } } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs384/certificate.cer.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "rsa-3072.cer" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs384/certificate.cer.dataset/rsa-3072.cer ================================================ -----BEGIN CERTIFICATE----- MIIEajCCAtICCQDGPcLvAf2Z+DANBgkqhkiG9w0BAQsFADB3MQswCQYDVQQGEwJH QjEPMA0GA1UECAwGTG9uZG9uMQ8wDQYDVQQHDAZMb25kb24xGDAWBgNVBAoMD0ds b2JhbCBTZWN1cml0eTEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDEUMBIGA1UEAwwL ZXhhbXBsZS5jb20wHhcNMTgwNzMxMjA1MTE3WhcNMTgwODMwMjA1MTE3WjB3MQsw CQYDVQQGEwJHQjEPMA0GA1UECAwGTG9uZG9uMQ8wDQYDVQQHDAZMb25kb24xGDAW BgNVBAoMD0dsb2JhbCBTZWN1cml0eTEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDEU MBIGA1UEAwwLZXhhbXBsZS5jb20wggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGK AoIBgQC+xNzoFmWqFIOVK27cv0hAoqEMMxjfWygAhn7x9xldQnGbekFsRhwDxdXm 7mdMyNZNp8cvXwP014WX1RPFyA19LTr7UBfK/z+QbmIpL2ujWqZfQTHkCzfQ1htw BkS891IXz8s5nk5iYUPVzgRH78z7OG4BQg5Bg1lREVrZzqNfvKbSzhbK2J3I2kZx sevvUIz0vBxNcAmU02ZpoLbSA7LgeMMxCovRwYLrf+QwxI0GhNVVE6Dm80lKxc+t 5LxLyPVl8Uw3u2gVq0HTkIys3TphRgWrkByrIf7PZVmqsL+Mn6RfmOHRB7l5vszK xpg/7iajOKGGVBW5LjLKehOdG+vSDFYIXWTVUb+4r5sUQv3/vHLO3a327OiLPYht Y+UXbO+5MWHYBYwbfQTk+ilkeR8YkhXUVhjHrwcsLPCiiO3FAQarPUDtA2j33PFL shevW63JO1YpjUj1CTcDqkfJHkYjtv65fhD2u4sZS/jRq4yhqMSx0T4bVpIdDgkK MBTMxTECAwEAATANBgkqhkiG9w0BAQsFAAOCAYEAhxIaH6QICDQkk9Rv+vh+ysnl 1o1RPwvk3dAr1cY9RDyiKbIzWJMPPa+quh2xZ+9ks4JDvPjnJb+MsZIYOsFiKzXq APkritHWyHFhK+nddVj7bpkrc7zorwm6csi9Xd0q0rpE3rlHNuMOycWO0/sd9vVE whJfqBO5MbDUqoTaXehnaycXDSN59JhHOze9E+JNu/9a+S7vZjX9qaHo2RIQwhVb lrAlHh35c2io5BUJME0ppyE/gVDxn9h60ABDVx1mlr0vr2Baw8rNUbURFhNcSMX1 EdqBOMMWZc8ui3LzBDFjZx/MWk/nbU7jwRpG4+Bdez6yjVAJvVeKQACCMVysQnWr QTRd1suXRVCo1spAF+kD+0YZa7fZVb0+SHAWCAJT5V4Q6aY8GhIZaCH36iuW8xub jKvBUqUuEbDjQwgHICKNw8/5G5VJJQecZ/NyA501dHsLLCTO+bTJ4jDTR3PKt7Bh ZsPrWvdf9Nmt0fm/TgQEY0uIE3hKJfxl89715ZFL -----END CERTIFICATE----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs384/p12_password.txt.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "rsa-3072-p12-password.txt" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs384/p12_password.txt.dataset/rsa-3072-p12-password.txt ================================================ password ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs384/private.p12.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "rsa-3072-private.p12" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs384/private.pem.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "rsa-3072-private.pem" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs384/private.pem.dataset/rsa-3072-private.pem ================================================ -----BEGIN RSA PRIVATE KEY----- MIIG5QIBAAKCAYEAvsTc6BZlqhSDlStu3L9IQKKhDDMY31soAIZ+8fcZXUJxm3pB bEYcA8XV5u5nTMjWTafHL18D9NeFl9UTxcgNfS06+1AXyv8/kG5iKS9ro1qmX0Ex 5As30NYbcAZEvPdSF8/LOZ5OYmFD1c4ER+/M+zhuAUIOQYNZURFa2c6jX7ym0s4W ytidyNpGcbHr71CM9LwcTXAJlNNmaaC20gOy4HjDMQqL0cGC63/kMMSNBoTVVROg 5vNJSsXPreS8S8j1ZfFMN7toFatB05CMrN06YUYFq5AcqyH+z2VZqrC/jJ+kX5jh 0Qe5eb7MysaYP+4mozihhlQVuS4yynoTnRvr0gxWCF1k1VG/uK+bFEL9/7xyzt2t 9uzoiz2IbWPlF2zvuTFh2AWMG30E5PopZHkfGJIV1FYYx68HLCzwoojtxQEGqz1A 7QNo99zxS7IXr1utyTtWKY1I9Qk3A6pHyR5GI7b+uX4Q9ruLGUv40auMoajEsdE+ G1aSHQ4JCjAUzMUxAgMBAAECggGADo3mbK6IwxkdkNvncWAGmyfNMakUVLYXrzKT rNI1VTAkisAhDamrqX4Ge7/kka8g6nvKborJOnzW7GaNQ6Gnpc01msbZids/dj11 r762b5gS6WGH9OYGNCChp0JTLDeSQ87Oqm6xfD//dOhq2zIoaWI8wkvP2p+yyMSS MdvaCwvRjnO6uW8dWp2MklAIuBFlL6bKYf4SPRCD17szN4Kguw97lNpBIJeq7Vys hCv6tmyb+gmtVPFqvhGpbpLs6rtCG/MGMnk0dAMUmPFfFzIXDg7iUWgSvSx7MhEO ilr6Xh7Rqr4UpF4pDYxxvodhbV7VwlJUxVojANDvOQ1ANntnr+unS7w6ma2tWB7L bzThBoZNViyLr/0RUoYrnizqrioFSskESGUVxVFSQfUa2lE4kTY1NAMYF+wOyq5p aGbSRvtFOPGLYF14pDK/yfZrO+3W0rZdGVowvDqNZ4tzML1aMBH/wCFvfy7wzwSv xRp3PYt3h36i9KgUJhB0Ln/bWguBAoHBAOEg8Mg/Z0l3o+3z2ZBkGjuRsF9wf1xz aKyw8Uti9fYc0MacvBd0kQxawiR3nIxxBu5LLZ05WsLJCSQ85bTing25JcEYhgDv sxCggAKsQP3IEOEPKOx7fPasU7i7J0BUWS6w8mNjlwx/GNVaIquAMUzownoYXejf QsuTfwuruyVYGQVPL6V/RpVi2+d6MSqlmoYVkrn0n4s+OAldtkxW6pOxdOWN2KFV qfVsKki3t+t3VcF8xiRG+sAID+4VfkPFtQKBwQDY7b0MZE0gMYme2vUHHQ4eBw2a PBMA5d0SGl31I8Q09ynxeLKAfzg2ORHexpayPx0wn0QA6sn3bB+3n2sn76tlIHA1 EO+6+T3r1zfX0bV15+WXSOUQjGL/6Iu6Xb2utu0hUjLDNLAfbCBSbCuduu59fZRd gLG0aQX6V7LGxohXsiJFU9Yy/iTBvXaikb8Tm09x/GdKW+8gTmTcWsOnWW9a+Afg Kmb/DWgAxuIap9Ue6X5aGcU1++Ok4JWhbTuBrw0CgcEAz6BrsKMZBR68J0bQDmTj 9LBms36zV3ZwwWPnBhncsgDdY29F4XP2GijSCIPv826Cb98R0IEG/cIfFja7u1mN Xya0dSPC4rYutVTw+oYW4ndTad1rZr50/6LrC+I/Twr7vR4gTh2ZP0MwigQ5GWZ/ EWlRgv1aDt1pYwtDDmZxkP1xBf6D+OQrGrc0DIYbNjPJEYRv7+R2CBt33tt4t2sp qNDu+I8bjZ/NwbTiQnJ9w0Ip6urCas6zj8tftbpI2wRJAoHBAMVYuqScVwHTrzRi U4lOKHquxfQrdMpbU5vVeua5zBS3SmQP/qwhkJzbnGND3PJ5sm96ZJ5E+snpho1B LXXedtmAAjR0nPNHLcrxNy9S67dA6UCRIzrDzIitIPjBsP9SETZAFkg6FYPwlRMG r0NGPRLS/Pd3TbMn3DVcNRraoEzPlJfnZjVruTq7x0KsPt1ybHrxOXKPYmLMjrtc oyQKm+BxRpDrYlnj81rJlAbV6m+90aHcUeoDppxnaBi8S+d1vQKBwQC4vU66vCvz EwJ+p0r1ZU9znSj0HQVo3Z6xdp9FvdWZ5pYvy3WzpkEHZmIyb6m6xyF45b9D4ypd PXgrejMHVv4TJ1Z2jFp2rlgKouFwCucWtJ9ujQ38unmBACEp9FlKqjS+FeiYxG0j MzCae4JENAjsfSmrZqppRQaENX6KX26XvUVVRT6GbETdr0rb4zFJaiAQX/x4VO3T Piut0mT+zeVCteBqZSZ3SAiEIcq1OBJVT7r6HWst40L5wOglK9pBMO0= -----END RSA PRIVATE KEY----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs384/public.pem.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "rsa-3072-public.pem" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs384/public.pem.dataset/rsa-3072-public.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAvsTc6BZlqhSDlStu3L9I QKKhDDMY31soAIZ+8fcZXUJxm3pBbEYcA8XV5u5nTMjWTafHL18D9NeFl9UTxcgN fS06+1AXyv8/kG5iKS9ro1qmX0Ex5As30NYbcAZEvPdSF8/LOZ5OYmFD1c4ER+/M +zhuAUIOQYNZURFa2c6jX7ym0s4WytidyNpGcbHr71CM9LwcTXAJlNNmaaC20gOy 4HjDMQqL0cGC63/kMMSNBoTVVROg5vNJSsXPreS8S8j1ZfFMN7toFatB05CMrN06 YUYFq5AcqyH+z2VZqrC/jJ+kX5jh0Qe5eb7MysaYP+4mozihhlQVuS4yynoTnRvr 0gxWCF1k1VG/uK+bFEL9/7xyzt2t9uzoiz2IbWPlF2zvuTFh2AWMG30E5PopZHkf GJIV1FYYx68HLCzwoojtxQEGqz1A7QNo99zxS7IXr1utyTtWKY1I9Qk3A6pHyR5G I7b+uX4Q9ruLGUv40auMoajEsdE+G1aSHQ4JCjAUzMUxAgMBAAE= -----END PUBLIC KEY----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs512/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "provides-namespace" : true } } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs512/certificate.cer.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "rsa-4096.cer" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs512/certificate.cer.dataset/rsa-4096.cer ================================================ -----BEGIN CERTIFICATE----- MIIFajCCA1ICCQDSbh992qsOpTANBgkqhkiG9w0BAQsFADB3MQswCQYDVQQGEwJH QjEPMA0GA1UECAwGTG9uZG9uMQ8wDQYDVQQHDAZMb25kb24xGDAWBgNVBAoMD0ds b2JhbCBTZWN1cml0eTEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDEUMBIGA1UEAwwL ZXhhbXBsZS5jb20wHhcNMTgwNzMxMjA1MjAwWhcNMTgwODMwMjA1MjAwWjB3MQsw CQYDVQQGEwJHQjEPMA0GA1UECAwGTG9uZG9uMQ8wDQYDVQQHDAZMb25kb24xGDAW BgNVBAoMD0dsb2JhbCBTZWN1cml0eTEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDEU MBIGA1UEAwwLZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK AoICAQDXpTSPiTQWTk8VIhS24FCHEEWGEpZltqmZx5e04lNyKOu6pXzXcAhEynkp siGR1/v9stP5CRXh8vu6T+AkiFCWKha8AHFIFOlV2dhMV2RKa0dn1Z7n4E6TAeTA h0tFzNJviWB76HwX7+Y8hVUjDohA5QVZ+gIMtsbTJEo3O9BLTGWtlcRNz4NR2qUz 5s6B4mY/6/UIRuoFLTXWqLMfrpp7nlLGKhMQw3eVTYDX27L9GeS0lQocKdBzr2bP 5uf5KjohNdNXQAmwdCHebUbm0ScUFrgCXlLcgDsTayrnHPuj7LbQTUiQKdfQ5QbF GYxrqNvAZKjfGzzFDsHUp07Ei2BA9L6NdaumnpxrXLJiCgg6ap7vxCWr3gjzC6PV vc5lrlXE8UpkcpK93m/J2Srvm/uXZoiQSbFB9IHcByY3eA35uKvQBx1dlwKwxkwt C+DloCCsMVBB8P5VOISe1/Gmx5FK7JmMxoICYaAHQFHOncDJbYC+3ERykROtzSnS +j5ba7l3fXX3CIVu4p6W2+XHR+p8G6JGVU9YMIISOttBdPaQSsW8qOsnKSKd2cRB HQltxIfxzUzy8oDll3u2Vpm8gvNK/wcJ6cK2NWgHeHa7jCJuC3uQWQLpiQSta/Hq F16w63eKvXg/Uim1qDrLl2cpRUqUz/XTxz09ORSP942oaIMICwIDAQABMA0GCSqG SIb3DQEBCwUAA4ICAQBC+KAKPNbzp2OMlipFxiZCYiclmDK0u6JT8mi23a1JH9oP loiO24BDEYbRHityE+ipc71ilG9khnP+h2ZNoGKYUl1AbEvZu6CTMturwhYMunqt pyCV1OWTl5Eh0mngFA5uqEYetXEZyDQ3q9ZcsYoO7xHkN1Ds76fSm9K3euK3iy3H rt2GqKhYbIb6rv8iItk3gYnc/6q3/lIlUIlkRDWijuFE27YJTYBnZJjELFq6hym9 z9vUbZAiX5vyVjMMQhnHrQBQNQ0IYUa6/Hn+7dPWQM8Dyr56wYKl/GRnSlB0iLAp hpdgKfd9Py9NaPhzfaGcxJopod8vn1imivoXMWRzgCMNFkj1zDW++pLIKeHp81qu tAZRIv3/H/qlYTs05EDcsD6cIUV/xnjip2OMZVxPSllAqdbwOXzq7N2q9hE62J0L SCq7XajPEW5q82zen6CvTWq0UeBfoezNtzmIOK/a3laOT8sFCFyAHnNri23UX5QF IACgN5GFDM1aVckkIyna/wIzFsFDSSsEPU0VDehf7vN+1IUgPigxXzwnJ+uhL8SG AFuAKs5FmerDLZkIPc3dv2kGuBu4zUxtjap1up+1q7UL3J5EOLi7N8B1YGSwEWQn hHWeZ0AnhpANv1zk3zNx9JKgexWvMHB70pqbFiA+SSJky0OUl0Ttv7ea0HVRZw== -----END CERTIFICATE----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs512/p12_password.txt.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "rsa-4096-p12-password.txt" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs512/p12_password.txt.dataset/rsa-4096-p12-password.txt ================================================ password ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs512/private.p12.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "rsa-4096-private.p12" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs512/private.pem.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "rsa-4096-private.pem" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs512/private.pem.dataset/rsa-4096-private.pem ================================================ -----BEGIN RSA PRIVATE KEY----- MIIJKAIBAAKCAgEA16U0j4k0Fk5PFSIUtuBQhxBFhhKWZbapmceXtOJTcijruqV8 13AIRMp5KbIhkdf7/bLT+QkV4fL7uk/gJIhQlioWvABxSBTpVdnYTFdkSmtHZ9We 5+BOkwHkwIdLRczSb4lge+h8F+/mPIVVIw6IQOUFWfoCDLbG0yRKNzvQS0xlrZXE Tc+DUdqlM+bOgeJmP+v1CEbqBS011qizH66ae55SxioTEMN3lU2A19uy/RnktJUK HCnQc69mz+bn+So6ITXTV0AJsHQh3m1G5tEnFBa4Al5S3IA7E2sq5xz7o+y20E1I kCnX0OUGxRmMa6jbwGSo3xs8xQ7B1KdOxItgQPS+jXWrpp6ca1yyYgoIOmqe78Ql q94I8wuj1b3OZa5VxPFKZHKSvd5vydkq75v7l2aIkEmxQfSB3AcmN3gN+bir0Acd XZcCsMZMLQvg5aAgrDFQQfD+VTiEntfxpseRSuyZjMaCAmGgB0BRzp3AyW2AvtxE cpETrc0p0vo+W2u5d3119wiFbuKeltvlx0fqfBuiRlVPWDCCEjrbQXT2kErFvKjr JykindnEQR0JbcSH8c1M8vKA5Zd7tlaZvILzSv8HCenCtjVoB3h2u4wibgt7kFkC 6YkErWvx6hdesOt3ir14P1Iptag6y5dnKUVKlM/108c9PTkUj/eNqGiDCAsCAwEA AQKCAgEAlHAr1gHj0NbmqO1kxN1zkQUqVjfFPw6VgD1buC9ysUppuXjgjouXpYKa FJGBehrqYqAOOYZ/gaD4li8VYxBSKIugSpkjYTLDy0zBDwu5BWEDLf5l+8bzT04m YEDBF7L9x7kQqTpG8VM5cL9280K1l7YOEPl/H7FQ+1YnoA2UO8DC3NIS5lzJUDbp MOjXjaCCMc4CRUhLHnUYckJ9ynkt7Zn18GJV7VwfnK5U2kFo28BPJd7RrsE5s+gx JTsUwvbGPMYITC7QfJ30El+2RnwCIlnhIAA9mXrLL3q9dYkFzrjKvmf0Ywfqfuin 2FTVy+XYHn8rnyfolNyrn+3q0m/+OHTBkIyjWxaErqXRXciBvh7GlFuVLdhlHz2f fJEOXeIlOiQSqh3UmffXHRmyltb9n0aFBsA8KmpEnlQ90RozI+hUpeCSPM70oAOA puUc8Ycmi4O3ej57hWbFnM2Mf4cjvYQKSyANnmJKYl8cZd/523BSVpqFKJDXSZKr 1aFoOJSSeXG1mqXUeoXKNzZLeUB/v86utvj+3VfOGWQ14drqvlnrurJMQlRXbAwF 8ct6JojOsNkxeO5+HsCeFirhuXL3MVPsxHMQGPorjtkPQ7B/QI2Z3kW2F8DSRPbX ftGaE/9+G6pI0ApkJ33sdhWrP7aOvO/mDNVlCe6E+tjzP8bqKsECggEBAO3uxaGu s3JTuJS+wMDc/M0y33AP3qn0GjJ+oF5oPBtyHyPmkMEoG8KXYOM7J4+8DA+kZCtz czRKi9zpjcCq9ChsZVDeHNOiu3N4kT8JP7rIEBiazjEzpIP4URH++PBXPR7/Z1jy tlxpUXcajmzF5Z0RkwfXmETsnOtbfVz07CSk8Ua9T3zRI88KPTT44Iv4s6MCDptY dV9kKIdGBKFqOy7budT7n7+qRvdKZ70SusRJupwXlUs8UDEBFLKYxSO/L2TkpPZ7 AryGYugUjOqTg9n0ytyc84H7jHnWypnn0mDsMrEGR4uk2WhNGUT4YHnQ+5mrPwsm 85kMYX/fxYYRkecCggEBAOgFLx522GxAUNfXR/oiKznKvxlUzlonU3+VAvpH40tq OpCHeYeRFiqjlX3cQdePouxFqFfKKd+utPGlurH12ZkwILqPKyWbtUQdI9NboMm+ YJEWbyFR0YPdOnYKNj3O17CYBGkEBj501WuFZeRwuVrGYxjdPa9wamVia+AIxsct JCzrs9/gmY6U3dk2Fez4ADqe0tp7Ul4al5AtMjLbrmFzxKTF32PgTIOsY72BvgQS fOEFr41Cmgm/pLjjNLk5cMBTMfgcpAYidy9g4lF1k6MZS2mrY5/s0BXat2LPgANt dD0WKODH23dWUQWQ8Efrhya/i4t0fhXNBR8eSbLyHD0CggEAdr1MP63xu8JwQTsY 8qbWOomC3GfvFR3O3Rg4bCTUqlW/mKj94IdloyzsmznwOlj8I+pEWzLYcWYqemrL 5TTreCjwPvU5qZxys+OdiLnS5iHldoH7GK7PEVUhEDwQe9DtncSUDN3DiEa+8xN7 tGjmeAZHPAip4uu6O/KCk5tfJcJy7nyXaJDur+pKNV9moDPTYiwqoff5S0uutiOJ OAzN0EqzaMjSJlKR6+Nj9gWc00yAJlnWlZ9Z3brOW3rGF1rYCh/Y+3DUIsVmIq/u yzom+OSjQInLNDkXF87LeRcp9Firy5B4sAXqwZSIYdUaQHC8vymo4qXjt6NoHOrN pmSqTQKCAQBbprCWOBwFpuJIYKHuDNFGYvBZ8UYSFrbFDve+JeeDQtMfhGRdSNKY xUWoEflwTSzuaBW3mAQyd7DCQ9UbtyHdgUVsbGF+2aMg5OHh+6/oAWvj5BjB8K/y htExD5edkrdg6qvTT+OniD9F2cwGEQEm+nbqu3pCcwWURuyV8uGSjCJeHD1RkkcW K3f29YZztQNiJJrl8xD2W0rDiRbrQBwCItjqvb8glNmkqdQ8Z6PHuAXcXYKbKlPu xeUro5SQFkCTuElk2OtyAOtTq9G6m9dV9gf0Fd+krMcF2v/V6GGI+RORjc9X+5qV 6WLX8Aj6X+9jPwbAb6PeuL3tLOmv5jOBAoIBACnn4nK7ybaG4GHNTti28NDYHTh/ fLRH+URPir8aaDOjtTxZqVnpXmKJ3D23dMbmxFUd/M0HhCF0ZFvr7QjSR0qUwO8L 2NGR/e3XNzH4SRycpvD5U62UiQeMUEbNillkm0++aGF/qrYMd52f0DuwrIXG7xu/ rIi8YeNhIctiX6ufqNF+P0UA262Z26jJ4bJBWht9wyciw+UGTmM/DjOkVDJ3eug+ JV6yfl0i/+hLmzy+TBZq5vqZnvwwsJP8upTTRIirl8R6YXEXBd83Paoc98XJFnCh lV7a0jpqiSf4C0L/pmLBDqhbFJ+zVbaZLbsESYe00fAtVgH4BGWu5v0M7+8= -----END RSA PRIVATE KEY----- ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs512/public.pem.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "rsa-4096-public.pem" } ] } ================================================ FILE: Tests/JWTTests/Resources/Certificates.xcassets/rs512/public.pem.dataset/rsa-4096-public.pem ================================================ -----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA16U0j4k0Fk5PFSIUtuBQ hxBFhhKWZbapmceXtOJTcijruqV813AIRMp5KbIhkdf7/bLT+QkV4fL7uk/gJIhQ lioWvABxSBTpVdnYTFdkSmtHZ9We5+BOkwHkwIdLRczSb4lge+h8F+/mPIVVIw6I QOUFWfoCDLbG0yRKNzvQS0xlrZXETc+DUdqlM+bOgeJmP+v1CEbqBS011qizH66a e55SxioTEMN3lU2A19uy/RnktJUKHCnQc69mz+bn+So6ITXTV0AJsHQh3m1G5tEn FBa4Al5S3IA7E2sq5xz7o+y20E1IkCnX0OUGxRmMa6jbwGSo3xs8xQ7B1KdOxItg QPS+jXWrpp6ca1yyYgoIOmqe78Qlq94I8wuj1b3OZa5VxPFKZHKSvd5vydkq75v7 l2aIkEmxQfSB3AcmN3gN+bir0AcdXZcCsMZMLQvg5aAgrDFQQfD+VTiEntfxpseR SuyZjMaCAmGgB0BRzp3AyW2AvtxEcpETrc0p0vo+W2u5d3119wiFbuKeltvlx0fq fBuiRlVPWDCCEjrbQXT2kErFvKjrJykindnEQR0JbcSH8c1M8vKA5Zd7tlaZvILz Sv8HCenCtjVoB3h2u4wibgt7kFkC6YkErWvx6hdesOt3ir14P1Iptag6y5dnKUVK lM/108c9PTkUj/eNqGiDCAsCAwEAAQ== -----END PUBLIC KEY----- ================================================ FILE: Tests/JWTTests/Resources/template/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "provides-namespace" : true } } ================================================ FILE: Tests/JWTTests/Resources/template/certificate.cer.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "secp256k1.cer" } ] } ================================================ FILE: Tests/JWTTests/Resources/template/p12_password.txt.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "secp256k1.txt" } ] } ================================================ FILE: Tests/JWTTests/Resources/template/private.p12.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "secp256k1.p12" } ] } ================================================ FILE: Tests/JWTTests/Resources/template/private.pem.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "secp256k1-private.pem" } ] } ================================================ FILE: Tests/JWTTests/Resources/template/public.pem.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "secp256k1-public.pem" } ] } ================================================ FILE: Tests/JWTTests/Resources/template/request.csr.dataset/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" }, "data" : [ { "idiom" : "universal", "filename" : "secp256k1.csr" } ] } ================================================ FILE: Tests/JWTTests/Tests/Algorithms/JWTAlgorithmAsymmetricTests.m ================================================ // // JWTAlgorithmAsymmetricTests.m // iOS_Tests // // Created by Dmitry on 7/29/18. // @import XCTest; @import JWT; #import "JWTAssetAccessor.h" @interface JWTAlgorithmAsymmetricTestsHelper : NSObject @property (copy, nonatomic, readwrite) NSDictionary *payloadDictionary; @property (copy, nonatomic, readwrite) NSDictionary *headersDictionary; @property (copy, nonatomic, readwrite) NSDictionary *fullDictionary; @property (copy, nonatomic, readwrite) NSDictionary *cryptoKeyBuilderParameters; - (instancetype)configuredByName:(NSString *)name; @property (copy, nonatomic, readwrite) NSString *name; @property (strong, nonatomic, readwrite) id algorithm; - (instancetype)configuredByToken:(NSString *)token; @property (copy, nonatomic, readwrite) NSString *token; @property (copy, nonatomic, readwrite) NSString *invalidToken; - (instancetype)configuredByAssetAccessor:(JWTAssetAccessor *)accessor; @property (strong, nonatomic, readwrite) JWTAssetAccessor *accessor; @end @interface JWTAlgorithmAsymmetricTestsHelper (Wrong) + (instancetype)wrong; - (instancetype)wrong; @end @interface JWTAlgorithmAsymmetricTests__ExtractionKeys : NSObject // Container Keys @property (copy, nonatomic, readonly, class) NSString *Tokens; @property (copy, nonatomic, readonly, class) NSString *Holders; // Extraction Types @property (copy, nonatomic, readonly, class) NSString *PrivateKeyFromP12; @property (copy, nonatomic, readonly, class) NSString *PublicKeyFromCertificate; @property (copy, nonatomic, readonly, class) NSString *PrivateKeyFromPem; @property (copy, nonatomic, readonly, class) NSString *PublicKeyFromPem; @end @implementation JWTAlgorithmAsymmetricTests__ExtractionKeys + (NSString *)Holders { return NSStringFromSelector(_cmd); } + (NSString *)Tokens { return NSStringFromSelector(_cmd); } + (NSString *)PrivateKeyFromPem { return NSStringFromSelector(_cmd); } + (NSString *)PrivateKeyFromP12 { return NSStringFromSelector(_cmd); } + (NSString *)PublicKeyFromPem { return NSStringFromSelector(_cmd); } + (NSString *)PublicKeyFromCertificate { return NSStringFromSelector(_cmd); } @end @implementation JWTAlgorithmAsymmetricTestsHelper - (NSDictionary *)configurations { __weak __auto_type weakSelf = self; return @{ JWTAlgorithmNameRS256 : ^{ __auto_type accessor = [[JWTAssetAccessor alloc] initWithAlgorithName:self.name]; [weakSelf configuredByAssetAccessor:accessor]; }, JWTAlgorithmNameRS384 : ^{ __auto_type accessor = [[JWTAssetAccessor alloc] initWithAlgorithName:self.name]; [weakSelf configuredByAssetAccessor:accessor]; }, JWTAlgorithmNameRS512 : ^{ __auto_type accessor = [[JWTAssetAccessor alloc] initWithAlgorithName:self.name]; [weakSelf configuredByAssetAccessor:accessor]; }, JWTAlgorithmNameES256 : ^{ __auto_type accessor = [[JWTAssetAccessor alloc] initWithAlgorithName:self.name]; [weakSelf configuredByAssetAccessor:accessor]; weakSelf.cryptoKeyBuilderParameters = @{JWTCryptoKey.parametersKeyBuilder : JWTCryptoKeyBuilder.new.keyTypeEC }; }, JWTAlgorithmNameES384 : ^{ __auto_type accessor = [[JWTAssetAccessor alloc] initWithAlgorithName:self.name]; [weakSelf configuredByAssetAccessor:accessor]; weakSelf.cryptoKeyBuilderParameters = @{JWTCryptoKey.parametersKeyBuilder : JWTCryptoKeyBuilder.new.keyTypeEC }; }, JWTAlgorithmNameES512 : ^{ __auto_type accessor = [[JWTAssetAccessor alloc] initWithAlgorithName:self.name]; [weakSelf configuredByAssetAccessor:accessor]; weakSelf.cryptoKeyBuilderParameters = @{JWTCryptoKey.parametersKeyBuilder : JWTCryptoKeyBuilder.new.keyTypeEC }; } }; } - (void)generalConfigure { self.payloadDictionary = @{@"hello" : @"world"}; self.headersDictionary = @{@"alg" : self.name, @"typ" : @"JWT"}; self.fullDictionary = @{ JWTCodingResultComponents.headers : self.headersDictionary, JWTCodingResultComponents.payload : self.payloadDictionary }; // self.payload = @"payload"; // self.secret = @"secret"; // self.wrongSecret = @"notTheSecret"; } - (instancetype)configuredByName:(NSString *)name { __auto_type configured = [self configurations][name]; if (configured) { self.name = name; [self generalConfigure]; configured(); } // choose configuration here? self.algorithm = [JWTAlgorithmFactory algorithmByName:name]; return self; } - (instancetype)configuredByToken:(NSString *)token { if (token != nil) { self.token = token; self.invalidToken = [token stringByReplacingOccurrencesOfString:@"F" withString:@"D"]; } return self; } - (instancetype)configuredByAssetAccessor:(JWTAssetAccessor *)accessor { if (accessor != nil) { self.accessor = accessor; } return self; } @end @interface JWTAlgorithmAsymmetricTests : XCTestCase @property (strong, nonatomic, readwrite) JWTAlgorithmAsymmetricTestsHelper *helper; @end @interface JWTAlgorithmAsymmetricTests (Check) - (void)assertDecodedDictionary:(NSDictionary *)dictionary andHelper:(JWTAlgorithmAsymmetricTestsHelper *)helper; - (void)assertToken:(NSString *)token andHelper:(JWTAlgorithmAsymmetricTestsHelper *)helper; @end @implementation JWTAlgorithmAsymmetricTests - (void)showExternalRepresentation:(SecKeyRef)key name:(NSString *)name type:(NSString *)type { NSError *error = nil; __auto_type presentation = [JWTCryptoSecurity externalRepresentationForKey:key error:&error]; __auto_type data = presentation; __auto_type string = [JWTBase64Coder base64UrlEncodedStringWithData:data]; NSLog(@"name: %@ type: %@ presentation: %@", name, type, string); } - (NSDictionary *)extractedKeysIntoSecretWithHelper:(JWTAlgorithmAsymmetricTestsHelper *)helper { __auto_type tokens = [NSMutableDictionary dictionary]; __auto_type holders = [NSMutableDictionary dictionary]; { __auto_type key = JWTAlgorithmAsymmetricTests__ExtractionKeys.PrivateKeyFromP12; id holder = [JWTAlgorithmRSFamilyDataHolder new].keyExtractorType([JWTCryptoKeyExtractor privateKeyInP12].type).privateKeyCertificatePassphrase(helper.accessor.p12Password).algorithm(helper.algorithm).secretData(helper.accessor.p12Data); __auto_type builder = [JWTEncodingBuilder encodePayload:helper.payloadDictionary].addHolder(holder); __auto_type result = builder.result; if (result.successResult) { tokens[key] = result.successResult.encoded; } } { __auto_type key = JWTAlgorithmAsymmetricTests__ExtractionKeys.PublicKeyFromCertificate; __auto_type theKey = helper.accessor.certificateBase64; __auto_type secret = ((JWTCryptoSecurityComponent *)[[JWTCryptoSecurity componentsFromFileContent:theKey] componentsOfType:JWTCryptoSecurityComponents.Certificate].firstObject).content; id holder = [JWTAlgorithmRSFamilyDataHolder new].keyExtractorType([JWTCryptoKeyExtractor publicKeyWithCertificate].type).algorithm(helper.algorithm).secret(secret); if (holder) { holders[key] = holder; } } { // do we need certificate passphrase here? __auto_type key = JWTAlgorithmAsymmetricTests__ExtractionKeys.PrivateKeyFromPem; __auto_type theKey = helper.accessor.privateKeyBase64; __auto_type secret = ((JWTCryptoSecurityComponent *)[[JWTCryptoSecurity componentsFromFileContent:theKey] componentsOfType:JWTCryptoSecurityComponents.Key].firstObject).content; id holder = [JWTAlgorithmRSFamilyDataHolder new].keyExtractorType([JWTCryptoKeyExtractor privateKeyWithPEMBase64].type).algorithm(helper.algorithm).secret(secret); __auto_type builder = [JWTEncodingBuilder encodePayload:helper.payloadDictionary].addHolder(holder); __auto_type result = builder.result; if (result.successResult) { tokens[key] = result.successResult.encoded; } } { __auto_type key = JWTAlgorithmAsymmetricTests__ExtractionKeys.PublicKeyFromPem; __auto_type theKey = helper.accessor.publicKeyBase64; __auto_type secret = ((JWTCryptoSecurityComponent *)[[JWTCryptoSecurity componentsFromFileContent:theKey] componentsOfType:JWTCryptoSecurityComponents.Key].firstObject).content; id holder = [JWTAlgorithmRSFamilyDataHolder new].keyExtractorType([JWTCryptoKeyExtractor publicKeyWithPEMBase64].type).algorithm(helper.algorithm).secret(secret); if (holder) { holders[key] = holder; } } __auto_type result = @{ JWTAlgorithmAsymmetricTests__ExtractionKeys.Tokens : tokens, JWTAlgorithmAsymmetricTests__ExtractionKeys.Holders : holders }; return result; } - (NSDictionary *)extractedKeysIntoSignAndVerifyKeysWithHelper:(JWTAlgorithmAsymmetricTestsHelper *)helper { __auto_type tokens = [NSMutableDictionary dictionary]; __auto_type holders = [NSMutableDictionary dictionary]; // check name? __auto_type parameters = helper.cryptoKeyBuilderParameters; { __auto_type key = JWTAlgorithmAsymmetricTests__ExtractionKeys.PrivateKeyFromP12; __auto_type privateKey = ({ NSError *error = nil; __auto_type result = [[JWTCryptoKeyPrivate alloc] initWithP12Data:helper.accessor.p12Data withPassphrase:helper.accessor.p12Password parameters:parameters error:&error]; result; }); [self showExternalRepresentation:privateKey.key name:helper.name type:key]; id holder = [JWTAlgorithmRSFamilyDataHolder new].signKey(privateKey).algorithm(helper.algorithm);//.secretData([NSData data]); __auto_type builder = [JWTEncodingBuilder encodePayload:helper.payloadDictionary].addHolder(holder); __auto_type result = builder.result; if (result.successResult) { tokens[key] = result.successResult.encoded; } } { __auto_type key = JWTAlgorithmAsymmetricTests__ExtractionKeys.PublicKeyFromCertificate; __auto_type certificate = helper.accessor.certificateBase64; __auto_type secret = ((JWTCryptoSecurityComponent *)[[JWTCryptoSecurity componentsFromFileContent:certificate] componentsOfType:JWTCryptoSecurityComponents.Certificate].firstObject).content; __auto_type publicKey = ({ NSError *error = nil; __auto_type result = [[JWTCryptoKeyPublic alloc] initWithCertificateBase64String:secret parameters:parameters error:&error]; result; }); [self showExternalRepresentation:publicKey.key name:helper.name type:key]; id holder = [JWTAlgorithmRSFamilyDataHolder new].verifyKey(publicKey).algorithm(helper.algorithm).secretData([NSData data]); if (holder) { holders[key] = holder; } } { __auto_type key = JWTAlgorithmAsymmetricTests__ExtractionKeys.PrivateKeyFromPem; __auto_type theKey = helper.accessor.privateKeyBase64; __auto_type secret = ((JWTCryptoSecurityComponent *)[[JWTCryptoSecurity componentsFromFileContent:theKey] componentsOfType:JWTCryptoSecurityComponents.Key].firstObject).content; __auto_type privateKey = ({ NSError *error = nil; __auto_type result = [[JWTCryptoKeyPrivate alloc] initWithBase64String:secret parameters:parameters error:&error]; result; }); id holder = [JWTAlgorithmRSFamilyDataHolder new].signKey(privateKey).algorithm(helper.algorithm).secretData([NSData data]); __auto_type builder = [JWTEncodingBuilder encodePayload:helper.payloadDictionary].addHolder(holder); __auto_type result = builder.result; if (result.successResult) { tokens[key] = result.successResult.encoded; } } { __auto_type key = JWTAlgorithmAsymmetricTests__ExtractionKeys.PublicKeyFromPem; __auto_type theKey = helper.accessor.publicKeyBase64; __auto_type secret = ((JWTCryptoSecurityComponent *)[[JWTCryptoSecurity componentsFromFileContent:theKey] componentsOfType:JWTCryptoSecurityComponents.Key].firstObject).content; __auto_type publicKey = ({ NSError *error = nil; __auto_type result = [[JWTCryptoKeyPublic alloc] initWithBase64String:secret parameters:parameters error:&error]; result; }); id holder = [JWTAlgorithmRSFamilyDataHolder new].verifyKey(publicKey).algorithm(helper.algorithm).secretData([NSData data]); if (holder) { holders[key] = holder; } } __auto_type result = @{ JWTAlgorithmAsymmetricTests__ExtractionKeys.Tokens : tokens, JWTAlgorithmAsymmetricTests__ExtractionKeys.Holders : holders }; return result; } /*API VERSION THREE*/ - (void)verifyKeysWithTokensAndHolders:(NSDictionary *)dictionary helper:(JWTAlgorithmAsymmetricTestsHelper *)helper { [self verifyKeysWithTokens:[dictionary objectForKey:JWTAlgorithmAsymmetricTests__ExtractionKeys.Tokens] holders:[dictionary objectForKey:JWTAlgorithmAsymmetricTests__ExtractionKeys.Holders] helper:helper]; } - (void)verifyKeysWithTokens:(NSDictionary *)tokens holders:(NSDictionary *)holders helper:(JWTAlgorithmAsymmetricTestsHelper *)helper { for (NSString *holderKey in holders) { __auto_type holder = (id )[holders objectForKey:holderKey]; for (NSString *tokenKey in tokens) { // we must __auto_type token = (NSString *)[tokens objectForKey:tokenKey]; __auto_type builder = [JWTDecodingBuilder decodeMessage:token].addHolder(holder); __auto_type result = builder.result; if (result.successResult) { NSLog(@"Pair: <%@> decodeBy <%@> passed", tokenKey, holderKey); [self assertDecodedDictionary:result.successResult.headerAndPayloadDictionary andHelper:helper]; } else { NSLog(@"Pair: <%@> decodeBy <%@> failed. Error: %@", tokenKey, holderKey, result.errorResult.error); [self assertDecodedDictionary:nil andHelper:helper]; } } } } /*API VERSION THREE*/ - (void)testExtractingKeysFromDifferentContainers { [XCTContext runActivityNamed:@"Extracting keys into secret and secretData" block:^(id _Nonnull activity) { __auto_type algorithmNames = @[ JWTAlgorithmNameRS256, JWTAlgorithmNameRS384, JWTAlgorithmNameRS512, JWTAlgorithmNameES256, JWTAlgorithmNameES384, JWTAlgorithmNameES512 ]; for (NSString *name in algorithmNames) { __auto_type helper = [[JWTAlgorithmAsymmetricTestsHelper new] configuredByName:name]; if (helper.accessor.checked == nil) { XCTFail("Warning. Accessor is invalid"); } if (helper.algorithm == nil) { continue; } __auto_type dictionary = [self extractedKeysIntoSecretWithHelper:helper]; [self verifyKeysWithTokensAndHolders:dictionary helper:helper]; } }]; [XCTContext runActivityNamed:@"Extracting keys into verify and sign keys" block:^(id _Nonnull activity) { __auto_type algorithmsNames = @[ JWTAlgorithmNameES256, JWTAlgorithmNameES384, JWTAlgorithmNameES512 ]; for (NSString *name in algorithmsNames) { __auto_type helper = [[JWTAlgorithmAsymmetricTestsHelper new] configuredByName:name]; if (helper.algorithm == nil) { continue; } __auto_type dictionary = [self extractedKeysIntoSignAndVerifyKeysWithHelper:helper]; [self verifyKeysWithTokensAndHolders:dictionary helper:helper]; } }]; } /*API VERSION TWO*/ // For RS part only. - (void)testEncoding { } - (void)testDecoding { } @end @implementation JWTAlgorithmAsymmetricTests (Check) - (void)assertDecodedDictionary:(NSDictionary *)dictionary andHelper:(JWTAlgorithmAsymmetricTestsHelper *)helper { XCTAssertEqualObjects(dictionary, helper.fullDictionary); } - (void)assertToken:(NSString *)token andHelper:(JWTAlgorithmAsymmetricTestsHelper *)helper { // configure token?! XCTAssertEqualObjects(token, helper.token); // decode it? // or not? // later.. :3 } @end ================================================ FILE: Tests/JWTTests/Tests/Algorithms/JWTAlgorithmHSTests.m ================================================ // // JWTAlgorithmHSTests.m // iOS_Tests // // Created by Dmitry on 7/29/18. // @import XCTest; @import JWT; @interface JWTAlgorithmHSTestsHelper : NSObject @property (copy, nonatomic, readwrite) NSString *payload; @property (copy, nonatomic, readwrite) NSString *signedPayload; @property (copy, nonatomic, readwrite) NSString *signedPayloadBase64UrlEncoded; @property (copy, nonatomic, readwrite) NSString *secret; @property (copy, nonatomic, readwrite) NSString *wrongSecret; @property (copy, nonatomic, readwrite) NSString *signature; @property (copy, nonatomic, readwrite) NSString *name; - (instancetype)configuredByName:(NSString *)name; @property (strong, nonatomic, readwrite) id algorithm; @property (strong, nonatomic, readwrite) JWTAlgorithmHolder *theAlgorithm; @property (strong, nonatomic, readwrite) JWTBase64Coder *base64Coder; @end @implementation JWTAlgorithmHSTestsHelper - (NSDictionary *)configurations { __weak __auto_type weakSelf = self; return @{ JWTAlgorithmNameHS256 : ^{ weakSelf.signedPayload = @"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9"; weakSelf.signedPayloadBase64UrlEncoded = @"uC_LeRrOxXhZuYm0MKgmSIzi5Hn9-SMmvQoug3WkK6Q"; weakSelf.signature = @"TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"; }, JWTAlgorithmNameHS384 : ^{ weakSelf.signedPayload = @"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9"; weakSelf.signedPayloadBase64UrlEncoded = @"s62aZf5ZLMSvjtBQpY4kiJbYxSu8wLAUop2D9nod5Eqgd-nyUCEj-iaDuVuI4gaJ"; weakSelf.signature = @"hnzqaUFa2kfSFnynQ_WBJ7-wpLCgsyEdilCkRKliadjVuG-hGnc1qhvIjlvxSie5"; }, JWTAlgorithmNameHS512 : ^{ weakSelf.signedPayload = @"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9"; weakSelf.signedPayloadBase64UrlEncoded = @"KR3aqiPK-jqq4cl1U5H0vvNbvby5JzmlYYpciW9lINKw0o0tKYfayXR54xIUpR2Wz86voo5GpPlhtjxGNSoYng"; weakSelf.signature = @"SerC5MWQIs3fRH6ZD7gKKbq51TsyydXTvl23WpD9sA085SzQ7pK6M0TnYjFITNUkwuniGG5Is2OKJCEIHPn1Kg"; } }; } - (void)generalConfigure { self.payload = @"payload"; self.secret = @"secret"; self.wrongSecret = @"notTheSecret"; self.base64Coder = [JWTBase64Coder new]; } - (instancetype)configuredByName:(NSString *)name { __auto_type configured = [self configurations][name]; if (configured) { [self generalConfigure]; configured(); self.name = name; } // choose configuration here? self.algorithm = [JWTAlgorithmFactory algorithmByName:name]; self.theAlgorithm = [[JWTAlgorithmHolder alloc] initWithAlgorithm:self.algorithm]; return self; } @end @interface JWTAlgorithmHSTests : XCTestCase @end @implementation JWTAlgorithmHSTests - (void)setUp { [super setUp]; // Put setup code here. This method is called before the invocation of each test method in the class. } - (void)tearDown { // Put teardown code here. This method is called after the invocation of each test method in the class. [super tearDown]; } - (void)testAlgorithms { { [self theTestForAlgorithmName:@"HS256"]; } { [self theTestForAlgorithmName:@"HS384"]; } { [self theTestForAlgorithmName:@"HS512"]; } } - (void)theTestForAlgorithmName:(NSString *)name { __block __auto_type helper = [[JWTAlgorithmHSTestsHelper new] configuredByName:name]; XCTAssertNotNil(helper); XCTAssertNotNil(helper.algorithm); [XCTContext runActivityNamed:@"name is from HS family" block:^(id _Nonnull activity) { XCTAssertEqualObjects(helper.algorithm.name, helper.name); }]; [XCTContext runActivityNamed:@"HMAC encodes the payload using SHA256" block:^(id _Nonnull activity) { __auto_type encodedPayload = [helper.theAlgorithm encodePayload:helper.payload withSecret:helper.secret]; XCTAssertEqualObjects([helper.base64Coder stringWithData:encodedPayload], helper.signedPayloadBase64UrlEncoded); }]; [XCTContext runActivityNamed:@"HMAC encodes the payload data using SHA256" block:^(id _Nonnull activity) { __auto_type payloadData = [helper.base64Coder dataWithString:helper.payload]; __auto_type secretData = [helper.base64Coder dataWithString:helper.secret]; __auto_type encodedPayload = [helper.theAlgorithm encodePayloadData:payloadData withSecret:secretData]; XCTAssertEqualObjects([helper.base64Coder stringWithData:encodedPayload], helper.signedPayloadBase64UrlEncoded); }]; [XCTContext runActivityNamed:@"HMAC encodes the payload canonically" block:^(id _Nonnull activity) { XCTAssertTrue([helper.theAlgorithm verifySignedInput:helper.signedPayload withSignature:helper.signature verificationKey:helper.secret]); }]; [XCTContext runActivityNamed:@"should verify JWT with valid signature and secret" block:^(id _Nonnull activity) { XCTAssertTrue([helper.theAlgorithm verifySignedInput:helper.signedPayload withSignature:helper.signature verificationKey:helper.secret]); }]; [XCTContext runActivityNamed:@"should fail to verify JWT with invalid secret" block:^(id _Nonnull activity) { XCTAssertFalse([helper.theAlgorithm verifySignedInput:helper.signedPayload withSignature:helper.signature verificationKey:helper.wrongSecret]); }]; [XCTContext runActivityNamed:@"should fail to verify JWT with invalid signature" block:^(id _Nonnull activity) { XCTAssertFalse([helper.theAlgorithm verifySignedInput:helper.signedPayload withSignature:nil verificationKey:helper.secret]); }]; [XCTContext runActivityNamed:@"should verify JWT with valid signature and secret Data" block:^(id _Nonnull activity) { __auto_type secretData = [helper.base64Coder dataWithString:helper.secret]; XCTAssertTrue([helper.theAlgorithm verifySignedInput:helper.signedPayload withSignature:helper.signature verificationKeyData:secretData]); }]; [XCTContext runActivityNamed:@"should fail to verify JWT with invalid secret" block:^(id _Nonnull activity) { __auto_type secretData = [helper.base64Coder dataWithString:helper.wrongSecret]; XCTAssertFalse([helper.theAlgorithm verifySignedInput:helper.signedPayload withSignature:helper.signature verificationKeyData:secretData]); }]; [XCTContext runActivityNamed:@"should fail to verify JWT with invalid signature" block:^(id _Nonnull activity) { __auto_type secretData = [helper.base64Coder dataWithString:helper.secret]; XCTAssertFalse([helper.theAlgorithm verifySignedInput:helper.signedPayload withSignature:nil verificationKeyData:secretData]); }]; } @end ================================================ FILE: Tests/JWTTests/Tests/Algorithms/JWTAlgorithmNoneTests.m ================================================ // // JWTAlgorithmNoneTests.m // iOS_Tests // // Created by Dmitry on 7/29/18. // @import XCTest; @import JWT; @interface JWTAlgorithmTestsHelper__None : NSObject @property (copy, nonatomic, readwrite) NSString *payload; @property (copy, nonatomic, readwrite) NSString *signedPayload; @property (copy, nonatomic, readwrite) NSString *signedPayloadBase64; @property (copy, nonatomic, readwrite) NSString *secret; @property (copy, nonatomic, readwrite) NSString *wrongSecret; @property (copy, nonatomic, readwrite) NSString *signature; @property (copy, nonatomic, readwrite) NSString *name; - (instancetype)configuredByName:(NSString *)name; @property (strong, nonatomic, readwrite) id algorithm; @property (strong, nonatomic, readwrite) JWTAlgorithmHolder *theAlgorithm; @property (strong, nonatomic, readwrite) JWTBase64Coder *base64Coder; @end @implementation JWTAlgorithmTestsHelper__None - (NSDictionary *)configurations { __weak __auto_type weakSelf = self; return @{ JWTAlgorithmNameNone : ^{ weakSelf.signedPayload = @"eyJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ"; weakSelf.signedPayloadBase64 = @""; weakSelf.signature = @"signed"; } }; } - (void)generalConfigure { self.payload = @"payload"; self.secret = @"secret"; self.wrongSecret = @"notTheSecret"; self.base64Coder = [JWTBase64Coder new]; } - (instancetype)configuredByName:(NSString *)name { __auto_type configured = [self configurations][name]; if (configured) { [self generalConfigure]; configured(); self.name = name; } // choose configuration here? self.algorithm = [JWTAlgorithmFactory algorithmByName:name]; self.theAlgorithm = [[JWTAlgorithmHolder alloc] initWithAlgorithm:self.algorithm]; return self; } @end @interface JWTAlgorithmNoneTests : XCTestCase @end @implementation JWTAlgorithmNoneTests - (void)setUp { [super setUp]; // Put setup code here. This method is called before the invocation of each test method in the class. } - (void)tearDown { // Put teardown code here. This method is called after the invocation of each test method in the class. [super tearDown]; } - (void)testExample { // This is an example of a functional test case. // Use XCTAssert and related functions to verify your tests produce the correct results. } - (void)testPerformanceExample { // This is an example of a performance test case. [self measureBlock:^{ // Put the code you want to measure the time of here. }]; } - (void)testAlgorithms { { [self theTestForAlgorithmName:@"none"]; } } - (void)theTestForAlgorithmName:(NSString *)name { __block __auto_type helper = [[JWTAlgorithmTestsHelper__None new] configuredByName:name]; XCTAssertNotNil(helper); XCTAssertNotNil(helper.algorithm); [XCTContext runActivityNamed:@"name is none" block:^(id _Nonnull activity){ XCTAssertEqualObjects(helper.algorithm.name, name); }]; [XCTContext runActivityNamed:@"should not encode payload and return emptry signature instead" block:^(id _Nonnull activity){ __auto_type encodedPayload = [helper.theAlgorithm encodePayload:helper.payload withSecret:helper.secret]; XCTAssertEqualObjects([helper.base64Coder stringWithData:encodedPayload], helper.signedPayloadBase64); }]; [XCTContext runActivityNamed:@"should not encode payload data and return emptry signature instead" block:^(id _Nonnull activity){ __auto_type payloadData = [helper.base64Coder dataWithString:helper.payload]; __auto_type secretData = [helper.base64Coder dataWithString:helper.secret]; __auto_type encodedPayload = [helper.theAlgorithm encodePayloadData:payloadData withSecret:secretData]; XCTAssertEqualObjects([encodedPayload base64EncodedStringWithOptions:0], helper.signedPayloadBase64); }]; [XCTContext runActivityNamed:@"should not verify JWT with a secret provided" block:^(id _Nonnull activity){ XCTAssertFalse([helper.theAlgorithm verifySignedInput:helper.signedPayload withSignature:nil verificationKey:helper.secret]); }]; [XCTContext runActivityNamed:@"should not verify JWT with a signature provided" block:^(id _Nonnull activity){ XCTAssertFalse([helper.theAlgorithm verifySignedInput:helper.signedPayload withSignature:helper.signature verificationKey:nil]); }]; [XCTContext runActivityNamed:@"should verify JWT with no signature and no secret provided" block:^(id _Nonnull activity){ XCTAssertTrue([helper.theAlgorithm verifySignedInput:helper.signedPayload withSignature:nil verificationKey:nil]); }]; [XCTContext runActivityNamed:@"should not verify JWT with a secret data provided" block:^(id _Nonnull activity){ __auto_type secretData = [helper.base64Coder dataWithString:helper.secret]; XCTAssertFalse([helper.theAlgorithm verifySignedInput:helper.signedPayload withSignature:nil verificationKeyData:secretData]); }]; [XCTContext runActivityNamed:@"should not verify JWT with a signature data provided" block:^(id _Nonnull activity){ __auto_type secretData = [helper.base64Coder dataWithString:nil]; XCTAssertFalse([helper.theAlgorithm verifySignedInput:helper.signedPayload withSignature:helper.signature verificationKeyData:secretData]); }]; [XCTContext runActivityNamed:@"should verify JWT with no signature and no secret data provided" block:^(id _Nonnull activity){ __auto_type secretData = [helper.base64Coder dataWithString:nil]; XCTAssertTrue([helper.theAlgorithm verifySignedInput:helper.signedPayload withSignature:nil verificationKeyData:secretData]); }]; } @end ================================================ FILE: Tests/JWTTests/Tests/ClaimSet/JWTClaimsCustomClaimsBaseTests.m ================================================ // // JWTClaimsCustomClaimsBaseTests.m // iOS_Tests // // Created by Dmitry Lobanov on 30.05.2021. // @import XCTest; @import JWT; /** Consider the following claims set. "intersection": "1, 2" // Actually, it is array and the rule "intersection" arrays should have non-empty intersection. Let's implement this claim. */ /// Define a name of claim @interface JWTClaimsNames (Custom) @property (copy, nonatomic, readonly, class) NSString *intersectionOfArrays; @end @implementation JWTClaimsNames (Custom) + (NSString *)intersectionOfArrays { return @"intersection"; } @end /// Define a claim @interface JWTClaimCustomIntersectionOfArrays : JWTClaimBase @end @implementation JWTClaimCustomIntersectionOfArrays + (NSString *)name { return JWTClaimsNames.intersectionOfArrays; } @end /// Define a serialization @interface JWTClaimSerializerForArray : JWTClaimSerializerBase @end @implementation JWTClaimSerializerForArray - (NSObject *)deserializedClaimValue:(NSObject *)value forName:(NSString *)name { if ([value isKindOfClass:NSString.class]) { __auto_type array = [(NSString *)value componentsSeparatedByString:@","]; __auto_type result = [NSMutableArray array]; for (NSString *item in array) { [result addObject:@(item.integerValue)]; } __auto_type descriptor = [[NSSortDescriptor alloc] initWithKey:@"integerValue" ascending:YES]; return [result sortedArrayUsingDescriptors:@[descriptor]]; } return value; } - (NSObject *)serializedClaimValue:(id)claim { __auto_type value = claim.value; if ([value isKindOfClass:NSArray.class]) { __auto_type descriptor = [[NSSortDescriptor alloc] initWithKey:@"integerValue" ascending:YES]; __auto_type sortedArray = [(NSArray *)claim.value sortedArrayUsingDescriptors:@[descriptor]]; return [sortedArray componentsJoinedByString:@","]; } return value; } @end /// Define a rule @interface JWTClaimVerifierForIntersection : JWTClaimVerifierBase @end @implementation JWTClaimVerifierForIntersection - (BOOL)verifyValue:(NSObject *)value withTrustedValue:(NSObject *)trustedValue { if ([value isKindOfClass:NSArray.class] && [trustedValue isKindOfClass:NSArray.class]) { __auto_type lhs = (NSArray *)value; __auto_type rhs = (NSArray *)trustedValue; if (rhs.count != 2) { return NO; } if (lhs.count > 2 || lhs.count == 0) { return NO; } __auto_type lowerBorder = ((NSNumber *)rhs.firstObject).integerValue; __auto_type upperBorder = ((NSNumber *)rhs.lastObject).integerValue; if (lhs.count == 1) { __auto_type checkValue = ((NSNumber *)lhs.firstObject).integerValue; return lowerBorder <= checkValue && upperBorder >= checkValue; } if (lhs.count == 2) { __auto_type untrustedLowerBorder = ((NSNumber *)lhs.firstObject).integerValue; __auto_type untrustedUpperBorder = ((NSNumber *)lhs.lastObject).integerValue; return (untrustedLowerBorder >= lowerBorder && untrustedLowerBorder <= upperBorder) || (untrustedUpperBorder >= lowerBorder && untrustedUpperBorder <= upperBorder); } } return NO; } @end /// Define a dsl @interface JWTClaimsSetDSLBase (CustomDSL) @property (copy, nonatomic, readwrite) NSArray *intersection; @end @implementation JWTClaimsSetDSLBase (CustomDSL) - (NSArray *)intersection { return (NSArray *)[self dslValueForName:JWTClaimsNames.intersectionOfArrays]; } - (void)setIntersection:(NSArray *)intersection { [self dslSetValue:intersection forName:JWTClaimsNames.intersectionOfArrays]; } @end @interface JWTClaimVariations (CustomDSL) + (id)intersectionOfArrays; @end @implementation JWTClaimVariations (CustomDSL) + (id)intersectionOfArrays { return [JWTClaimCustomIntersectionOfArrays new]; } @end @interface JWTClaimSerializerVariations (CustomDSL) + (id)array; @end @implementation JWTClaimSerializerVariations (CustomDSL) + (id)array { return [JWTClaimSerializerForArray new]; } @end @interface JWTClaimVerifierVariations (CustomDSL) + (id)intersection; @end @implementation JWTClaimVerifierVariations (CustomDSL) + (id)intersection { return [JWTClaimVerifierForIntersection new]; } @end @interface JWTClaimsCustomClaimsBaseTests : XCTestCase @property (strong, nonatomic, readwrite) id claimsSetCoordinator; @end @implementation JWTClaimsCustomClaimsBaseTests - (void)setUp { // Put setup code here. This method is called before the invocation of each test method in the class. __auto_type claim = JWTClaimVariations.intersectionOfArrays; __auto_type claimSerializer = JWTClaimSerializerVariations.array; __auto_type claimVerifier = JWTClaimVerifierVariations.intersection; self.claimsSetCoordinator = [JWTClaimsSetCoordinatorBase new]; [self.claimsSetCoordinator registerClaim:claim serializer:claimSerializer verifier:claimVerifier forClaimName:JWTClaimsNames.intersectionOfArrays]; } - (void)tearDown { // Put teardown code here. This method is called after the invocation of each test method in the class. } - (void)testSerialize { __auto_type deserialized = ({ self.claimsSetCoordinator.configureClaimsSet(^JWTClaimsSetDSLBase * _Nonnull(JWTClaimsSetDSLBase * _Nonnull claimsSetDSL) { claimsSetDSL.intersection = @[@(2), @(5)]; return claimsSetDSL; }); self.claimsSetCoordinator.claimsSetStorage; }); __auto_type serialized = ({ __auto_type dictionary = [self.claimsSetCoordinator.claimsSetSerializer dictionaryFromClaimsSet:deserialized]; dictionary; }); __auto_type result = @{ JWTClaimsNames.intersectionOfArrays : @"2,5" }; XCTAssertEqual(serialized.count, 1); XCTAssertEqualObjects(serialized, result); } - (void)testDeserialize { __auto_type given = @{ JWTClaimsNames.intersectionOfArrays : @"2,5" }; __auto_type deserialized = ({ self.claimsSetCoordinator.claimsSetStorage = [JWTClaimsSetBase new]; [self.claimsSetCoordinator.claimsSetSerializer claimsSetFromDictionary:given]; }); __auto_type result = ({ __auto_type dsl = self.claimsSetCoordinator.dslDesrciption; dsl.intersection = @[@(2), @(5)]; dsl; }); XCTAssertEqualObjects(result.intersection, [deserialized claimByName:JWTClaimsNames.intersectionOfArrays].value); } - (void)testPerformanceExample { // This is an example of a performance test case. [self measureBlock:^{ // Put the code you want to measure the time of here. }]; } @end @interface JWTClaimsCustomClaimsDifferentNamesTests : XCTestCase @property (strong, nonatomic, readwrite) id claimsSetCoordinator; @property (copy, nonatomic, readwrite) NSString *duplicateClaimName; @end @implementation JWTClaimsCustomClaimsDifferentNamesTests - (void)setUp { self.duplicateClaimName = @"duplicateClaimName"; __auto_type claim = JWTClaimVariations.intersectionOfArrays; __auto_type claimSerializer = JWTClaimSerializerVariations.array; __auto_type claimVerifier = JWTClaimVerifierVariations.intersection; self.claimsSetCoordinator = [JWTClaimsSetCoordinatorBase new]; // [self.claimsSetCoordinator registerClaim:claim serializer:claimSerializer verifier:claimVerifier forClaimName:JWTClaimsNames.intersectionOfArrays]; [self.claimsSetCoordinator registerClaim:claim serializer:claimSerializer verifier:claimVerifier forClaimName:self.duplicateClaimName]; } - (void)testSerialize { __auto_type deserialized = ({ self.claimsSetCoordinator.configureClaimsSet(^JWTClaimsSetDSLBase * _Nonnull(JWTClaimsSetDSLBase * _Nonnull claimsSetDSL) { [claimsSetDSL dslSetValue:@[@(2), @(5)] forName:self.duplicateClaimName]; return claimsSetDSL; }); self.claimsSetCoordinator.claimsSetStorage; }); __auto_type serialized = ({ __auto_type dictionary = [self.claimsSetCoordinator.claimsSetSerializer dictionaryFromClaimsSet:deserialized]; dictionary; }); __auto_type result = @{ self.duplicateClaimName : @"2,5" }; XCTAssertEqual(serialized.count, 1); XCTAssertEqualObjects(serialized, result); } - (void)testDeserialize { __auto_type given = @{ self.duplicateClaimName : @"2,5" }; __auto_type deserialized = ({ self.claimsSetCoordinator.claimsSetStorage = [JWTClaimsSetBase new]; [self.claimsSetCoordinator.claimsSetSerializer claimsSetFromDictionary:given]; }); __auto_type result = ({ __auto_type dsl = self.claimsSetCoordinator.dslDesrciption; // dsl.intersection = @[@(2), @(5)]; [dsl dslSetValue:@[@(2), @(5)] forName:self.duplicateClaimName]; dsl; }); XCTAssertNotNil([result dslValueForName:self.duplicateClaimName]); XCTAssertEqualObjects([result dslValueForName:self.duplicateClaimName], [deserialized claimByName:self.duplicateClaimName].value); } @end ================================================ FILE: Tests/JWTTests/Tests/ClaimSet/JWTClaimsSerializerBaseTests.m ================================================ // // JWTClaimsSerializerBaseTests.m // Tests // // Created by Dmitry Lobanov on 24.05.2021. // @import XCTest; @import JWT; @interface JWTClaimsSerializerBaseTests : XCTestCase @property (strong, nonatomic, readwrite) id deserialized; @property (copy, nonatomic, readwrite) NSDictionary *serialized; @property (assign, nonatomic, readwrite) NSTimeInterval expirationDateTimestamp; @property (assign, nonatomic, readwrite) NSTimeInterval notBeforeDateTimestamp; @property (assign, nonatomic, readwrite) NSTimeInterval issuedAtTimestamp; @end @implementation JWTClaimsSerializerBaseTests @end @interface JWTClaimsSerializerBaseTests__Serialization : JWTClaimsSerializerBaseTests @end @implementation JWTClaimsSerializerBaseTests__Serialization - (void)setUp { self.expirationDateTimestamp = 1234567; self.notBeforeDateTimestamp = 1234321; self.issuedAtTimestamp = 1234333; __auto_type coordinator = [JWTClaimsSetCoordinatorBase new]; self.deserialized = ({ coordinator.configureClaimsSet(^JWTClaimsSetDSLBase * _Nonnull(JWTClaimsSetDSLBase * _Nonnull claimsSetDSL) { claimsSetDSL.issuer = @"Facebook"; claimsSetDSL.subject = @"Token"; claimsSetDSL.audience = @"https://jwt.io"; claimsSetDSL.expirationDate = [NSDate dateWithTimeIntervalSince1970:self.expirationDateTimestamp]; claimsSetDSL.notBeforeDate = [NSDate dateWithTimeIntervalSince1970:self.notBeforeDateTimestamp]; claimsSetDSL.issuedAt = [NSDate dateWithTimeIntervalSince1970:self.issuedAtTimestamp]; claimsSetDSL.identifier = @"thisisunique"; claimsSetDSL.type = @"test"; claimsSetDSL.scope = @"https://www.googleapis.com/auth/devstorage.read_write"; return claimsSetDSL; }); coordinator.claimsSetStorage; }); __auto_type serializer = coordinator.claimsSetSerializer; self.serialized = ({ __auto_type serialized = [serializer dictionaryFromClaimsSet:self.deserialized]; serialized; }); } - (void)testHaveEnoughKeys:(NSNumber *)number inDictionary:(NSDictionary *)dictionary { [XCTContext runActivityNamed:@"number of serialized values" block:^(id _Nonnull activity) { XCTAssertEqualObjects(@(dictionary.allValues.count), @(9)); }]; } - (void)testDictionary:(NSDictionary *)dictionary hasValue:(id)value forKey:(NSString *)key name:(NSString *)name { __auto_type activityName = [NSString stringWithFormat:@"serializes the %@ property", name]; [XCTContext runActivityNamed:activityName block:^(id _Nonnull activity) { XCTAssertEqualObjects([dictionary objectForKey:key], value); }]; } - (void)test { [self testHaveEnoughKeys:@(9) inDictionary:self.serialized]; [self testDictionary:self.serialized hasValue:[self.deserialized claimByName:JWTClaimsNames.issuer].value forKey:JWTClaimsNames.issuer name:@"issuer"]; [self testDictionary:self.serialized hasValue:[self.deserialized claimByName:JWTClaimsNames.subject].value forKey:JWTClaimsNames.subject name:@"subject"]; [self testDictionary:self.serialized hasValue:[self.deserialized claimByName:JWTClaimsNames.audience].value forKey:JWTClaimsNames.audience name:@"audience"]; [self testDictionary:self.serialized hasValue:@(self.expirationDateTimestamp) forKey:JWTClaimsNames.expirationTime name:@"expirationDate"]; [self testDictionary:self.serialized hasValue:@(self.notBeforeDateTimestamp) forKey:JWTClaimsNames.notBefore name:@"notBeforeDate"]; [self testDictionary:self.serialized hasValue:@(self.issuedAtTimestamp) forKey:JWTClaimsNames.issuedAt name:@"issuedAtDate"]; [self testDictionary:self.serialized hasValue:[self.deserialized claimByName:JWTClaimsNames.jwtID].value forKey:JWTClaimsNames.jwtID name:@"identifier(jti)"]; [self testDictionary:self.serialized hasValue:[self.deserialized claimByName:JWTClaimsNames.type].value forKey:JWTClaimsNames.type name:@"type"]; [self testDictionary:self.serialized hasValue:[self.deserialized claimByName:JWTClaimsNames.scope].value forKey:JWTClaimsNames.scope name:@"scope"]; } @end @interface JWTClaimsSerializerBaseTests__Deserialization : JWTClaimsSerializerBaseTests @end @implementation JWTClaimsSerializerBaseTests__Deserialization - (void)setUp { self.serialized = @{ @"iss": @"Facebook", @"sub": @"Token", @"aud": @"https://jwt.io", @"exp": @(64092211200), @"nbf": @(-62135769600), @"iat": @(1370005175), @"jti": @"thisisunique", @"typ": @"test", @"scope": @"https://www.googleapis.com/auth/devstorage.read_write" }; __auto_type claimsProvider = [[JWTClaimsProviderBase alloc] init]; __auto_type claimsSetStorage = [[JWTClaimsSetBase alloc] init]; __auto_type serializer = [[JWTClaimsSetSerializerBase alloc] init]; serializer.claimsProvider = claimsProvider; serializer.claimsSetStorage = claimsSetStorage; __auto_type result = [serializer claimsSetFromDictionary:self.serialized]; self.deserialized = [[[JWTClaimsSetBase alloc] init] copyWithClaims:result.claims]; } - (void)testDeserializeProperty:(id)property comparedToValue:(id)value name:(NSString *)name { __auto_type propertyKey = name; __auto_type activityName = [NSString stringWithFormat:@"deserializes the %@ property", propertyKey]; [XCTContext runActivityNamed:activityName block:^(id _Nonnull activity) { XCTAssertEqualObjects(property, value); }]; } - (void)test { [self testDeserializeProperty:[self.deserialized claimByName:JWTClaimsNames.issuer].value comparedToValue:self.serialized[JWTClaimsNames.issuer] name:JWTClaimsNames.issuer]; [self testDeserializeProperty:[self.deserialized claimByName:JWTClaimsNames.subject].value comparedToValue:self.serialized[JWTClaimsNames.subject] name:JWTClaimsNames.subject]; [self testDeserializeProperty:[self.deserialized claimByName:JWTClaimsNames.audience].value comparedToValue:self.serialized[JWTClaimsNames.audience] name:JWTClaimsNames.audience]; [self testDeserializeProperty:[self.deserialized claimByName:JWTClaimsNames.expirationTime].value comparedToValue:[NSDate dateWithTimeIntervalSince1970:[self.serialized[JWTClaimsNames.expirationTime] doubleValue]] name:JWTClaimsNames.expirationTime]; [self testDeserializeProperty:[self.deserialized claimByName:JWTClaimsNames.notBefore].value comparedToValue:[NSDate dateWithTimeIntervalSince1970:[self.serialized[JWTClaimsNames.notBefore] doubleValue]] name:JWTClaimsNames.notBefore]; [self testDeserializeProperty:[self.deserialized claimByName:JWTClaimsNames.issuedAt].value comparedToValue:[NSDate dateWithTimeIntervalSince1970:[self.serialized[JWTClaimsNames.issuedAt] doubleValue]] name:JWTClaimsNames.issuedAt]; [self testDeserializeProperty:[self.deserialized claimByName:JWTClaimsNames.jwtID].value comparedToValue:self.serialized[JWTClaimsNames.jwtID] name:JWTClaimsNames.jwtID]; [self testDeserializeProperty:[self.deserialized claimByName:JWTClaimsNames.type].value comparedToValue:self.serialized[JWTClaimsNames.type] name:JWTClaimsNames.type]; [self testDeserializeProperty:[self.deserialized claimByName:JWTClaimsNames.scope].value comparedToValue:self.serialized[JWTClaimsNames.scope] name:JWTClaimsNames.scope]; } @end ================================================ FILE: Tests/JWTTests/Tests/ClaimSet/JWTClaimsSerializerTests.m ================================================ // // JWTClaimsSerializerTests.m // iOS_Tests // // Created by Dmitry on 7/29/18. // @import XCTest; @import JWT; @interface JWTClaimsSerializerTests : XCTestCase @property (strong, nonatomic, readwrite) JWTClaimsSet *deserialized; @property (copy, nonatomic, readwrite) NSDictionary *serialized; @property (assign, nonatomic, readwrite) NSTimeInterval expirationDateTimestamp; @property (assign, nonatomic, readwrite) NSTimeInterval notBeforeDateTimestamp; @property (assign, nonatomic, readwrite) NSTimeInterval issuedAtTimestamp; @end @implementation JWTClaimsSerializerTests @end @interface JWTClaimsSerializerTests__Serialization : JWTClaimsSerializerTests @end @implementation JWTClaimsSerializerTests__Serialization - (void)setUp { self.expirationDateTimestamp = 1234567; self.notBeforeDateTimestamp = 1234321; self.issuedAtTimestamp = 1234333; self.deserialized = ({ __auto_type claimsSet = [[JWTClaimsSet alloc] init]; claimsSet.issuer = @"Facebook"; claimsSet.subject = @"Token"; claimsSet.audience = @"https://jwt.io"; claimsSet.expirationDate = [NSDate dateWithTimeIntervalSince1970:self.expirationDateTimestamp]; claimsSet.notBeforeDate = [NSDate dateWithTimeIntervalSince1970:self.notBeforeDateTimestamp]; claimsSet.issuedAt = [NSDate dateWithTimeIntervalSince1970:self.issuedAtTimestamp]; claimsSet.identifier = @"thisisunique"; claimsSet.type = @"test"; claimsSet.scope = @"https://www.googleapis.com/auth/devstorage.read_write"; claimsSet; }); self.serialized = ({ __auto_type serialized = [JWTClaimsSetSerializer dictionaryWithClaimsSet:self.deserialized]; serialized; }); } - (void)testHaveEnoughKeys:(NSNumber *)number inDictionary:(NSDictionary *)dictionary { [XCTContext runActivityNamed:@"number of serialized values" block:^(id _Nonnull activity) { XCTAssertEqualObjects(@(dictionary.allValues.count), @(9)); }]; } - (void)testDictionary:(NSDictionary *)dictionary hasValue:(id)value forKey:(NSString *)key name:(NSString *)name { __auto_type activityName = [NSString stringWithFormat:@"serializes the %@ property", name]; [XCTContext runActivityNamed:activityName block:^(id _Nonnull activity) { XCTAssertEqualObjects([dictionary objectForKey:key], value); }]; } - (void)test { [self testHaveEnoughKeys:@(9) inDictionary:self.serialized]; [self testDictionary:self.serialized hasValue:self.deserialized.issuer forKey:@"iss" name:@"issuer"]; [self testDictionary:self.serialized hasValue:self.deserialized.subject forKey:@"sub" name:@"subject"]; [self testDictionary:self.serialized hasValue:self.deserialized.audience forKey:@"aud" name:@"audience"]; [self testDictionary:self.serialized hasValue:@(self.expirationDateTimestamp) forKey:@"exp" name:@"expirationDate"]; [self testDictionary:self.serialized hasValue:@(self.notBeforeDateTimestamp) forKey:@"nbf" name:@"notBeforeDate"]; [self testDictionary:self.serialized hasValue:@(self.issuedAtTimestamp) forKey:@"iat" name:@"issuedAtDate"]; [self testDictionary:self.serialized hasValue:self.deserialized.identifier forKey:@"jti" name:@"identifier(jti)"]; [self testDictionary:self.serialized hasValue:self.deserialized.type forKey:@"typ" name:@"type"]; [self testDictionary:self.serialized hasValue:self.deserialized.scope forKey:@"scope" name:@"scope"]; } @end @interface JWTClaimsSerializerTests__Deserialization : JWTClaimsSerializerTests @end @implementation JWTClaimsSerializerTests__Deserialization - (void)setUp { self.serialized = @{ @"iss": @"Facebook", @"sub": @"Token", @"aud": @"https://jwt.io", @"exp": @(64092211200), @"nbf": @(-62135769600), @"iat": @(1370005175), @"jti": @"thisisunique", @"typ": @"test", @"scope": @"https://www.googleapis.com/auth/devstorage.read_write" }; self.deserialized = [JWTClaimsSetSerializer claimsSetWithDictionary:self.serialized]; } - (void)testDeserializeProperty:(id)property comparedToValue:(id)value name:(NSString *)name { __auto_type propertyKey = name; __auto_type activityName = [NSString stringWithFormat:@"deserializes the %@ property", propertyKey]; [XCTContext runActivityNamed:activityName block:^(id _Nonnull activity) { XCTAssertEqualObjects(property, value); }]; } - (void)test { [self testDeserializeProperty:self.deserialized.issuer comparedToValue:[self.serialized objectForKey:@"iss"] name:@"iss"]; [self testDeserializeProperty:self.deserialized.subject comparedToValue:[self.serialized objectForKey:@"sub"] name:@"sub"]; [self testDeserializeProperty:self.deserialized.audience comparedToValue:[self.serialized objectForKey:@"aud"] name:@"aud"]; [self testDeserializeProperty:self.deserialized.expirationDate comparedToValue:[NSDate dateWithTimeIntervalSince1970:[[self.serialized objectForKey:@"exp"] doubleValue]] name:@"exp"]; [self testDeserializeProperty:self.deserialized.notBeforeDate comparedToValue:[NSDate dateWithTimeIntervalSince1970:[[self.serialized objectForKey:@"nbf"] doubleValue]] name:@"nbf"]; [self testDeserializeProperty:self.deserialized.issuedAt comparedToValue:[NSDate dateWithTimeIntervalSince1970:[[self.serialized objectForKey:@"iat"] doubleValue]] name:@"iat"]; [self testDeserializeProperty:self.deserialized.identifier comparedToValue:[self.serialized objectForKey:@"jti"] name:@"jti"]; [self testDeserializeProperty:self.deserialized.type comparedToValue:[self.serialized objectForKey:@"typ"] name:@"typ"]; [self testDeserializeProperty:self.deserialized.scope comparedToValue:[self.serialized objectForKey:@"scope"] name:@"scope"]; } @end ================================================ FILE: Tests/JWTTests/Tests/JWT/JWTIssuesTests.m ================================================ // // JWTIssuesTests.m // iOS_Tests // // Created by Dmitry on 7/29/18. // @import XCTest; @import JWT; #import "JWTAssetAccessor.h" @interface JWTIssuesTests : XCTestCase @end @implementation JWTIssuesTests - (void)testIssues { [XCTContext runActivityNamed:@"RS256 key should be read correctly from file. #121" block:^(id _Nonnull activity) { __auto_type accessor = [[JWTAssetAccessor alloc] initWithFolder:@"rs256"]; __auto_type content = accessor.publicKeyBase64; id key = ((JWTCryptoSecurityComponent *)[[JWTCryptoSecurity componentsFromFileContent:content] componentsOfType:JWTCryptoSecurityComponents.Key].firstObject).content; NSLog(@"%@ key: %@", self.debugDescription, key); }]; [XCTContext runActivityNamed:@"RS256 signature verification crashes application #141" block:^(id _Nonnull activity) { NSString *publicKey = @"MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAM/l2OJO6C6eZWwV4h2FooxI2YZ/XNL+BP7kEB7wiudqi0vGRAheahe+vtazFE+J3V1iy+bwIqLXop571zgj6G0CAwEAAQ=="; NSString *algorithmName = JWTAlgorithmNameRS256; NSString *token = @"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGFpbVZlcnNpb24iOiIxLjAuMCIsImNvbnRlbnRIYXNoIjoiMDJlMzNkZjhlMjUwYzRmOTZlODUwM2VlZDRlMDJlN2MxMWQ1MWVmOGViYzI0MDkyM2NlOWQ0NDcwMWU5Y2YxOSIsImlhdCI6MTUwMzQwNzUxOH0.d1ETmvpXxPl747A8OzIGDy-Tke5D9NRVmnJtTBxx61wLQo7fH14u4XMWChMlkjG_9WAvWOAIVFtMQb9IZuA5QQ"; id verifyDataHolder = [JWTAlgorithmRSFamilyDataHolder new].keyExtractorType([JWTCryptoKeyExtractor publicKeyWithPEMBase64].type).algorithmName(algorithmName).secret(publicKey); JWTCodingBuilder *verifyBuilder = [JWTDecodingBuilder decodeMessage:token].addHolder(verifyDataHolder); JWTCodingResultType *verifyResult = verifyBuilder.result; if (verifyResult.successResult) { // success NSLog(@"%@ success: %@", self.debugDescription, verifyResult.successResult.payload); } else { // error NSLog(@"%@ error: %@", self.debugDescription, verifyResult.errorResult.error); } }]; [XCTContext runActivityNamed:@"RS256 verification fails with valid public key #139" block:^(id _Nonnull activity) { NSString *publicKey = @"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlyT86d6Stui8i8ZpzzbFHE+WVx/77fU+rglC6CMAslBr3WZO0xibQJJtBCTEkw7r6LkLaEOTkvHdjE1/cUnAFw4M7iIy238gx5gRoELZ7g+nh9C6v8HuQJovabaOFed+wnayw8D0YV5+JG6HJ4ExOO/3TmAum1yacBAzYFHcxOO/glbJY0/41K1kU7d5bFK9gs7DsMyBOInXDdIiTO9XrmN8zY3zncnsgYiwlrVwm5lfJIBnE38gOWen7EnFossogJqrn84SPao9Kslr9064PJN74AWh1ricU/A1zYH0QAFHSI2WGlyoH9V9ZbOWm8gn1IqCypVyg1YCrwaqThjESQIDAQAB"; NSString *algorithmName = JWTAlgorithmNameRS256; NSString* token = @"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC93d3cuY3JhY2tlZC5jb20iLCJhdWQiOiJjcmFja2VkIGFwcCIsInN1YiI6ImNyYWNrZWQgYXBwIiwiZXhwIjoxNTA0OTEzMTY2LCJ1aWQiOiI3Nzk3MiIsInNhbHQiOiI0NTQ3YjQ0ZTA2OTAyOTE3OTJiMjM0MjcwOWY5NTU4ZmQ2MTE3MGExIiwiYXBwX2FkIjpmYWxzZSwiYXBwX3ZvdGVfY29tbWVudCI6dHJ1ZX0.Bqllr9A2ULTlncb0EKLNjTn0qWKG_8NX6mwjf2S1GdS3JH9D7uGGVioxhHN24OZS5QCN9q6rcuYSQzMn-Vz4fAKtDOQws6LZLm7OFwe7uLYXlrK0w3GIxs6nRuGWGIzyxiwjOcy5Vs0HlKAZF7bE8aDUtW5WpbBz4JvgvKc2kmAc3IAMhxs8zRF0jaaiAye7Z7EMjtztmuW8eUosnwKPSa-P2zC-ElcAA67WJ7otYThlbqYDEnVhHrSxj3i3LdgRk0dwumf1zmIikCxFJBDClIroSat9J3hBYFTs6R8EL1YAUc387H_XXLMItLWeHPIMwmXx5wVzr6G_biWlaSyK1w"; id verifyDataHolder = [JWTAlgorithmRSFamilyDataHolder new].keyExtractorType([JWTCryptoKeyExtractor publicKeyWithPEMBase64].type).algorithmName(algorithmName).secret(publicKey); JWTCodingBuilder *verifyBuilder = [JWTDecodingBuilder decodeMessage:token].addHolder(verifyDataHolder); JWTCodingResultType *verifyResult = verifyBuilder.result; if (verifyResult.successResult) { // success NSLog(@"%@ success: %@", self.debugDescription, verifyResult.successResult.payload); token = verifyResult.successResult.encoded; NSLog(@"%@ token: %@", self.debugDescription, token); } else { // error NSLog(@"%@ error: %@", self.debugDescription, verifyResult.errorResult.error); } }]; [XCTContext runActivityNamed:@"Crashing RS256 decoding #112" block:^(id _Nonnull activity) { NSString *publicKey = @" MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdlatRjRjogo3WojgGHFHYLugdUWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQsHUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5Do2kQ+X5xK9cipRgEKwIDAQAB=="; NSString *algorithmName = @"RS256"; NSString *message = @"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.EkN-DOsnsuRjRO6BxXemmJDm3HbxrbRzXglbN2S4sOkopdU4IsDxTI8jO19W_A4K8ZPJijNLis4EZsHeY559a4DFOd50_OqgHGuERTqYZyuhtF39yxJPAjUESwxk2J5k_4zM3O-vtd1Ghyo4IbqKKSy6J9mTniYJPenn5-HIirE"; JWTBuilder *builder = [JWTBuilder decodeMessage:message].secret(publicKey).algorithmName(algorithmName); NSDictionary *dictionary = builder.decode; // should be invalid certificate error. if (builder.jwtError) { NSLog(@"%@ error occurred: %@", self, builder.jwtError); } else { NSLog(@"%@ payload! %@", self, dictionary); } XCTAssertNil(dictionary); }]; } @end ================================================ FILE: Tests/JWTTests/Tests/JWT/JWTReadmeTests.m ================================================ // // JWTReadmeTests.m // iOS_Tests // // Created by Dmitry on 7/29/18. // @import XCTest; @import JWT; @interface JWTReadmeTests : XCTestCase @end @implementation JWTReadmeTests - (void)testVersionThree { [XCTContext runActivityNamed:@"ClaimsSetCoordinator should work properly" block:^(id _Nonnull activity) { id claimsSetCoordinator = [JWTClaimsSetCoordinatorBase new]; __auto_type claimsSetDSL = claimsSetCoordinator.dslDesrciption; // fill it claimsSetDSL.issuer = @"Facebook"; claimsSetDSL.subject = @"Token"; claimsSetDSL.audience = @"https://jwt.io"; claimsSetCoordinator.claimsSetStorage = claimsSetDSL.claimsSetStorage; // encode it __auto_type secret = @"secret"; __auto_type algorithmName = @"HS384"; __auto_type headers = @{@"custom":@"value"}; idholder = [JWTAlgorithmHSFamilyDataHolder new].algorithmName(algorithmName).secret(secret); JWTCodingResultType *result = [JWTEncodingBuilder encodeClaimsSetWithCoordinator:claimsSetCoordinator].headers(headers).addHolder(holder).result; NSString *encodedToken = result.successResult.encoded; if (result.successResult) { // handle encoded result NSLog(@"encoded result: %@", result.successResult.encoded); } else { // handle error NSLog(@"encode failed, error: %@", result.errorResult.error); } // decode it // you can set any property that you want, all properties are optional __auto_type trustedClaimsSet = claimsSetDSL.claimsSetStorage; NSNumber *options = @(JWTCodingDecodingOptionsNone); NSString *yourJwt = encodedToken; // from previous example JWTCodingResultType *decodedResult = [JWTDecodingBuilder decodeMessage:yourJwt].claimsSetCoordinator(claimsSetCoordinator).addHolder(holder).options(options).and.result; if (decodedResult.successResult) { // handle decoded result NSLog(@"decoded result: %@", decodedResult.successResult.headerAndPayloadDictionary); NSLog(@"headers: %@", decodedResult.successResult.headers); NSLog(@"payload: %@", decodedResult.successResult.payload); NSLog(@"trustedClaimsSet: %@", [claimsSetCoordinator.claimsSetSerializer dictionaryFromClaimsSet:trustedClaimsSet]); NSLog(@"decodedClaimsSet: %@", [claimsSetCoordinator.claimsSetSerializer dictionaryFromClaimsSet:decodedResult.successResult.claimsSetStorage]); } else { // handle error NSLog(@"decode failed, error: %@", decodedResult.errorResult.error); } }]; [XCTContext runActivityNamed:@"API should work well with EC algorithms" block:^(id _Nonnull activity) { NSString *privatePemFilename = @"ec256-private"; NSString *publicPemFilename = @"ec256-public"; NSString *passphrase = @"password"; NSString *(^loadKey)(NSString *, NSBundle *) = ^NSString *(NSString *name, NSBundle *bundle){ NSURL *fileURL = [bundle URLForResource:name withExtension:@"pem"]; NSError *error = nil; NSString *fileContent = [NSString stringWithContentsOfURL:fileURL encoding:NSUTF8StringEncoding error:&error]; if (error) { NSLog(@"%@ error: %@", self.debugDescription, error); return nil; } return fileContent; }; NSBundle *bundle = [NSBundle bundleForClass:self.class]; NSString *publicPemKey = loadKey(publicPemFilename, bundle); NSString *privatePemKey = loadKey(privatePemFilename, bundle); // sign and verify { NSString *algorithmName = @"ES256"; id signDataHolder = [JWTAlgorithmRSFamilyDataHolder new].keyExtractorType([JWTCryptoKeyExtractor privateKeyWithPEMBase64].type).privateKeyCertificatePassphrase(passphrase).algorithmName(algorithmName).secret(privatePemKey); id verifyDataHolder = [JWTAlgorithmRSFamilyDataHolder new].keyExtractorType([JWTCryptoKeyExtractor publicKeyWithPEMBase64].type).algorithmName(algorithmName).secret(publicPemKey); NSDictionary *payloadDictionary = @{@"hello": @"world"}; JWTCodingBuilder *signBuilder = [JWTEncodingBuilder encodePayload:payloadDictionary].addHolder(signDataHolder); JWTCodingResultType *signResult = signBuilder.result; NSString *token = nil; if (signResult.successResult) { // success NSLog(@"%@ success: %@", self.debugDescription, signResult.successResult.encoded); token = signResult.successResult.encoded; } else { // error NSLog(@"%@ error: %@", self.debugDescription, signResult.errorResult.error); } // verify if (token == nil) { NSLog(@"something wrong"); } JWTCodingBuilder *verifyBuilder = [JWTDecodingBuilder decodeMessage:token].addHolder(verifyDataHolder); JWTCodingResultType *verifyResult = verifyBuilder.result; if (verifyResult.successResult) { // success NSLog(@"%@ success: %@", self.debugDescription, verifyResult.successResult.payload); token = verifyResult.successResult.encoded; NSLog(@"%@ token: %@", self.debugDescription, token); } else { // error NSLog(@"%@ error: %@", self.debugDescription, verifyResult.errorResult.error); } } }]; [XCTContext runActivityNamed:@"API should work well with Pem keys loading" block:^(id _Nonnull activity){ NSString *privatePemFilename = @"rs256-private"; NSString *publicPemFilename = @"rs256-public"; NSString *passphrase = @"password"; NSString *(^loadKey)(NSString *, NSBundle *) = ^NSString *(NSString *name, NSBundle *bundle){ NSURL *fileURL = [bundle URLForResource:name withExtension:@"pem"]; NSError *error = nil; NSString *fileContent = [NSString stringWithContentsOfURL:fileURL encoding:NSUTF8StringEncoding error:&error]; if (error) { NSLog(@"%@ error: %@", self.debugDescription, error); return nil; } return fileContent; }; NSBundle *bundle = [NSBundle bundleForClass:self.class]; NSString *publicPemKey = loadKey(publicPemFilename, bundle); NSString *privatePemKey = loadKey(privatePemFilename, bundle); // sign and verify { NSString *algorithmName = @"RS256"; id signDataHolder = [JWTAlgorithmRSFamilyDataHolder new].keyExtractorType([JWTCryptoKeyExtractor privateKeyWithPEMBase64].type).privateKeyCertificatePassphrase(passphrase).algorithmName(algorithmName).secret(privatePemKey); id verifyDataHolder = [JWTAlgorithmRSFamilyDataHolder new].keyExtractorType([JWTCryptoKeyExtractor publicKeyWithPEMBase64].type).algorithmName(algorithmName).secret(publicPemKey); NSDictionary *payloadDictionary = @{@"hello": @"world"}; JWTCodingBuilder *signBuilder = [JWTEncodingBuilder encodePayload:payloadDictionary].addHolder(signDataHolder); JWTCodingResultType *signResult = signBuilder.result; NSString *token = nil; if (signResult.successResult) { // success NSLog(@"%@ success: %@", self.debugDescription, signResult.successResult.encoded); token = signResult.successResult.encoded; } else { // error NSLog(@"%@ error: %@", self.debugDescription, signResult.errorResult.error); } // verify if (token == nil) { NSLog(@"something wrong"); } JWTCodingBuilder *verifyBuilder = [JWTDecodingBuilder decodeMessage:token].addHolder(verifyDataHolder); JWTCodingResultType *verifyResult = verifyBuilder.result; if (verifyResult.successResult) { // success NSLog(@"%@ success: %@", self.debugDescription, verifyResult.successResult.payload); token = verifyResult.successResult.encoded; NSLog(@"%@ token: %@", self.debugDescription, token); } else { // error NSLog(@"%@ error: %@", self.debugDescription, verifyResult.errorResult.error); } } }]; [XCTContext runActivityNamed:@"API should show work with chains moderate" block:^(id _Nonnull activity){ JWTClaimsSet *claimsSet = [[JWTClaimsSet alloc] init]; // fill it claimsSet.issuer = @"Facebook"; claimsSet.subject = @"Token"; claimsSet.audience = @"https://jwt.io"; // possible that your algorithm has several secrets. // you don't know which secret to use. // but you want to decode it. NSString *firstSecret = @"first"; NSArray *manySecrets = @[@"second", @"third", @"forty two"]; // translate to data NSArray *manySecretsData = @[]; for (NSString *secret in manySecrets) { NSData *secretData = [JWTBase64Coder dataWithBase64UrlEncodedString:secret]; if (secret) { manySecretsData = [manySecretsData arrayByAddingObject:secretData]; } } NSString *algorithmName = JWTAlgorithmNameHS384; id firstHolder = [JWTAlgorithmHSFamilyDataHolder new].algorithmName(algorithmName).secret(firstSecret); // lets create chain JWTAlgorithmDataHolderChain *chain = [JWTAlgorithmDataHolderChain chainWithHolder:firstHolder]; // and lets populate chain with secrets. NSLog(@"chain has: %@", chain.debugDescription); JWTAlgorithmDataHolderChain *expandedChain = [chain chainByPopulatingAlgorithm:firstHolder.internalAlgorithm withManySecretData:manySecretsData]; // now we have expanded chain with many secrets and one algorithm. NSLog(@"expanded chain has: %@", expandedChain.debugDescription); }]; [XCTContext runActivityNamed:@"API should show work with chains simple" block:^(id _Nonnull activity){ JWTClaimsSet *claimsSet = [[JWTClaimsSet alloc] init]; // fill it claimsSet.issuer = @"Facebook"; claimsSet.subject = @"Token"; claimsSet.audience = @"https://jwt.io"; // create token NSString *token = @"..."; // possible that algorithm could return error. // you could try use algorithm and data chain. NSString *firstSecret = @"first"; NSString *firstAlgorithmName = JWTAlgorithmNameHS384; id firstHolder = [JWTAlgorithmHSFamilyDataHolder new].algorithmName(firstAlgorithmName).secret(firstSecret); id errorHolder = [JWTAlgorithmNoneDataHolder new]; // chain together. JWTAlgorithmDataHolderChain *chain = [[JWTAlgorithmDataHolderChain alloc] initWithHolders:@[firstHolder, errorHolder]]; // or add them in builder [JWTDecodingBuilder decodeMessage:token].addHolder(firstHolder).addHolder(errorHolder); // or add them as chain [JWTDecodingBuilder decodeMessage:token].chain(chain); }]; } - (void)testOthers { [XCTContext runActivityNamed:@"RS coding should work correctly" block:^(id _Nonnull activity){ // Test example. // Encode NSDictionary *payload = @{@"payload" : @"hidden_information"}; NSString *algorithmName = @"RS256"; NSString *fileName = @"Test certificate and private key 1"; NSString *filePath = [[NSBundle bundleForClass:[self class]] pathForResource:fileName ofType:@"p12"]; NSData *privateKeySecretData = [NSData dataWithContentsOfFile:filePath]; NSString *passphraseForPrivateKey = @"password"; JWTBuilder *builder = [JWTBuilder encodePayload:payload].secretData(privateKeySecretData).privateKeyCertificatePassphrase(passphraseForPrivateKey).algorithmName(algorithmName); NSString *token = builder.encode; // check error if (builder.jwtError) { // error occurred. NSLog(@"%@ error occured while encoding: %@", self, builder.jwtError); } else { NSLog(@"%@ token: %@", self, token); } // Decode // Suppose, that you get token from previous example. You need a valid public key for a private key in previous example. // Private key stored in @"secret_key.p12". So, you need public key for that private key. NSString *publicKey = @"..."; // load public key. Or use it as raw string. // test example: publicKey = @"MIICnTCCAYUCBEReYeAwDQYJKoZIhvcNAQEFBQAwEzERMA8GA1UEAxMIand0LTIwNDgwHhcNMTQwMTI0MTMwOTE2WhcNMzQwMjIzMjAwMDAwWjATMREwDwYDVQQDEwhqd3QtMjA0ODCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKhWb9KXmv45+TKOKhFJkrboZbpbKPJ9Yp12xKLXf8060KfStEStIX+7dCuAYylYWoqiGpuLVVUL5JmHgXmK9TJpzv9Dfe3TAc/+35r8r9IYB2gXUOZkebty05R6PLY0RO/hs2ZhrOozHMo+x216Gwz0CWaajcuiY5Yg1V8VvJ1iQ3rcRgZapk49RNX69kQrGS63gzj0gyHnRtbqc/Ua2kobCA83nnznCom3AGinnlSN65AFPP5jmri0l79+4ZZNIerErSW96mUF8jlJFZI1yJIbzbv73tL+y4i0+BvzsWBs6TkHAp4pinaI8zT+hrVQ2jD4fkJEiRN9lAqLPUd8CNkCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAnqBw3UHOSSHtU7yMi1+HE+9119tMh7X/fCpcpOnjYmhW8uy9SiPBZBl1z6vQYkMPcURnDMGHdA31kPKICZ6GLWGkBLY3BfIQi064e8vWHW7zX6+2Wi1zFWdJlmgQzBhbr8pYh9xjZe6FjPwbSEuS0uE8dWSWHJLdWsA4xNX9k3pr601R2vPVFCDKs3K1a8P/Xi59kYmKMjaX6vYT879ygWt43yhtGTF48y85+eqLdFRFANTbBFSzdRlPQUYa5d9PZGxeBTcg7UBkK/G+d6D5sd78T2ymwlLYrNi+cSDYD6S4hwZaLeEK6h7p/OoG02RBNuT4VqFRu5DJ6Po+C6JhqQ=="; algorithmName = @"RS256"; JWTBuilder *decodeBuilder = [JWTBuilder decodeMessage:token].secret(publicKey).algorithmName(algorithmName); NSDictionary *envelopedPayload = decodeBuilder.decode; // check error if (decodeBuilder.jwtError) { // error occurred. NSLog(@"%@ error occured while decoding %@", self,decodeBuilder.jwtError); } else { NSLog(@"%@ envelopedPayload: %@ ", self, envelopedPayload); } }]; [XCTContext runActivityNamed:@"fluent example should work correctly" block:^(id _Nonnull activity){ // suppose, that you create ClaimsSet JWTClaimsSet *claimsSet = [[JWTClaimsSet alloc] init]; // fill it claimsSet.issuer = @"Facebook"; claimsSet.subject = @"Token"; claimsSet.audience = @"https://jwt.io"; // encode it NSString *secret = @"secret"; NSString *algorithmName = @"HS384"; NSDictionary *headers = @{@"custom":@"value"}; JWTBuilder *encodeBuilder = [JWT encodeClaimsSet:claimsSet]; NSString *encodedResult = encodeBuilder.secret(secret).algorithmName(algorithmName).headers(headers).encode; if (encodeBuilder.jwtError) { // handle error NSLog(@"encode failed, error: %@", encodeBuilder.jwtError); } else { // handle encoded result NSLog(@"encoded result: %@", encodedResult); } // decode it // you can set any property that you want, all properties are optional JWTClaimsSet *trustedClaimsSet = [claimsSet copy]; // decode forced ? try YES BOOL decodeForced = NO; NSNumber *options = @(decodeForced); NSString *yourJwt = encodedResult; // from previous example NSString *yourSecret = secret; // from previous example JWTBuilder *decodeBuilder = [JWT decodeMessage:yourJwt]; NSDictionary *decodedResult = decodeBuilder.message(yourJwt).secret(yourSecret).claimsSet(trustedClaimsSet).options(options).decode; if (decodeBuilder.jwtError) { // handle error NSLog(@"decode failed, error: %@", decodeBuilder.jwtError); } else { // handle decoded result NSLog(@"decoded result: %@", decodedResult); } }]; } - (void)testReadme { [self testVersionThree]; [self testOthers]; } @end ================================================ FILE: Tests/JWTTests/Tests/JWTCoding/JWTCodingTests.m ================================================ // // JWTCodingTests.m // // // Created by Dmitry Lobanov on 06.02.2022. // #import @import JWT; @interface JWTCodingTests : XCTestCase @end @implementation JWTCodingTests - (void)setUp { // Put setup code here. This method is called before the invocation of each test method in the class. } - (void)tearDown { // Put teardown code here. This method is called after the invocation of each test method in the class. } - (void)testJWTCodingBuilderShouldEncode { __auto_type expectedToken = @"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"; __auto_type secret = @"secret"; __auto_type payload = @{ @"sub": @"1234567890", @"name": @"John Doe", @"admin": @(YES), }; __auto_type holder = [JWTAlgorithmHSFamilyDataHolder new].algorithmName(JWTAlgorithmNameHS256).secret(secret); __auto_type result = [JWTEncodingBuilder encodePayload:payload].addHolder(holder).result; XCTAssertNotNil(result.successResult); // XCTAssertEqualObjects(result.successResult.encoded, expectedToken); XCTAssertNil(result.errorResult); } - (void)testJWTCodingBuilderShouldDecode { __auto_type token = @"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"; __auto_type secret = @"secret"; __auto_type expectedHeaders = @{ @"typ": @"JWT", @"alg": @"HS256" }; __auto_type expectedPayload = @{ @"admin": @(1), @"name": @"John Doe", @"sub": @"1234567890" }; __auto_type holder = [JWTAlgorithmHSFamilyDataHolder new].algorithmName(JWTAlgorithmNameHS256).secret(secret); __auto_type result = [JWTDecodingBuilder decodeMessage:token].addHolder(holder).result; XCTAssertNotNil(result.successResult); XCTAssertEqualObjects(result.successResult.headers, expectedHeaders); XCTAssertEqualObjects(result.successResult.payload, expectedPayload); XCTAssertNil(result.errorResult); } @end ================================================ FILE: Tests/JWTTests/include/JWTAssetAccessor.h ================================================ // // JWTAssetAccessor.h // Tests // // Created by Dmitry Lobanov on 05.01.2022. // #import #import NS_ASSUME_NONNULL_BEGIN @interface JWTAssetAccessor : NSObject @property (copy, nonatomic, readwrite) NSString *folder; - (instancetype)initWithFolder:(NSString *)folder; - (instancetype)initWithAlgorithmType:(NSString *)type shaSize:(NSNumber *)size; - (instancetype)initWithAlgorithName:(NSString *)name; @end @interface JWTAssetAccessor (Validation) - (nullable instancetype)checked; - (BOOL)check; @end @interface JWTAssetAccessor (FolderAccess) - (NSString *)stringFromFileWithName:(NSString *)name; - (NSData *)dataFromFileWithName:(NSString *)name; @end @interface JWTAssetAccessor (Getters) @property (copy, nonatomic, readonly) NSString *privateKeyBase64; @property (copy, nonatomic, readonly) NSString *publicKeyBase64; @property (copy, nonatomic, readonly) NSString *certificateBase64; @property (copy, nonatomic, readonly) NSData *p12Data; @property (copy, nonatomic, readonly) NSString *p12Password; @end NS_ASSUME_NONNULL_END ================================================ FILE: VERSION ================================================ 3.0.0-beta.14