diff --git a/.github/workflows/modules.yml b/.github/workflows/modules.yml new file mode 100644 index 000000000..361e5689c --- /dev/null +++ b/.github/workflows/modules.yml @@ -0,0 +1,56 @@ +name: Build & Test with modules + +on: + push: + branches: [master] + pull_request: + branches: [master] + paths: + - "CMakeLists.txt" + - "cmake/**" + - "include/jwt-cpp/**" + - "tests/cmake/**" + - ".github/actions/**" + - ".github/workflows/cmake.yml" + +jobs: + build: + name: ${{ matrix.runs_on }}-${{ matrix.compiler }}-${{ matrix.configure_preset }} + runs-on: ${{ matrix.runs_on }} + strategy: + fail-fast: false + matrix: + include: + - runs_on: windows-2025-vs2026 + compiler: msvc-14.50 + configure_preset: "x64-vs-modules" + build_preset: "x64-vs-modules-build" + test_preset : "x64-vs-modules-test" + # To be uncommented once GitHub Actions adds GCC 15 with Ubuntu 26 + # - runs_on: ubuntu-latest + # compiler: gcc-15 + # configure_preset: "linux-debug" + # build_preset: "linux-debug-build" + # test_preset : "linux-debug-test" + # - runs_on: ubuntu-latest + # compiler: clang-18 + # cc: clang + # cxx: clang++ + # configure_preset: "linux-debug-modules" + # build_preset: "linux-debug-modules-build" + # test_preset : "linux-debug-modules-test" + steps: + + - uses: actions/checkout@v6 + + - uses: lukka/get-cmake@latest + + - name: "Build & Test" + uses: lukka/run-cmake@v10 + env: + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + with: + configurePreset: ${{ matrix.configure_preset }} + buildPreset: ${{ matrix.build_preset }} + testPreset: ${{ matrix.test_preset }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8c2dfa7ad..515f2a82b 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ +out/ # Visual Studio 2015 cache/options directory .vs/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b494d4fe..31e313fd1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,8 @@ if(POLICY CMP0135) # DOWNLOAD_EXTRACT_TIMESTAMP cmake_policy(SET CMP0135 NEW) endif() +set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "451f2fe2-a8a2-47c3-bc32-94786d8fc91b") + # HUNTER_ENABLED is always set if this package is included in a project using hunter (HunterGate sets it) In this case # we will use hunter as well to stay consistent. If not the use can supply it on configure to force using hunter. if(HUNTER_ENABLED) @@ -20,6 +22,8 @@ option(JWT_BUILD_TESTS "Configure CMake to build tests (or not)" OFF) option(JWT_BUILD_DOCS "Adds a target for building the doxygen documentation" OFF) option(JWT_ENABLE_COVERAGE "Enable code coverage testing" OFF) option(JWT_ENABLE_FUZZING "Enable fuzz testing" OFF) +option(JWT_ENABLE_MODULES "Build C++ modules" OFF) +option(JWT_USE_IMPORT_STD "Use import std" OFF) option(JWT_DISABLE_PICOJSON "Do not provide the picojson template specialiaze" OFF) option(JWT_DISABLE_BASE64 "Do not include the base64 implementation from this library" OFF) @@ -92,50 +96,95 @@ endif() set(JWT_INCLUDE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/include) set(JWT_HEADER_FILES ${JWT_INCLUDE_PATH}/jwt-cpp/jwt.h) +set(JWT_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/modules) foreach(traits ${JWT_JSON_TRAITS_OPTIONS}) list(APPEND JWT_HEADER_FILES ${JWT_INCLUDE_PATH}/jwt-cpp/traits/${traits}/defaults.h ${JWT_INCLUDE_PATH}/jwt-cpp/traits/${traits}/traits.h) endforeach() if(NOT JWT_DISABLE_BASE64) - list(APPEND JWT_HEADER_FILES ${JWT_INCLUDE_PATH}/jwt-cpp/base.h) + list(APPEND JWT_HEADER_FILES ${JWT_INCLUDE_PATH}/jwt-cpp/base.h) endif() -add_library(jwt-cpp INTERFACE) +if (JWT_ENABLE_MODULES) + if(CMAKE_VERSION VERSION_LESS "4.3") + message(FATAL_ERROR "CMake >= 4.3 is required to build with modules") + endif() + + set(CMAKE_CXX_SCAN_FOR_MODULES ON) + + if(JWT_USE_IMPORT_STD) + if(NOT CMAKE_GENERATOR MATCHES "Visual Studio") + set(CMAKE_CXX_MODULE_STD 1) + endif() + endif() +endif() + +if (JWT_ENABLE_MODULES) + add_library(jwt-cpp STATIC) + set(JWT_LIBRARY_TYPE PUBLIC) +else() + add_library(jwt-cpp INTERFACE) + set(JWT_LIBRARY_TYPE INTERFACE) +endif() add_library(jwt-cpp::jwt-cpp ALIAS jwt-cpp) # To match export -target_compile_features(jwt-cpp INTERFACE cxx_std_11) + +if(NOT JWT_ENABLE_MODULES) + target_compile_features(jwt-cpp ${JWT_LIBRARY_TYPE} cxx_std_11) +else() + if(NOT JWT_USE_IMPORT_STD) + target_compile_features(jwt-cpp ${JWT_LIBRARY_TYPE} cxx_std_20) + else() + target_compile_features(jwt-cpp ${JWT_LIBRARY_TYPE} cxx_std_23) + target_compile_definitions(jwt-cpp PRIVATE JWT_USE_IMPORT_STD) + endif() + target_sources(jwt-cpp + PUBLIC + FILE_SET cxx_modules TYPE CXX_MODULES + BASE_DIRS ${JWT_MODULE_PATH} + FILES ${JWT_MODULE_PATH}/jwt.cppm + ) +endif() + if(JWT_DISABLE_BASE64) - target_compile_definitions(jwt-cpp INTERFACE JWT_DISABLE_BASE64) + target_compile_definitions(jwt-cpp ${JWT_LIBRARY_TYPE} JWT_DISABLE_BASE64) endif() if(JWT_DISABLE_PICOJSON) - target_compile_definitions(jwt-cpp INTERFACE JWT_DISABLE_PICOJSON) + target_compile_definitions(jwt-cpp ${JWT_LIBRARY_TYPE} JWT_DISABLE_PICOJSON) endif() + +source_group( + TREE "${JWT_INCLUDE_PATH}" + PREFIX "Implementation files" + FILES ${JWT_HEADER_FILES} +) + include(GNUInstallDirs) include(CMakePackageConfigHelpers) -target_include_directories(jwt-cpp INTERFACE $ +target_include_directories(jwt-cpp ${JWT_LIBRARY_TYPE} $ $) if(${JWT_SSL_LIBRARY} MATCHES "OpenSSL") - target_link_libraries(jwt-cpp INTERFACE OpenSSL::SSL OpenSSL::Crypto) + target_link_libraries(jwt-cpp ${JWT_LIBRARY_TYPE} OpenSSL::SSL OpenSSL::Crypto) endif() if(${JWT_SSL_LIBRARY} MATCHES "LibreSSL") - target_link_libraries(jwt-cpp INTERFACE LibreSSL::TLS) + target_link_libraries(jwt-cpp ${JWT_LIBRARY_TYPE} LibreSSL::TLS) endif() if(${JWT_SSL_LIBRARY} MATCHES "wolfSSL") - target_link_libraries(jwt-cpp INTERFACE PkgConfig::wolfssl) + target_link_libraries(jwt-cpp ${JWT_LIBRARY_TYPE} PkgConfig::wolfssl) # This is required to access OpenSSL compatibility API - target_include_directories(jwt-cpp INTERFACE ${wolfssl_INCLUDE_DIRS}) - # This flag is required to have the mandatory header included automatically + target_include_directories(jwt-cpp ${JWT_LIBRARY_TYPE} ${wolfssl_INCLUDE_DIRS}) + # This flag is required to have the mandatory header included automatically # https://github.com/Thalhammer/jwt-cpp/pull/352#discussion_r1627971786 # https://github.com/wolfSSL/wolfssl/blob/3b74a6402998a8b8839e25e31ba8ac74749aa9b0/wolfssl/wolfcrypt/settings.h#L58 - target_compile_definitions(jwt-cpp INTERFACE EXTERNAL_OPTS_OPENVPN) + target_compile_definitions(jwt-cpp ${JWT_LIBRARY_TYPE} EXTERNAL_OPTS_OPENVPN) endif() if(NOT JWT_DISABLE_PICOJSON AND JWT_EXTERNAL_PICOJSON) - target_link_libraries(jwt-cpp INTERFACE picojson::picojson) + target_link_libraries(jwt-cpp ${JWT_LIBRARY_TYPE} picojson::picojson) endif() # Hunter needs relative paths so the files are placed correctly @@ -146,18 +195,22 @@ endif() configure_package_config_file( ${CMAKE_CURRENT_LIST_DIR}/cmake/jwt-cpp-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/jwt-cpp-config.cmake INSTALL_DESTINATION ${JWT_CMAKE_FILES_INSTALL_DIR}) -write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/jwt-cpp-config-version.cmake VERSION 0.7.2 - COMPATIBILITY ExactVersion) - -install(TARGETS jwt-cpp EXPORT jwt-cpp-targets PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/jwt-cpp-config-version.cmake VERSION 0.7.2 COMPATIBILITY ExactVersion) +if (JWT_ENABLE_MODULES) + install(TARGETS jwt-cpp EXPORT jwt-cpp-targets + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILE_SET cxx_modules DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/modules) +else() + install(TARGETS jwt-cpp EXPORT jwt-cpp-targets + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +endif() install(EXPORT jwt-cpp-targets NAMESPACE jwt-cpp:: FILE jwt-cpp-targets.cmake DESTINATION ${JWT_CMAKE_FILES_INSTALL_DIR}) install(DIRECTORY ${JWT_INCLUDE_PATH}/jwt-cpp DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) if(NOT JWT_EXTERNAL_PICOJSON AND NOT JWT_DISABLE_PICOJSON) install(FILES ${JWT_INCLUDE_PATH}/picojson/picojson.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/picojson) endif() -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/jwt-cpp-config.cmake ${CMAKE_CURRENT_BINARY_DIR}/jwt-cpp-config-version.cmake - DESTINATION ${JWT_CMAKE_FILES_INSTALL_DIR}) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/jwt-cpp-config.cmake ${CMAKE_CURRENT_BINARY_DIR}/jwt-cpp-config-version.cmake DESTINATION ${JWT_CMAKE_FILES_INSTALL_DIR}) if(JWT_BUILD_EXAMPLES) add_subdirectory(example) diff --git a/CMakePresets.json b/CMakePresets.json index acac67081..8463236f1 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -21,6 +21,47 @@ "JWT_BUILD_EXAMPLES": "ON", "JWT_BUILD_TESTS": "ON" } + }, + { + "name": "windows-vs-base", + "hidden": true, + "generator": "Visual Studio 18 2026", + "binaryDir": "${sourceDir}/out/build/${presetName}", + "installDir": "${sourceDir}/out/install/${presetName}", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "x64-vs-modules", + "displayName": "x64 (VS generator) with Modules", + "inherits": "windows-vs-base", + "architecture": "x64", + "cacheVariables": { + "JWT_ENABLE_MODULES": "ON", + "JWT_USE_IMPORT_STD": "ON", + "JWT_BUILD_EXAMPLES": "ON" + } + }, + { + "name": "linux-debug-modules", + "displayName": "Linux Debug with Modules", + "generator": "Ninja", + "binaryDir": "${sourceDir}/out/build/${presetName}", + "installDir": "${sourceDir}/out/install/${presetName}", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "JWT_ENABLE_MODULES": "ON", + "JWT_USE_IMPORT_STD": "ON", + "JWT_BUILD_EXAMPLES": "ON" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Linux" + } } ], "buildPresets": [ @@ -28,6 +69,14 @@ "name": "dev", "configurePreset": "dev", "configuration": "Debug" + }, + { + "name": "x64-vs-modules-build", + "configurePreset": "x64-vs-modules" + }, + { + "name": "linux-debug-modules-build", + "configurePreset": "linux-debug-modules" } ], "testPresets": [ @@ -35,6 +84,14 @@ "name": "dev", "displayName": "Run all tests", "configurePreset": "dev" + }, + { + "name": "x64-vs-modules-test", + "configurePreset": "x64-vs-modules" + }, + { + "name": "linux-debug-modules-test", + "configurePreset": "linux-debug-modules" } ] } \ No newline at end of file diff --git a/README.md b/README.md index 6412ada0f..80aa26dc2 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,15 @@ If you are looking to issue or verify more unique tokens, checkout out the [exam Building on the goal of providing flexibility. +#### Modules support +jwt-cpp supports C++20/23 modules. There are two configuration options: `JWT_ENABLE_MODULES` to enable modules (С++20) and `JWT_USE_IMPORT_STD` to use `import std` (С++23). +CMake example: +```cmake +set(JWT_ENABLE_MODULES ON) +set(JWT_USE_IMPORT_STD ON) +``` +You can now `import jwt_cpp;`. + #### SSL Compatibility jwt-cpp supports [OpenSSL](https://github.com/openssl/openssl), [LibreSSL](https://github.com/libressl-portable/portable), and [wolfSSL](https://github.com/wolfSSL/wolfssl). For a listed of tested versions, check [this page](docs/ssl.md) for more details. diff --git a/docs/install.md b/docs/install.md index 3266e29ff..28220b2f6 100644 --- a/docs/install.md +++ b/docs/install.md @@ -8,6 +8,15 @@ It's strongly recommended to use a package manager, as JWT-CPP has dependencies When manually adding this dependency, and the dependencies this has, check the GitHub Actions and Workflows for some inspiration about how to go about it. +#### Modules support +jwt-cpp supports C++20/23 modules. There are two configuration options: `JWT_ENABLE_MODULES` to enable modules (С++20) and `JWT_USE_IMPORT_STD` to use `import std` (С++23). +CMake example: +```cmake +set(JWT_ENABLE_MODULES ON) +set(JWT_USE_IMPORT_STD ON) +``` +You can now `import jwt_cpp;`. + ### Package Manager - Conan: diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 6406dc247..ffd04118d 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.14) +cmake_minimum_required(VERSION 3.15) project(jwt-cpp-examples) if(NOT TARGET jwt-cpp) @@ -14,25 +14,43 @@ endif() add_executable(print-claims print-claims.cpp) target_link_libraries(print-claims jwt-cpp::jwt-cpp) add_custom_target(print-claims-run COMMAND print-claims) +if (JWT_ENABLE_MODULES) + target_compile_definitions(print-claims PRIVATE JWT_ENABLE_MODULES) +endif() add_executable(private-claims private-claims.cpp) target_link_libraries(private-claims jwt-cpp::jwt-cpp) add_custom_target(private-claims-run COMMAND private-claims) +if (JWT_ENABLE_MODULES) + target_compile_definitions(private-claims PRIVATE JWT_ENABLE_MODULES) +endif() add_executable(rsa-create rsa-create.cpp) target_link_libraries(rsa-create jwt-cpp::jwt-cpp) add_custom_target(rsa-create-run COMMAND rsa-create) +if (JWT_ENABLE_MODULES) + target_compile_definitions(rsa-create PRIVATE JWT_ENABLE_MODULES) +endif() add_executable(rsa-verify rsa-verify.cpp) target_link_libraries(rsa-verify jwt-cpp::jwt-cpp) add_custom_target(rsa-verify-run COMMAND rsa-verify) +if (JWT_ENABLE_MODULES) + target_compile_definitions(rsa-verify PRIVATE JWT_ENABLE_MODULES) +endif() add_executable(jwks-verify jwks-verify.cpp) target_link_libraries(jwks-verify jwt-cpp::jwt-cpp) add_custom_target(jwks-verify-run COMMAND jwks-verify) +if (JWT_ENABLE_MODULES) + target_compile_definitions(jwks-verify PRIVATE JWT_ENABLE_MODULES) +endif() add_executable(es256k es256k.cpp) target_link_libraries(es256k jwt-cpp::jwt-cpp) +if (JWT_ENABLE_MODULES) + target_compile_definitions(es256k PRIVATE JWT_ENABLE_MODULES) +endif() add_executable(partial-claim-verifier partial-claim-verifier.cpp) target_link_libraries(partial-claim-verifier jwt-cpp::jwt-cpp nlohmann_json::nlohmann_json) diff --git a/example/es256k.cpp b/example/es256k.cpp index 0ba701927..c8d599095 100644 --- a/example/es256k.cpp +++ b/example/es256k.cpp @@ -1,6 +1,18 @@ /// @file es256k.cpp + +#ifndef JWT_ENABLE_MODULES +#include #include #include +#else +#ifdef JWT_USE_IMPORT_STD +import std; +#else +#include +#include +#endif +import jwt_cpp; +#endif int main() { // openssl ecparam -name secp256k1 -genkey -noout -out ec-secp256k1-priv-key.pem diff --git a/example/jwks-verify.cpp b/example/jwks-verify.cpp index fa966e35a..5918ee02b 100644 --- a/example/jwks-verify.cpp +++ b/example/jwks-verify.cpp @@ -4,9 +4,21 @@ * Novel example using a JWT's "key ID" to match with a JWK Set * and using the corresponding x5c from the JWK to verify the token */ +#include + +#ifndef JWT_ENABLE_MODULES #include +#include #include -#include +#else +#ifdef JWT_USE_IMPORT_STD +import std; +#else +#include +#include +#endif +import jwt_cpp; +#endif int main() { std::string raw_jwks = diff --git a/example/partial-claim-verifier.cpp b/example/partial-claim-verifier.cpp index 0ca427b17..a347a3fd3 100644 --- a/example/partial-claim-verifier.cpp +++ b/example/partial-claim-verifier.cpp @@ -1,8 +1,8 @@ /// @file partial-claim-verifier.cpp -#include "jwt-cpp/traits/nlohmann-json/defaults.h" - #include +#include "jwt-cpp/traits/nlohmann-json/defaults.h" + int main() { std::string const rsa_priv_key = R"(-----BEGIN PRIVATE KEY----- MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC4ZtdaIrd1BPIJ diff --git a/example/print-claims.cpp b/example/print-claims.cpp index 15badcc9f..56ae1038d 100644 --- a/example/print-claims.cpp +++ b/example/print-claims.cpp @@ -1,6 +1,16 @@ /// @file print-claims.cpp + +#ifndef JWT_ENABLE_MODULES #include #include +#else +#ifdef JWT_USE_IMPORT_STD +import std; +#else +#include +#endif +import jwt_cpp; +#endif int main() { const std::string token = diff --git a/example/private-claims.cpp b/example/private-claims.cpp index f2718989d..068ea01f1 100644 --- a/example/private-claims.cpp +++ b/example/private-claims.cpp @@ -1,8 +1,20 @@ /// @file private-claims.cpp -#include +#ifndef JWT_ENABLE_MODULES +#include +#include +#include +#include +#else +#ifdef JWT_USE_IMPORT_STD +import std; +#else +#include #include #include +#endif +import jwt_cpp; +#endif using sec = std::chrono::seconds; using min = std::chrono::minutes; @@ -13,7 +25,7 @@ int main() { iss >> from_raw_json; jwt::claim::set_t list{"once", "twice"}; - std::vector big_numbers{727663072ULL, 770979831ULL, 427239169ULL, 525936436ULL}; + std::vector big_numbers{727663072ULL, 770979831ULL, 427239169ULL, 525936436ULL}; const auto time = jwt::date::clock::now(); const auto token = jwt::create() @@ -24,7 +36,7 @@ int main() { .set_not_before(time - sec{15}) .set_expires_at(time + sec{15} + min{2}) .set_payload_claim("boolean", picojson::value(true)) - .set_payload_claim("integer", picojson::value(int64_t{12345})) + .set_payload_claim("integer", picojson::value(std::int64_t{12345})) .set_payload_claim("precision", picojson::value(12.345)) .set_payload_claim("strings", jwt::claim(list)) .set_payload_claim("array", jwt::claim(big_numbers.begin(), big_numbers.end())) diff --git a/example/rsa-create.cpp b/example/rsa-create.cpp index 4ee3f6017..b7fb7a1ec 100644 --- a/example/rsa-create.cpp +++ b/example/rsa-create.cpp @@ -1,6 +1,18 @@ /// @file rsa-create.cpp + +#ifndef JWT_ENABLE_MODULES +#include #include #include +#else +#ifdef JWT_USE_IMPORT_STD +import std; +#else +#include +#include +#endif +import jwt_cpp; +#endif int main() { std::string const rsa_priv_key = R"(-----BEGIN PRIVATE KEY----- diff --git a/example/rsa-verify.cpp b/example/rsa-verify.cpp index c8240b49f..787784630 100644 --- a/example/rsa-verify.cpp +++ b/example/rsa-verify.cpp @@ -1,6 +1,18 @@ /// \file rsa-verify.cpp + +#ifndef JWT_ENABLE_MODULES +#include #include #include +#else +#ifdef JWT_USE_IMPORT_STD +import std; +#else +#include +#include +#endif +import jwt_cpp; +#endif int main() { const std::string rsa_pub_key = R"(-----BEGIN PUBLIC KEY----- diff --git a/example/traits/boost-json.cpp b/example/traits/boost-json.cpp index 6f6399db6..25912b5c7 100644 --- a/example/traits/boost-json.cpp +++ b/example/traits/boost-json.cpp @@ -1,9 +1,9 @@ -#include "jwt-cpp/traits/boost-json/traits.h" - // #include // You may require this if you are not building it elsewhere #include #include +#include "jwt-cpp/traits/boost-json/traits.h" + int main() { using sec = std::chrono::seconds; using min = std::chrono::minutes; diff --git a/example/traits/danielaparker-jsoncons.cpp b/example/traits/danielaparker-jsoncons.cpp index 61043deb0..c3a5dda8f 100644 --- a/example/traits/danielaparker-jsoncons.cpp +++ b/example/traits/danielaparker-jsoncons.cpp @@ -1,8 +1,8 @@ -#include "jwt-cpp/traits/danielaparker-jsoncons/traits.h" - #include #include +#include "jwt-cpp/traits/danielaparker-jsoncons/traits.h" + int main() { using sec = std::chrono::seconds; using min = std::chrono::minutes; diff --git a/example/traits/kazuho-picojson.cpp b/example/traits/kazuho-picojson.cpp index 4bdf4a078..fade710c0 100644 --- a/example/traits/kazuho-picojson.cpp +++ b/example/traits/kazuho-picojson.cpp @@ -1,8 +1,8 @@ -#include "jwt-cpp/traits/kazuho-picojson/traits.h" - #include #include +#include "jwt-cpp/traits/kazuho-picojson/traits.h" + int main() { using sec = std::chrono::seconds; using min = std::chrono::minutes; diff --git a/example/traits/nlohmann-json.cpp b/example/traits/nlohmann-json.cpp index f0bb1d5d7..f4147f115 100644 --- a/example/traits/nlohmann-json.cpp +++ b/example/traits/nlohmann-json.cpp @@ -1,8 +1,8 @@ -#include "jwt-cpp/traits/nlohmann-json/traits.h" - #include #include +#include "jwt-cpp/traits/nlohmann-json/traits.h" + int main() { using sec = std::chrono::seconds; using min = std::chrono::minutes; diff --git a/example/traits/open-source-parsers-jsoncpp.cpp b/example/traits/open-source-parsers-jsoncpp.cpp index 523925c10..eb503efc6 100644 --- a/example/traits/open-source-parsers-jsoncpp.cpp +++ b/example/traits/open-source-parsers-jsoncpp.cpp @@ -1,8 +1,8 @@ -#include "jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h" - #include #include +#include "jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h" + int main() { using sec = std::chrono::seconds; using min = std::chrono::minutes; diff --git a/include/jwt-cpp/base.h b/include/jwt-cpp/base.h index 7258b2e70..80ba58b70 100644 --- a/include/jwt-cpp/base.h +++ b/include/jwt-cpp/base.h @@ -1,12 +1,25 @@ #ifndef JWT_CPP_BASE_H #define JWT_CPP_BASE_H +#ifndef JWT_CPP_EXPORT +#if defined(JWT_CPP_MODULE_INTERFACE_BUILD) +#define JWT_CPP_EXPORT export +#else +#define JWT_CPP_EXPORT +#endif +#endif + +#if !defined(JWT_CPP_MODULE_INTERFACE_BUILD) && defined(JWT_USE_IMPORT_STD) +import std; +#elif !defined(JWT_CPP_MODULE_INTERFACE_BUILD) #include #include +#include #include #include #include #include +#endif #ifdef __has_cpp_attribute #if __has_cpp_attribute(fallthrough) @@ -29,7 +42,7 @@ namespace jwt { * As directed in [X.509 Parameter](https://datatracker.ietf.org/doc/html/rfc7517#section-4.7) certificate chains are * base64-encoded as per [Section 4 of RFC4648](https://datatracker.ietf.org/doc/html/rfc4648#section-4) */ - struct base64 { + JWT_CPP_EXPORT struct base64 { static const std::array& data() { static constexpr std::array data{ {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', @@ -38,8 +51,8 @@ namespace jwt { 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}}; return data; } - static const std::array& rdata() { - static constexpr std::array rdata{{ + static const std::array& rdata() { + static constexpr std::array rdata{{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, @@ -68,7 +81,7 @@ namespace jwt { * > Base64 encoding using the URL- and filename-safe character set defined in * > [Section 5 of RFC 4648 RFC4648](https://tools.ietf.org/html/rfc4648#section-5), with all trailing '=' characters omitted */ - struct base64url { + JWT_CPP_EXPORT struct base64url { static const std::array& data() { static constexpr std::array data{ {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', @@ -77,8 +90,8 @@ namespace jwt { 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'}}; return data; } - static const std::array& rdata() { - static constexpr std::array rdata{{ + static const std::array& rdata() { + static constexpr std::array rdata{{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, @@ -105,7 +118,7 @@ namespace jwt { * * This is useful in situations outside of JWT encoding/decoding and is provided as a helper */ - struct base64url_percent_encoding { + JWT_CPP_EXPORT struct base64url_percent_encoding { static const std::array& data() { static constexpr std::array data{ {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', @@ -114,8 +127,8 @@ namespace jwt { 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'}}; return data; } - static const std::array& rdata() { - static constexpr std::array rdata{{ + static const std::array& rdata() { + static constexpr std::array rdata{{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, @@ -137,10 +150,10 @@ namespace jwt { }; } // namespace helper - inline uint32_t index(const std::array& rdata, char symbol) { + JWT_CPP_EXPORT inline std::uint32_t index(const std::array& rdata, char symbol) { auto index = rdata[static_cast(symbol)]; if (index <= -1) { throw std::runtime_error("Invalid input: not within alphabet"); } - return static_cast(index); + return static_cast(index); } } // namespace alphabet @@ -150,11 +163,11 @@ namespace jwt { namespace base { namespace details { struct padding { - size_t count = 0; - size_t length = 0; + std::size_t count = 0; + std::size_t length = 0; padding() = default; - padding(size_t count, size_t length) : count(count), length(length) {} + padding(std::size_t count, std::size_t length) : count(count), length(length) {} padding operator+(const padding& p) { return padding(count + p.count, length + p.length); } @@ -178,17 +191,17 @@ namespace jwt { inline std::string encode(const std::string& bin, const std::array& alphabet, const std::string& fill) { - size_t size = bin.size(); + std::size_t size = bin.size(); std::string res; // clear incomplete bytes - size_t fast_size = size - size % 3; - for (size_t i = 0; i < fast_size;) { - uint32_t octet_a = static_cast(bin[i++]); - uint32_t octet_b = static_cast(bin[i++]); - uint32_t octet_c = static_cast(bin[i++]); + std::size_t fast_size = size - size % 3; + for (std::size_t i = 0; i < fast_size;) { + std::uint32_t octet_a = static_cast(bin[i++]); + std::uint32_t octet_b = static_cast(bin[i++]); + std::uint32_t octet_c = static_cast(bin[i++]); - uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; + std::uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; res += alphabet[(triple >> 3 * 6) & 0x3F]; res += alphabet[(triple >> 2 * 6) & 0x3F]; @@ -198,13 +211,13 @@ namespace jwt { if (fast_size == size) return res; - size_t mod = size % 3; + std::size_t mod = size % 3; - uint32_t octet_a = fast_size < size ? static_cast(bin[fast_size++]) : 0; - uint32_t octet_b = fast_size < size ? static_cast(bin[fast_size++]) : 0; - uint32_t octet_c = fast_size < size ? static_cast(bin[fast_size++]) : 0; + std::uint32_t octet_a = fast_size < size ? static_cast(bin[fast_size++]) : 0; + std::uint32_t octet_b = fast_size < size ? static_cast(bin[fast_size++]) : 0; + std::uint32_t octet_c = fast_size < size ? static_cast(bin[fast_size++]) : 0; - uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; + std::uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; switch (mod) { case 1: @@ -225,28 +238,28 @@ namespace jwt { return res; } - inline std::string decode(const std::string& base, const std::array& rdata, + inline std::string decode(const std::string& base, const std::array& rdata, const std::vector& fill) { const auto pad = count_padding(base, fill); if (pad.count > 2) throw std::runtime_error("Invalid input: too much fill"); - const size_t size = base.size() - pad.length; + const std::size_t size = base.size() - pad.length; if ((size + pad.count) % 4 != 0) throw std::runtime_error("Invalid input: incorrect total size"); - size_t out_size = size / 4 * 3; + std::size_t out_size = size / 4 * 3; std::string res; res.reserve(out_size); - auto get_sextet = [&](size_t offset) { return alphabet::index(rdata, base[offset]); }; + auto get_sextet = [&](std::size_t offset) { return alphabet::index(rdata, base[offset]); }; - size_t fast_size = size - size % 4; - for (size_t i = 0; i < fast_size;) { - uint32_t sextet_a = get_sextet(i++); - uint32_t sextet_b = get_sextet(i++); - uint32_t sextet_c = get_sextet(i++); - uint32_t sextet_d = get_sextet(i++); + std::size_t fast_size = size - size % 4; + for (std::size_t i = 0; i < fast_size;) { + std::uint32_t sextet_a = get_sextet(i++); + std::uint32_t sextet_b = get_sextet(i++); + std::uint32_t sextet_c = get_sextet(i++); + std::uint32_t sextet_d = get_sextet(i++); - uint32_t triple = + std::uint32_t triple = (sextet_a << 3 * 6) + (sextet_b << 2 * 6) + (sextet_c << 1 * 6) + (sextet_d << 0 * 6); res += static_cast((triple >> 2 * 8) & 0xFFU); @@ -256,7 +269,7 @@ namespace jwt { if (pad.count == 0) return res; - uint32_t triple = (get_sextet(fast_size) << 3 * 6) + (get_sextet(fast_size + 1) << 2 * 6); + std::uint32_t triple = (get_sextet(fast_size) << 3 * 6) + (get_sextet(fast_size + 1) << 2 * 6); switch (pad.count) { case 1: @@ -271,7 +284,7 @@ namespace jwt { return res; } - inline std::string decode(const std::string& base, const std::array& rdata, + inline std::string decode(const std::string& base, const std::array& rdata, const std::string& fill) { return decode(base, rdata, std::vector{fill}); } @@ -304,7 +317,7 @@ namespace jwt { * const auto b64 = jwt::base::encode("example_data") * \endcode */ - template + JWT_CPP_EXPORT template std::string encode(const std::string& bin) { return details::encode(bin, T::data(), T::fill()); } @@ -318,7 +331,7 @@ namespace jwt { * const auto b64 = jwt::base::decode("ZXhhbXBsZV9kYXRh") * \endcode */ - template + JWT_CPP_EXPORT template std::string decode(const std::string& base) { return details::decode(base, T::rdata(), T::fill()); } @@ -332,7 +345,7 @@ namespace jwt { * const auto b64 = jwt::base::pad("ZXhhbXBsZV9kYQ") * \endcode */ - template + JWT_CPP_EXPORT template std::string pad(const std::string& base) { return details::pad(base, T::fill()); } @@ -346,7 +359,7 @@ namespace jwt { * const auto b64 = jwt::base::trim("ZXhhbXBsZV9kYQ==") * \endcode */ - template + JWT_CPP_EXPORT template std::string trim(const std::string& base) { return details::trim(base, T::fill()); } diff --git a/include/jwt-cpp/jwt.h b/include/jwt-cpp/jwt.h index e21020586..e4bbd7ac8 100644 --- a/include/jwt-cpp/jwt.h +++ b/include/jwt-cpp/jwt.h @@ -1,6 +1,30 @@ #ifndef JWT_CPP_JWT_H #define JWT_CPP_JWT_H +#ifndef JWT_CPP_EXPORT +#if defined(JWT_CPP_MODULE_INTERFACE_BUILD) +#define JWT_CPP_EXPORT export +#else +#define JWT_CPP_EXPORT +#endif +#endif + +#if !defined(JWT_CPP_MODULE_INTERFACE_BUILD) || !defined(JWT_USE_IMPORT_STD) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + #ifndef JWT_DISABLE_PICOJSON #ifndef PICOJSON_USE_INT64 #define PICOJSON_USE_INT64 @@ -12,6 +36,7 @@ #include "base.h" #endif +#ifndef JWT_CPP_MODULE_INTERFACE_BUILD #include #include #include @@ -44,10 +69,13 @@ #endif #endif #endif +#endif #if OPENSSL_VERSION_NUMBER >= 0x30000000L // 3.0.0 #define JWT_OPENSSL_3_0 +#ifndef JWT_CPP_MODULE_INTERFACE_BUILD #include +#endif #elif OPENSSL_VERSION_NUMBER >= 0x10101000L // 1.1.1 #define JWT_OPENSSL_1_1_1 #elif OPENSSL_VERSION_NUMBER >= 0x10100000L // 1.1.0 @@ -85,31 +113,31 @@ namespace jwt { /** * Default system time point in UTC */ - using date = std::chrono::system_clock::time_point; + JWT_CPP_EXPORT using date = std::chrono::system_clock::time_point; /** * \brief Everything related to error codes issued by the library */ namespace error { - struct signature_verification_exception : public std::system_error { + JWT_CPP_EXPORT struct signature_verification_exception : public std::system_error { using system_error::system_error; }; - struct signature_generation_exception : public std::system_error { + JWT_CPP_EXPORT struct signature_generation_exception : public std::system_error { using system_error::system_error; }; - struct rsa_exception : public std::system_error { + JWT_CPP_EXPORT struct rsa_exception : public std::system_error { using system_error::system_error; }; - struct ecdsa_exception : public std::system_error { + JWT_CPP_EXPORT struct ecdsa_exception : public std::system_error { using system_error::system_error; }; - struct token_verification_exception : public std::system_error { + JWT_CPP_EXPORT struct token_verification_exception : public std::system_error { using system_error::system_error; }; /** * \brief Errors related to processing of RSA signatures */ - enum class rsa_error { + JWT_CPP_EXPORT enum class rsa_error { ok = 0, cert_load_failed = 10, get_key_failed, @@ -126,7 +154,7 @@ namespace jwt { /** * \brief Error category for RSA errors */ - inline std::error_category& rsa_error_category() { + JWT_CPP_EXPORT inline std::error_category& rsa_error_category() { class rsa_error_cat : public std::error_category { public: const char* name() const noexcept override { return "rsa_error"; }; @@ -154,11 +182,13 @@ namespace jwt { /** * \brief Converts JWT-CPP errors into generic STL error_codes */ - inline std::error_code make_error_code(rsa_error e) { return {static_cast(e), rsa_error_category()}; } + JWT_CPP_EXPORT inline std::error_code make_error_code(rsa_error e) { + return {static_cast(e), rsa_error_category()}; + } /** * \brief Errors related to processing of RSA signatures */ - enum class ecdsa_error { + JWT_CPP_EXPORT enum class ecdsa_error { ok = 0, load_key_bio_write = 10, load_key_bio_read, @@ -178,7 +208,7 @@ namespace jwt { /** * \brief Error category for ECDSA errors */ - inline std::error_category& ecdsa_error_category() { + JWT_CPP_EXPORT inline std::error_category& ecdsa_error_category() { class ecdsa_error_cat : public std::error_category { public: const char* name() const noexcept override { return "ecdsa_error"; }; @@ -210,12 +240,14 @@ namespace jwt { /** * \brief Converts JWT-CPP errors into generic STL error_codes */ - inline std::error_code make_error_code(ecdsa_error e) { return {static_cast(e), ecdsa_error_category()}; } + JWT_CPP_EXPORT inline std::error_code make_error_code(ecdsa_error e) { + return {static_cast(e), ecdsa_error_category()}; + } /** * \brief Errors related to verification of signatures */ - enum class signature_verification_error { + JWT_CPP_EXPORT enum class signature_verification_error { ok = 0, invalid_signature = 10, create_context_failed, @@ -229,7 +261,7 @@ namespace jwt { /** * \brief Error category for verification errors */ - inline std::error_category& signature_verification_error_category() { + JWT_CPP_EXPORT inline std::error_category& signature_verification_error_category() { class verification_error_cat : public std::error_category { public: const char* name() const noexcept override { return "signature_verification_error"; }; @@ -261,14 +293,14 @@ namespace jwt { /** * \brief Converts JWT-CPP errors into generic STL error_codes */ - inline std::error_code make_error_code(signature_verification_error e) { + JWT_CPP_EXPORT inline std::error_code make_error_code(signature_verification_error e) { return {static_cast(e), signature_verification_error_category()}; } /** * \brief Errors related to signature generation errors */ - enum class signature_generation_error { + JWT_CPP_EXPORT enum class signature_generation_error { ok = 0, hmac_failed = 10, create_context_failed, @@ -288,7 +320,7 @@ namespace jwt { /** * \brief Error category for signature generation errors */ - inline std::error_category& signature_generation_error_category() { + JWT_CPP_EXPORT inline std::error_category& signature_generation_error_category() { class signature_generation_error_cat : public std::error_category { public: const char* name() const noexcept override { return "signature_generation_error"; }; @@ -331,14 +363,14 @@ namespace jwt { /** * \brief Converts JWT-CPP errors into generic STL error_codes */ - inline std::error_code make_error_code(signature_generation_error e) { + JWT_CPP_EXPORT inline std::error_code make_error_code(signature_generation_error e) { return {static_cast(e), signature_generation_error_category()}; } /** * \brief Errors related to token verification errors */ - enum class token_verification_error { + JWT_CPP_EXPORT enum class token_verification_error { ok = 0, wrong_algorithm = 10, missing_claim, @@ -350,7 +382,7 @@ namespace jwt { /** * \brief Error category for token verification errors */ - inline std::error_category& token_verification_error_category() { + JWT_CPP_EXPORT inline std::error_category& token_verification_error_category() { class token_verification_error_cat : public std::error_category { public: const char* name() const noexcept override { return "token_verification_error"; }; @@ -376,13 +408,13 @@ namespace jwt { /** * \brief Converts JWT-CPP errors into generic STL error_codes */ - inline std::error_code make_error_code(token_verification_error e) { + JWT_CPP_EXPORT inline std::error_code make_error_code(token_verification_error e) { return {static_cast(e), token_verification_error_category()}; } /** * \brief Raises an exception if any JWT-CPP error codes are active */ - inline void throw_if_error(std::error_code ec) { + JWT_CPP_EXPORT inline void throw_if_error(std::error_code ec) { if (ec) { if (ec.category() == rsa_error_category()) throw rsa_exception(ec); if (ec.category() == ecdsa_error_category()) throw ecdsa_exception(ec); @@ -396,15 +428,15 @@ namespace jwt { } // namespace jwt namespace std { - template<> + JWT_CPP_EXPORT template<> struct is_error_code_enum : true_type {}; - template<> + JWT_CPP_EXPORT template<> struct is_error_code_enum : true_type {}; - template<> + JWT_CPP_EXPORT template<> struct is_error_code_enum : true_type {}; - template<> + JWT_CPP_EXPORT template<> struct is_error_code_enum : true_type {}; - template<> + JWT_CPP_EXPORT template<> struct is_error_code_enum : true_type {}; } // namespace std @@ -424,7 +456,7 @@ namespace jwt { * jwt-cpp to leverage that and thus safe an allocation for the control block in std::shared_ptr. * The handle uses shared_ptr as a fallback on older versions. The behaviour should be identical between both. */ - class evp_pkey_handle { + JWT_CPP_EXPORT class evp_pkey_handle { public: /** * \brief Creates a null key pointer. @@ -498,11 +530,11 @@ namespace jwt { #endif }; - inline std::unique_ptr make_mem_buf_bio() { + JWT_CPP_EXPORT inline std::unique_ptr make_mem_buf_bio() { return std::unique_ptr(BIO_new(BIO_s_mem()), BIO_free_all); } - inline std::unique_ptr make_mem_buf_bio(const std::string& data) { + JWT_CPP_EXPORT inline std::unique_ptr make_mem_buf_bio(const std::string& data) { return std::unique_ptr( #if OPENSSL_VERSION_NUMBER <= 0x10100003L BIO_new_mem_buf(const_cast(data.data()), static_cast(data.size())), BIO_free_all @@ -512,7 +544,7 @@ namespace jwt { ); } - template + JWT_CPP_EXPORT template std::string write_bio_to_string(std::unique_ptr& bio_out, std::error_code& ec) { char* ptr = nullptr; auto len = BIO_get_mem_data(bio_out.get(), &ptr); @@ -523,7 +555,7 @@ namespace jwt { return {ptr, static_cast(len)}; } - inline std::unique_ptr make_evp_md_ctx() { + JWT_CPP_EXPORT inline std::unique_ptr make_evp_md_ctx() { return #ifdef JWT_OPENSSL_1_0_0 std::unique_ptr(EVP_MD_CTX_create(), &EVP_MD_CTX_destroy); @@ -540,7 +572,7 @@ namespace jwt { * \param pw Password used to decrypt certificate (leave empty if not encrypted) * \param ec error_code for error_detection (gets cleared if no error occurred) */ - template + JWT_CPP_EXPORT template std::string extract_pubkey_from_cert(const std::string& certstr, const std::string& pw, std::error_code& ec) { ec.clear(); auto certbio = make_mem_buf_bio(certstr); @@ -577,7 +609,7 @@ namespace jwt { * \param pw Password used to decrypt certificate (leave empty if not encrypted) * \throw templated error_category's type exception if an error occurred */ - template + JWT_CPP_EXPORT template std::string extract_pubkey_from_cert(const std::string& certstr, const std::string& pw = "") { std::error_code ec; auto res = extract_pubkey_from_cert(certstr, pw, ec); @@ -591,7 +623,7 @@ namespace jwt { * \param cert_der_str String containing the certificate encoded as base64 DER * \param ec error_code for error_detection (gets cleared if no error occurs) */ - inline std::string convert_der_to_pem(const std::string& cert_der_str, std::error_code& ec) { + JWT_CPP_EXPORT inline std::string convert_der_to_pem(const std::string& cert_der_str, std::error_code& ec) { ec.clear(); auto c_str = reinterpret_cast(cert_der_str.c_str()); @@ -626,7 +658,7 @@ namespace jwt { * \param decode The function to decode the cert * \param ec error_code for error_detection (gets cleared if no error occurs) */ - template + JWT_CPP_EXPORT template std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str, Decode decode, std::error_code& ec) { ec.clear(); @@ -648,7 +680,7 @@ namespace jwt { * \param decode The function to decode the cert * \throw rsa_exception if an error occurred */ - template + JWT_CPP_EXPORT template std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str, Decode decode) { std::error_code ec; auto res = convert_base64_der_to_pem(cert_base64_der_str, std::move(decode), ec); @@ -662,7 +694,7 @@ namespace jwt { * \param cert_der_str String containing the DER certificate * \throw rsa_exception if an error occurred */ - inline std::string convert_der_to_pem(const std::string& cert_der_str) { + JWT_CPP_EXPORT inline std::string convert_der_to_pem(const std::string& cert_der_str) { std::error_code ec; auto res = convert_der_to_pem(cert_der_str, ec); error::throw_if_error(ec); @@ -679,7 +711,8 @@ namespace jwt { * \param cert_base64_der_str String containing the certificate encoded as base64 DER * \param ec error_code for error_detection (gets cleared if no error occurs) */ - inline std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str, std::error_code& ec) { + JWT_CPP_EXPORT inline std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str, + std::error_code& ec) { auto decode = [](const std::string& token) { return base::decode(base::pad(token)); }; @@ -695,7 +728,7 @@ namespace jwt { * \param cert_base64_der_str String containing the certificate encoded as base64 DER * \throw rsa_exception if an error occurred */ - inline std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str) { + JWT_CPP_EXPORT inline std::string convert_base64_der_to_pem(const std::string& cert_base64_der_str) { std::error_code ec; auto res = convert_base64_der_to_pem(cert_base64_der_str, ec); error::throw_if_error(ec); @@ -712,7 +745,7 @@ namespace jwt { * \param password Password used to decrypt certificate (leave empty if not encrypted) * \param ec error_code for error_detection (gets cleared if no error occurs) */ - template + JWT_CPP_EXPORT template evp_pkey_handle load_public_key_from_string(const std::string& key, const std::string& password, std::error_code& ec) { ec.clear(); @@ -764,7 +797,7 @@ namespace jwt { * \param password Password used to decrypt certificate (leave empty if not encrypted) * \throw Templated error_category's type exception if an error occurred */ - template + JWT_CPP_EXPORT template inline evp_pkey_handle load_public_key_from_string(const std::string& key, const std::string& password = "") { std::error_code ec; auto res = load_public_key_from_string(key, password, ec); @@ -780,7 +813,7 @@ namespace jwt { * \param password Password used to decrypt key (leave empty if not encrypted) * \param ec error_code for error_detection (gets cleared if no error occurs) */ - template + JWT_CPP_EXPORT template inline evp_pkey_handle load_private_key_from_string(const std::string& key, const std::string& password, std::error_code& ec) { ec.clear(); @@ -808,7 +841,7 @@ namespace jwt { * \param password Password used to decrypt key (leave empty if not encrypted) * \throw Templated error_category's type exception if an error occurred */ - template + JWT_CPP_EXPORT template inline evp_pkey_handle load_private_key_from_string(const std::string& key, const std::string& password = "") { std::error_code ec; auto res = load_private_key_from_string(key, password, ec); @@ -827,8 +860,9 @@ namespace jwt { * \param password Password used to decrypt certificate (leave empty if not encrypted) * \param ec error_code for error_detection (gets cleared if no error occurs) */ - inline evp_pkey_handle load_public_ec_key_from_string(const std::string& key, const std::string& password, - std::error_code& ec) { + JWT_CPP_EXPORT inline evp_pkey_handle load_public_ec_key_from_string(const std::string& key, + const std::string& password, + std::error_code& ec) { return load_public_key_from_string(key, password, ec); } @@ -856,7 +890,8 @@ namespace jwt { * \param ec error_code for error_detection (gets cleared if no error occurs) * \return BIGNUM representation */ - inline std::unique_ptr raw2bn(const std::string& raw, std::error_code& ec) { + JWT_CPP_EXPORT inline std::unique_ptr raw2bn(const std::string& raw, + std::error_code& ec) { auto bn = BN_bin2bn(reinterpret_cast(raw.data()), static_cast(raw.size()), nullptr); // https://www.openssl.org/docs/man1.1.1/man3/BN_bin2bn.html#RETURN-VALUES @@ -871,7 +906,7 @@ namespace jwt { * \param raw String to convert * \return BIGNUM representation */ - inline std::unique_ptr raw2bn(const std::string& raw) { + JWT_CPP_EXPORT inline std::unique_ptr raw2bn(const std::string& raw) { std::error_code ec; auto res = raw2bn(raw, ec); error::throw_if_error(ec); @@ -889,8 +924,8 @@ namespace jwt { * \param password Password used to decrypt certificate or key (leave empty if not encrypted) * \throw ecdsa_exception if an error occurred */ - inline evp_pkey_handle load_public_ec_key_from_string(const std::string& key, - const std::string& password = "") { + JWT_CPP_EXPORT inline evp_pkey_handle load_public_ec_key_from_string(const std::string& key, + const std::string& password = "") { std::error_code ec; auto res = load_public_key_from_string(key, password, ec); error::throw_if_error(ec); @@ -906,8 +941,9 @@ namespace jwt { * \param password Password used to decrypt key (leave empty if not encrypted) * \param ec error_code for error_detection (gets cleared if no error occurs) */ - inline evp_pkey_handle load_private_ec_key_from_string(const std::string& key, const std::string& password, - std::error_code& ec) { + JWT_CPP_EXPORT inline evp_pkey_handle load_private_ec_key_from_string(const std::string& key, + const std::string& password, + std::error_code& ec) { return load_private_key_from_string(key, password, ec); } @@ -925,7 +961,7 @@ namespace jwt { * \param ec error_code for error_detection (gets cleared if no error occur * \return public key in PEM format */ - template + JWT_CPP_EXPORT template std::string create_public_key_from_rsa_components(const std::string& modulus, const std::string& exponent, Decode decode, std::error_code& ec) { ec.clear(); @@ -1041,7 +1077,7 @@ namespace jwt { * \param decode The function to decode the RSA parameters * \return public key in PEM format */ - template + JWT_CPP_EXPORT template std::string create_public_key_from_rsa_components(const std::string& modulus, const std::string& exponent, Decode decode) { std::error_code ec; @@ -1061,8 +1097,9 @@ namespace jwt { * \param ec error_code for error_detection (gets cleared if no error occur * \return public key in PEM format */ - inline std::string create_public_key_from_rsa_components(const std::string& modulus, - const std::string& exponent, std::error_code& ec) { + JWT_CPP_EXPORT inline std::string create_public_key_from_rsa_components(const std::string& modulus, + const std::string& exponent, + std::error_code& ec) { auto decode = [](const std::string& token) { return base::decode(base::pad(token)); }; @@ -1077,8 +1114,8 @@ namespace jwt { * \param exponent string containing base64url encoded exponent * \return public key in PEM format */ - inline std::string create_public_key_from_rsa_components(const std::string& modulus, - const std::string& exponent) { + JWT_CPP_EXPORT inline std::string create_public_key_from_rsa_components(const std::string& modulus, + const std::string& exponent) { std::error_code ec; auto res = create_public_key_from_rsa_components(modulus, exponent, ec); error::throw_if_error(ec); @@ -1094,8 +1131,8 @@ namespace jwt { * \param password Password used to decrypt key (leave empty if not encrypted) * \throw ecdsa_exception if an error occurred */ - inline evp_pkey_handle load_private_ec_key_from_string(const std::string& key, - const std::string& password = "") { + JWT_CPP_EXPORT inline evp_pkey_handle load_private_ec_key_from_string(const std::string& key, + const std::string& password = "") { std::error_code ec; auto res = load_private_key_from_string(key, password, ec); error::throw_if_error(ec); @@ -1111,7 +1148,7 @@ namespace jwt { * \param ec error_code for error_detection * \return group name */ - inline std::string curve2group(const std::string curve, std::error_code& ec) { + JWT_CPP_EXPORT inline std::string curve2group(const std::string curve, std::error_code& ec) { if (curve == "P-256") { return "prime256v1"; } else if (curve == "P-384") { @@ -1133,7 +1170,7 @@ namespace jwt { * \param ec error_code for error_detection * \return ID */ - inline int curve2nid(const std::string curve, std::error_code& ec) { + JWT_CPP_EXPORT inline int curve2nid(const std::string curve, std::error_code& ec) { if (curve == "P-256") { return NID_X9_62_prime256v1; } else if (curve == "P-384") { @@ -1163,7 +1200,7 @@ namespace jwt { * \param ec error_code for error_detection (gets cleared if no error occur * \return public key in PEM format */ - template + JWT_CPP_EXPORT template std::string create_public_key_from_ec_components(const std::string& curve, const std::string& x, const std::string& y, Decode decode, std::error_code& ec) { ec.clear(); @@ -1291,7 +1328,7 @@ namespace jwt { * \param decode The function to decode the RSA parameters * \return public key in PEM format */ - template + JWT_CPP_EXPORT template std::string create_public_key_from_ec_components(const std::string& curve, const std::string& x, const std::string& y, Decode decode) { std::error_code ec; @@ -1312,8 +1349,10 @@ namespace jwt { * \param ec error_code for error_detection (gets cleared if no error occur * \return public key in PEM format */ - inline std::string create_public_key_from_ec_components(const std::string& curve, const std::string& x, - const std::string& y, std::error_code& ec) { + JWT_CPP_EXPORT inline std::string create_public_key_from_ec_components(const std::string& curve, + const std::string& x, + const std::string& y, + std::error_code& ec) { auto decode = [](const std::string& token) { return base::decode(base::pad(token)); }; @@ -1329,8 +1368,9 @@ namespace jwt { * \param y string containing base64url encoded y coordinate * \return public key in PEM format */ - inline std::string create_public_key_from_ec_components(const std::string& curve, const std::string& x, - const std::string& y) { + JWT_CPP_EXPORT inline std::string create_public_key_from_ec_components(const std::string& curve, + const std::string& x, + const std::string& y) { std::error_code ec; auto res = create_public_key_from_ec_components(curve, x, y, ec); error::throw_if_error(ec); @@ -1356,7 +1396,7 @@ namespace jwt { * See [RFC 7518 Section 3.6](https://datatracker.ietf.org/doc/html/rfc7518#section-3.6) * for more information. */ - struct none { + JWT_CPP_EXPORT struct none { /** * \brief Return an empty string */ @@ -1381,7 +1421,7 @@ namespace jwt { /** * \brief Base class for HMAC family of algorithms */ - struct hmacsha { + JWT_CPP_EXPORT struct hmacsha { /** * Construct new hmac algorithm * @@ -1451,7 +1491,7 @@ namespace jwt { /** * \brief Base class for RSA family of algorithms */ - struct rsa { + JWT_CPP_EXPORT struct rsa { /** * Construct new rsa algorithm * @@ -1562,7 +1602,7 @@ namespace jwt { /** * \brief Base class for ECDSA family of algorithms */ - struct ecdsa { + JWT_CPP_EXPORT struct ecdsa { /** * Construct new ecdsa algorithm * @@ -1810,7 +1850,7 @@ namespace jwt { * so these algorithms are only available when building against this version or higher. * LibreSSL added EdDSA (Ed25519) functionality in [LibreSSL 3.7.1](https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.7.1-relnotes.txt) */ - struct eddsa { + JWT_CPP_EXPORT struct eddsa { /** * Construct new eddsa algorithm * \param public_key EdDSA public key in PEM format @@ -1934,7 +1974,7 @@ namespace jwt { /** * \brief Base class for PSS-RSA family of algorithms */ - struct pss { + JWT_CPP_EXPORT struct pss { /** * Construct new pss algorithm * \param public_key RSA public key in PEM format @@ -2062,7 +2102,7 @@ namespace jwt { /** * HS256 algorithm */ - struct hs256 : public hmacsha { + JWT_CPP_EXPORT struct hs256 : public hmacsha { /** * Construct new instance of algorithm * \param key HMAC signing key @@ -2072,7 +2112,7 @@ namespace jwt { /** * HS384 algorithm */ - struct hs384 : public hmacsha { + JWT_CPP_EXPORT struct hs384 : public hmacsha { /** * Construct new instance of algorithm * \param key HMAC signing key @@ -2082,7 +2122,7 @@ namespace jwt { /** * HS512 algorithm */ - struct hs512 : public hmacsha { + JWT_CPP_EXPORT struct hs512 : public hmacsha { /** * Construct new instance of algorithm * \param key HMAC signing key @@ -2094,7 +2134,7 @@ namespace jwt { * * This data structure is used to describe the RSA256 and can be used to verify JWTs */ - struct rs256 : public rsa { + JWT_CPP_EXPORT struct rs256 : public rsa { /** * \brief Construct new instance of algorithm * @@ -2110,7 +2150,7 @@ namespace jwt { /** * RS384 algorithm */ - struct rs384 : public rsa { + JWT_CPP_EXPORT struct rs384 : public rsa { /** * Construct new instance of algorithm * \param public_key RSA public key in PEM format @@ -2125,7 +2165,7 @@ namespace jwt { /** * RS512 algorithm */ - struct rs512 : public rsa { + JWT_CPP_EXPORT struct rs512 : public rsa { /** * Construct new instance of algorithm * \param public_key RSA public key in PEM format @@ -2140,7 +2180,7 @@ namespace jwt { /** * ES256 algorithm */ - struct es256 : public ecdsa { + JWT_CPP_EXPORT struct es256 : public ecdsa { /** * Construct new instance of algorithm * \param public_key ECDSA public key in PEM format @@ -2157,7 +2197,7 @@ namespace jwt { /** * ES384 algorithm */ - struct es384 : public ecdsa { + JWT_CPP_EXPORT struct es384 : public ecdsa { /** * Construct new instance of algorithm * \param public_key ECDSA public key in PEM format @@ -2174,7 +2214,7 @@ namespace jwt { /** * ES512 algorithm */ - struct es512 : public ecdsa { + JWT_CPP_EXPORT struct es512 : public ecdsa { /** * Construct new instance of algorithm * \param public_key ECDSA public key in PEM format @@ -2191,7 +2231,7 @@ namespace jwt { /** * ES256K algorithm */ - struct es256k : public ecdsa { + JWT_CPP_EXPORT struct es256k : public ecdsa { /** * Construct new instance of algorithm * \param public_key ECDSA public key in PEM format @@ -2213,7 +2253,7 @@ namespace jwt { * * Requires at least OpenSSL 1.1.1 or LibreSSL 3.7.1. */ - struct ed25519 : public eddsa { + JWT_CPP_EXPORT struct ed25519 : public eddsa { /** * Construct new instance of algorithm * \param public_key Ed25519 public key in PEM format @@ -2236,7 +2276,7 @@ namespace jwt { * * Requires at least OpenSSL 1.1.1. Note: Not supported by LibreSSL. */ - struct ed448 : public eddsa { + JWT_CPP_EXPORT struct ed448 : public eddsa { /** * Construct new instance of algorithm * \param public_key Ed448 public key in PEM format @@ -2256,7 +2296,7 @@ namespace jwt { /** * PS256 algorithm */ - struct ps256 : public pss { + JWT_CPP_EXPORT struct ps256 : public pss { /** * Construct new instance of algorithm * \param public_key RSA public key in PEM format @@ -2271,7 +2311,7 @@ namespace jwt { /** * PS384 algorithm */ - struct ps384 : public pss { + JWT_CPP_EXPORT struct ps384 : public pss { /** * Construct new instance of algorithm * \param public_key RSA public key in PEM format @@ -2286,7 +2326,7 @@ namespace jwt { /** * PS512 algorithm */ - struct ps512 : public pss { + JWT_CPP_EXPORT struct ps512 : public pss { /** * Construct new instance of algorithm * \param public_key RSA public key in PEM format @@ -2311,7 +2351,7 @@ namespace jwt { * to identify the different structures and reason about them without needing a "concept" * to capture that defintion to compare against a concrete type. */ - enum class type { boolean, integer, number, string, array, object }; + JWT_CPP_EXPORT enum class type { boolean, integer, number, string, array, object }; } // namespace json namespace details { @@ -2593,7 +2633,7 @@ namespace jwt { * * \see [RFC 7519: JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519) */ - template + JWT_CPP_EXPORT template class basic_claim { /** * The reason behind this is to provide an expressive abstraction without @@ -2737,13 +2777,13 @@ namespace jwt { /** * Attempt to parse JSON was unsuccessful */ - struct invalid_json_exception : public std::runtime_error { + JWT_CPP_EXPORT struct invalid_json_exception : public std::runtime_error { invalid_json_exception() : runtime_error("invalid json") {} }; /** * Attempt to access claim was unsuccessful */ - struct claim_not_present_exception : public std::out_of_range { + JWT_CPP_EXPORT struct claim_not_present_exception : public std::out_of_range { claim_not_present_exception() : out_of_range("claim not found") {} }; } // namespace error @@ -2812,7 +2852,7 @@ namespace jwt { * Base class that represents a token payload. * Contains Convenience accessors for common claims. */ - template + JWT_CPP_EXPORT template class payload { protected: details::map_of_claims payload_claims; @@ -2930,7 +2970,7 @@ namespace jwt { * Base class that represents a token header. * Contains Convenience accessors for common claims. */ - template + JWT_CPP_EXPORT template class header { protected: details::map_of_claims header_claims; @@ -3005,7 +3045,7 @@ namespace jwt { /** * Class containing all information about a decoded token */ - template + JWT_CPP_EXPORT template class decoded_jwt : public header, public payload { protected: /// Unmodified token, as passed to constructor @@ -3140,7 +3180,7 @@ namespace jwt { * Builder class to build and sign a new token * Use jwt::create() to get an instance of this class. */ - template + JWT_CPP_EXPORT template class builder { typename json_traits::object_type header_claims; typename json_traits::object_type payload_claims; @@ -3392,7 +3432,7 @@ namespace jwt { /** * This is the base container which holds the token that need to be verified */ - template + JWT_CPP_EXPORT template struct verify_context { verify_context(date ctime, const decoded_jwt& j, size_t l) : current_time(ctime), jwt(j), default_leeway(l) {} @@ -3463,7 +3503,7 @@ namespace jwt { /** * This is the default operation and does case sensitive matching */ - template + JWT_CPP_EXPORT template struct equals_claim { const basic_claim expected; void operator()(const verify_context& ctx, std::error_code& ec) const { @@ -3492,7 +3532,7 @@ namespace jwt { * Checks that the current time is before the time specified in the given * claim. This is identical to how the "exp" check works. */ - template + JWT_CPP_EXPORT template struct date_before_claim { const size_t leeway; void operator()(const verify_context& ctx, std::error_code& ec) const { @@ -3509,7 +3549,7 @@ namespace jwt { * Checks that the current time is after the time specified in the given * claim. This is identical to how the "nbf" and "iat" check works. */ - template + JWT_CPP_EXPORT template struct date_after_claim { const size_t leeway; void operator()(const verify_context& ctx, std::error_code& ec) const { @@ -3527,7 +3567,7 @@ namespace jwt { * If the token value is a string it is treated as a set with a single element. * The comparison is case sensitive. */ - template + JWT_CPP_EXPORT template struct is_subset_claim { const typename basic_claim::set_t expected; void operator()(const verify_context& ctx, std::error_code& ec) const { @@ -3556,7 +3596,7 @@ namespace jwt { /** * Checks if the claim is a string and does an case insensitive comparison. */ - template + JWT_CPP_EXPORT template struct insensitive_string_claim { const typename json_traits::string_type expected; std::locale locale; @@ -3611,7 +3651,7 @@ namespace jwt { * Verifier class used to check if a decoded token contains all claims required by your application and has a valid * signature. */ - template + JWT_CPP_EXPORT template class verifier { public: using basic_claim_t = basic_claim; @@ -3874,7 +3914,7 @@ namespace jwt { * A JSON object that represents a cryptographic key. The members of * the object represent properties of the key, including its value. */ - template + JWT_CPP_EXPORT template class jwk { using basic_claim_t = basic_claim; const details::map_of_claims jwk_claims; @@ -4085,7 +4125,7 @@ namespace jwt { * * This container takes a JWKs and simplifies it to a vector of JWKs */ - template + JWT_CPP_EXPORT template class jwks { public: /// JWK instance template specialization @@ -4160,7 +4200,7 @@ namespace jwt { * \param c Clock instance to use * \return verifier instance */ - template + JWT_CPP_EXPORT template verifier verify(Clock c) { return verifier(c); } @@ -4170,7 +4210,7 @@ namespace jwt { * \param c Clock instance to use * \return builder instance */ - template + JWT_CPP_EXPORT template builder create(Clock c) { return builder(c); } @@ -4178,7 +4218,7 @@ namespace jwt { /** * Default clock class using std::chrono::system_clock as a backend. */ - struct default_clock { + JWT_CPP_EXPORT struct default_clock { /** * Gets the current system time * \return time_point of the host system @@ -4194,7 +4234,7 @@ namespace jwt { * \param c Clock instance to use * \return verifier instance */ - template + JWT_CPP_EXPORT template verifier verify(default_clock c = {}) { return verifier(c); } @@ -4202,7 +4242,7 @@ namespace jwt { /** * Return a builder instance to create a new token */ - template + JWT_CPP_EXPORT template builder create(default_clock c = {}) { return builder(c); } @@ -4221,7 +4261,7 @@ namespace jwt { * \throw std::invalid_argument Token is not in correct format * \throw std::runtime_error Base64 decoding failed or invalid json */ - template + JWT_CPP_EXPORT template decoded_jwt decode(const typename json_traits::string_type& token, Decode decode) { return decoded_jwt(token, decode); } @@ -4236,7 +4276,7 @@ namespace jwt { * \throw std::invalid_argument Token is not in correct format * \throw std::runtime_error Base64 decoding failed or invalid json */ - template + JWT_CPP_EXPORT template decoded_jwt decode(const typename json_traits::string_type& token) { return decoded_jwt(token); } @@ -4246,7 +4286,7 @@ namespace jwt { * \param jwk_ string buffer containing the JSON object * \return Decoded jwk */ - template + JWT_CPP_EXPORT template jwk parse_jwk(const typename json_traits::string_type& jwk_) { return jwk(jwk_); } @@ -4260,18 +4300,18 @@ namespace jwt { * \return Parsed JSON object containing the data of the JWK SET string * \throw std::runtime_error Token is not in correct format */ - template + JWT_CPP_EXPORT template jwks parse_jwks(const typename json_traits::string_type& jwks_) { return jwks(jwks_); } } // namespace jwt -template +JWT_CPP_EXPORT template std::istream& operator>>(std::istream& is, jwt::basic_claim& c) { return c.operator>>(is); } -template +JWT_CPP_EXPORT template std::ostream& operator<<(std::ostream& os, const jwt::basic_claim& c) { return os << c.to_json(); } diff --git a/include/jwt-cpp/traits/boost-json/traits.h b/include/jwt-cpp/traits/boost-json/traits.h index a421bfd09..a3c6989f1 100644 --- a/include/jwt-cpp/traits/boost-json/traits.h +++ b/include/jwt-cpp/traits/boost-json/traits.h @@ -2,7 +2,11 @@ #define JWT_CPP_BOOSTJSON_TRAITS_H #define JWT_DISABLE_PICOJSON +#if defined(JWT_ENABLE_MODULES) && !defined(JWT_USE_IMPORT_STD) +import jwt_cpp; +#else #include "jwt-cpp/jwt.h" +#endif #include // if not boost JSON standalone then error... diff --git a/include/jwt-cpp/traits/danielaparker-jsoncons/traits.h b/include/jwt-cpp/traits/danielaparker-jsoncons/traits.h index bb00d5418..b133e4552 100644 --- a/include/jwt-cpp/traits/danielaparker-jsoncons/traits.h +++ b/include/jwt-cpp/traits/danielaparker-jsoncons/traits.h @@ -5,7 +5,11 @@ #define JSONCONS_NO_DEPRECATED #include "jsoncons/json.hpp" +#if defined(JWT_ENABLE_MODULES) && !defined(JWT_USE_IMPORT_STD) +import jwt_cpp; +#else #include "jwt-cpp/jwt.h" +#endif #include #include diff --git a/include/jwt-cpp/traits/kazuho-picojson/defaults.h b/include/jwt-cpp/traits/kazuho-picojson/defaults.h index eae9789ae..b4de2f4e8 100644 --- a/include/jwt-cpp/traits/kazuho-picojson/defaults.h +++ b/include/jwt-cpp/traits/kazuho-picojson/defaults.h @@ -1,6 +1,14 @@ #ifndef JWT_CPP_KAZUHO_PICOJSON_DEFAULTS_H #define JWT_CPP_KAZUHO_PICOJSON_DEFAULTS_H +#ifndef JWT_CPP_EXPORT +#if defined(JWT_CPP_MODULE_INTERFACE_BUILD) +#define JWT_CPP_EXPORT export +#else +#define JWT_CPP_EXPORT +#endif +#endif + #include "traits.h" namespace jwt { @@ -10,13 +18,13 @@ namespace jwt { * This type is the specialization of the \ref basic_claim class which * uses the standard template types. */ - using claim = basic_claim; + JWT_CPP_EXPORT using claim = basic_claim; /** * Create a verifier using the default clock * \return verifier instance */ - inline verifier verify() { + JWT_CPP_EXPORT inline verifier verify() { return verify(default_clock{}); } @@ -24,7 +32,7 @@ namespace jwt { * Create a builder using the default clock * \return builder instance to create a new token */ - inline builder create() { + JWT_CPP_EXPORT inline builder create() { return builder(default_clock{}); } @@ -36,7 +44,7 @@ namespace jwt { * \throw std::invalid_argument Token is not in correct format * \throw std::runtime_error Base64 decoding failed or invalid json */ - inline decoded_jwt decode(const std::string& token) { + JWT_CPP_EXPORT inline decoded_jwt decode(const std::string& token) { return decoded_jwt(token); } #endif @@ -52,7 +60,7 @@ namespace jwt { * \throw std::invalid_argument Token is not in correct format * \throw std::runtime_error Base64 decoding failed or invalid json */ - template + JWT_CPP_EXPORT template decoded_jwt decode(const std::string& token, Decode decode) { return decoded_jwt(token, decode); } @@ -63,7 +71,7 @@ namespace jwt { * \return Parsed JWK * \throw std::runtime_error Token is not in correct format */ - inline jwk parse_jwk(const traits::kazuho_picojson::string_type& token) { + JWT_CPP_EXPORT inline jwk parse_jwk(const traits::kazuho_picojson::string_type& token) { return jwk(token); } @@ -73,7 +81,7 @@ namespace jwt { * \return Parsed JWKs * \throw std::runtime_error Token is not in correct format */ - inline jwks parse_jwks(const traits::kazuho_picojson::string_type& token) { + JWT_CPP_EXPORT inline jwks parse_jwks(const traits::kazuho_picojson::string_type& token) { return jwks(token); } @@ -81,7 +89,7 @@ namespace jwt { * This type is the specialization of the \ref verify_ops::verify_context class which * uses the standard template types. */ - using verify_context = verify_ops::verify_context; + JWT_CPP_EXPORT using verify_context = verify_ops::verify_context; } // namespace jwt #endif // JWT_CPP_KAZUHO_PICOJSON_DEFAULTS_H diff --git a/include/jwt-cpp/traits/kazuho-picojson/traits.h b/include/jwt-cpp/traits/kazuho-picojson/traits.h index 27a11df4d..22cf32dad 100644 --- a/include/jwt-cpp/traits/kazuho-picojson/traits.h +++ b/include/jwt-cpp/traits/kazuho-picojson/traits.h @@ -1,6 +1,14 @@ #ifndef JWT_CPP_PICOJSON_TRAITS_H #define JWT_CPP_PICOJSON_TRAITS_H +#ifndef JWT_CPP_EXPORT +#if defined(JWT_CPP_MODULE_INTERFACE_BUILD) +#define JWT_CPP_EXPORT export +#else +#define JWT_CPP_EXPORT +#endif +#endif + #ifndef PICOJSON_USE_INT64 #define PICOJSON_USE_INT64 #endif @@ -9,7 +17,11 @@ #ifndef JWT_DISABLE_PICOJSON #define JWT_DISABLE_PICOJSON #endif +#if defined(JWT_ENABLE_MODULES) && !defined(JWT_USE_IMPORT_STD) +import jwt_cpp; +#else #include "jwt-cpp/jwt.h" +#endif namespace jwt { /** @@ -17,7 +29,7 @@ namespace jwt { */ namespace traits { /// basic_claim's JSON trait implementation for picojson - struct kazuho_picojson { + JWT_CPP_EXPORT struct kazuho_picojson { using value_type = picojson::value; using object_type = picojson::object; using array_type = picojson::array; diff --git a/include/jwt-cpp/traits/nlohmann-json/traits.h b/include/jwt-cpp/traits/nlohmann-json/traits.h index 272f3d331..50485aab7 100644 --- a/include/jwt-cpp/traits/nlohmann-json/traits.h +++ b/include/jwt-cpp/traits/nlohmann-json/traits.h @@ -1,7 +1,11 @@ #ifndef JWT_CPP_NLOHMANN_JSON_TRAITS_H #define JWT_CPP_NLOHMANN_JSON_TRAITS_H -#include "jwt-cpp/jwt.h" +#if defined(JWT_ENABLE_MODULES) && !defined(JWT_USE_IMPORT_STD) +import jwt_cpp; +#else +#include +#endif #include "nlohmann/json.hpp" namespace jwt { diff --git a/include/jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h b/include/jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h index 52e14ae3c..63e54ce8d 100644 --- a/include/jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h +++ b/include/jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h @@ -1,7 +1,11 @@ #ifndef JWT_CPP_JSONCPP_TRAITS_H #define JWT_CPP_JSONCPP_TRAITS_H +#if defined(JWT_ENABLE_MODULES) && !defined(JWT_USE_IMPORT_STD) +import jwt_cpp; +#else #include "jwt-cpp/jwt.h" +#endif #include "json/json.h" #include diff --git a/include/picojson/picojson.h b/include/picojson/picojson.h index 76742fe06..ddea5aad9 100644 --- a/include/picojson/picojson.h +++ b/include/picojson/picojson.h @@ -28,6 +28,19 @@ #ifndef picojson_h #define picojson_h +#ifdef JWT_CPP_EXPORT +#define PICOJSON_JWT_CPP_EXPORT JWT_CPP_EXPORT +#else +#define PICOJSON_JWT_CPP_EXPORT +#endif + +#if defined(JWT_CPP_MODULE_INTERFACE_BUILD) && defined(JWT_USE_IMPORT_STD) +#define PICOJSON_USE_IMPORTED_STD 1 +#else +#define PICOJSON_USE_IMPORTED_STD 0 +#endif + +#if !PICOJSON_USE_IMPORTED_STD #include #include #include @@ -41,10 +54,13 @@ #include #include #include +#endif // for isnan/isinf #if __cplusplus >= 201103L +#if !PICOJSON_USE_IMPORTED_STD #include +#endif #else extern "C" { #ifdef _MSC_VER @@ -76,6 +92,7 @@ extern "C" { // experimental support for int64_t (see README.mkdn for detail) #ifdef PICOJSON_USE_INT64 #define __STDC_FORMAT_MACROS +#if !PICOJSON_USE_IMPORTED_STD #include #if __cplusplus >= 201103L #include @@ -85,12 +102,13 @@ extern "C" { } #endif #endif +#endif // to disable the use of localeconv(3), set PICOJSON_USE_LOCALE to 0 #ifndef PICOJSON_USE_LOCALE #define PICOJSON_USE_LOCALE 1 #endif -#if PICOJSON_USE_LOCALE +#if PICOJSON_USE_LOCALE && !PICOJSON_USE_IMPORTED_STD extern "C" { #include } @@ -132,9 +150,9 @@ enum { enum { INDENT_WIDTH = 2, DEFAULT_MAX_DEPTHS = 100 }; -struct null {}; +PICOJSON_JWT_CPP_EXPORT struct null {}; -class value { +PICOJSON_JWT_CPP_EXPORT class value { public: typedef std::vector array; typedef std::map object; @@ -206,8 +224,8 @@ class value { void clear(); }; -typedef value::array array; -typedef value::object object; +PICOJSON_JWT_CPP_EXPORT typedef value::array array; +PICOJSON_JWT_CPP_EXPORT typedef value::object object; inline value::value() : type_(null_type), u_() { } @@ -493,7 +511,8 @@ inline std::string value::to_str() const { case number_type: { char buf[256]; double tmp; - SNPRINTF(buf, sizeof(buf), fabs(u_.number_) < (1ULL << 53) && modf(u_.number_, &tmp) == 0 ? "%.f" : "%.17g", u_.number_); + SNPRINTF(buf, sizeof(buf), std::fabs(u_.number_) < (1ULL << 53) && std::modf(u_.number_, &tmp) == 0 ? "%.f" : "%.17g", + u_.number_); #if PICOJSON_USE_LOCALE char *decimal_point = localeconv()->decimal_point; if (strcmp(decimal_point, ".") != 0) { @@ -1147,7 +1166,7 @@ inline const std::string &get_last_error() { return last_error_t::s; } -inline bool operator==(const value &x, const value &y) { +PICOJSON_JWT_CPP_EXPORT inline bool operator==(const value &x, const value &y) { if (x.is()) return y.is(); #define PICOJSON_CMP(type) \ @@ -1166,7 +1185,7 @@ inline bool operator==(const value &x, const value &y) { return false; } -inline bool operator!=(const value &x, const value &y) { +PICOJSON_JWT_CPP_EXPORT inline bool operator!=(const value &x, const value &y) { return !(x == y); } } @@ -1179,7 +1198,7 @@ template <> inline void swap(picojson::value &x, picojson::value &y) { } #endif -inline std::istream &operator>>(std::istream &is, picojson::value &x) { +PICOJSON_JWT_CPP_EXPORT inline std::istream &operator>>(std::istream &is, picojson::value &x) { picojson::set_last_error(std::string()); const std::string err(picojson::parse(x, is)); if (!err.empty()) { @@ -1189,7 +1208,7 @@ inline std::istream &operator>>(std::istream &is, picojson::value &x) { return is; } -inline std::ostream &operator<<(std::ostream &os, const picojson::value &x) { +PICOJSON_JWT_CPP_EXPORT inline std::ostream &operator<<(std::ostream &os, const picojson::value &x) { x.serialize(std::ostream_iterator(os)); return os; } @@ -1197,4 +1216,7 @@ inline std::ostream &operator<<(std::ostream &os, const picojson::value &x) { #pragma warning(pop) #endif +#undef PICOJSON_JWT_CPP_EXPORT +#undef PICOJSON_USE_IMPORTED_STD + #endif diff --git a/modules/jwt.cppm b/modules/jwt.cppm new file mode 100644 index 000000000..061c522b6 --- /dev/null +++ b/modules/jwt.cppm @@ -0,0 +1,79 @@ +module; + +#ifndef NOMINMAX +#define NOMINMAX 1 +#endif + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif + +#ifndef JWT_USE_IMPORT_STD +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#endif + +export module jwt_cpp; + +#ifdef JWT_USE_IMPORT_STD +import std; +#endif + +#define JWT_CPP_MODULE_INTERFACE_BUILD 1 +#include "jwt-cpp/jwt.h" +#undef JWT_CPP_MODULE_INTERFACE_BUILD diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index bd407efa5..31d0adf26 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -145,6 +145,10 @@ if(TARGET reflectcpp::reflectcpp) endif() add_executable(jwt-cpp-test ${TEST_SOURCES}) +if(JWT_ENABLE_MODULES AND NOT JWT_USE_IMPORT_STD) + target_compile_definitions(jwt-cpp-test PRIVATE JWT_ENABLE_MODULES) + set_property(TARGET jwt-cpp-test PROPERTY CXX_SCAN_FOR_MODULES ON) +endif() # Add include path for generated traits_typelist.h target_include_directories(jwt-cpp-test PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/tests/HelperTest.cpp b/tests/HelperTest.cpp index dfcc0b0e0..a6a3f05d7 100644 --- a/tests/HelperTest.cpp +++ b/tests/HelperTest.cpp @@ -1,5 +1,9 @@ -#include "jwt-cpp/jwt.h" #include +#ifdef JWT_ENABLE_MODULES +import jwt_cpp; +#else +#include +#endif namespace { extern std::string google_cert; diff --git a/tests/OpenSSLErrorTest.cpp b/tests/OpenSSLErrorTest.cpp index 52c7cac91..7c213e116 100644 --- a/tests/OpenSSLErrorTest.cpp +++ b/tests/OpenSSLErrorTest.cpp @@ -2,10 +2,15 @@ #ifndef HUNTER_ENABLED // Static linking (which hunter always? does) breaks the tests (duplicate definition), so skip them -#include "jwt-cpp/jwt.h" #include #include + +#ifdef JWT_ENABLE_MODULES +import jwt_cpp; +#else +#include "jwt-cpp/jwt.h" +#endif // TODO: Figure out why the tests fail on older openssl versions #ifndef JWT_OPENSSL_1_0_0 // It fails on < 1.1 but no idea why. // LibreSSL has different return codes but was already outside of the effective scope diff --git a/tests/traits/BoostJsonTest.cpp b/tests/traits/BoostJsonTest.cpp index 8cdf7e145..c3ae7efb6 100644 --- a/tests/traits/BoostJsonTest.cpp +++ b/tests/traits/BoostJsonTest.cpp @@ -1,7 +1,7 @@ -#include "jwt-cpp/traits/boost-json/traits.h" - #include +#include "jwt-cpp/traits/boost-json/traits.h" + TEST(BoostJsonTest, BasicClaims) { const auto string = jwt::basic_claim(jwt::traits::boost_json::string_type("string")); ASSERT_EQ(string.get_type(), jwt::json::type::string); diff --git a/tests/traits/JsonconsTest.cpp b/tests/traits/JsonconsTest.cpp index facd90e3b..95f037572 100644 --- a/tests/traits/JsonconsTest.cpp +++ b/tests/traits/JsonconsTest.cpp @@ -1,7 +1,7 @@ -#include "jwt-cpp/traits/danielaparker-jsoncons/traits.h" - #include +#include "jwt-cpp/traits/danielaparker-jsoncons/traits.h" + TEST(JsonconsTest, BasicClaims) { const auto string = jwt::basic_claim( jwt::traits::danielaparker_jsoncons::string_type("string")); diff --git a/tests/traits/NlohmannTest.cpp b/tests/traits/NlohmannTest.cpp index 513a6c7f4..bd67138e4 100644 --- a/tests/traits/NlohmannTest.cpp +++ b/tests/traits/NlohmannTest.cpp @@ -1,7 +1,7 @@ -#include "jwt-cpp/traits/nlohmann-json/traits.h" - #include +#include "jwt-cpp/traits/nlohmann-json/traits.h" + TEST(NlohmannTest, BasicClaims) { const auto string = jwt::basic_claim(jwt::traits::nlohmann_json::string_type("string")); ASSERT_EQ(string.get_type(), jwt::json::type::string); diff --git a/tests/traits/OspJsoncppTest.cpp b/tests/traits/OspJsoncppTest.cpp index b85311848..de9bec472 100644 --- a/tests/traits/OspJsoncppTest.cpp +++ b/tests/traits/OspJsoncppTest.cpp @@ -1,7 +1,7 @@ -#include "jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h" - #include +#include "jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h" + TEST(OspJsoncppTest, BasicClaims) { const auto string = jwt::basic_claim( jwt::traits::open_source_parsers_jsoncpp::string_type("string"));