Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add JWT implementation #971

Merged
merged 12 commits into from
Oct 29, 2024
2 changes: 1 addition & 1 deletion externals/fmt
Submodule fmt updated 188 files
2 changes: 1 addition & 1 deletion externals/googletest
Submodule googletest updated 89 files
+43 −0 .github/workflows/gtest-ci.yml
+0 −1 .gitignore
+13 −30 BUILD.bazel
+2 −11 CMakeLists.txt
+4 −4 CONTRIBUTING.md
+0 −1 CONTRIBUTORS
+0 −67 MODULE.bazel
+13 −9 README.md
+13 −48 WORKSPACE
+0 −35 WORKSPACE.bzlmod
+4 −6 ci/linux-presubmit.sh
+1 −2 ci/macos-presubmit.sh
+3 −8 ci/windows-presubmit.bat
+13 −23 docs/advanced.md
+39 −18 docs/faq.md
+1 −1 docs/gmock_cheat_sheet.md
+6 −41 docs/gmock_cook_book.md
+5 −7 docs/gmock_for_dummies.md
+21 −20 docs/primer.md
+30 −23 docs/quickstart-bazel.md
+2 −2 docs/reference/assertions.md
+2 −1 docs/reference/mocking.md
+4 −25 docs/reference/testing.md
+0 −33 fake_fuchsia_sdk.bzl
+13 −14 googlemock/CMakeLists.txt
+3 −3 googlemock/README.md
+24 −87 googlemock/include/gmock/gmock-actions.h
+4 −5 googlemock/include/gmock/gmock-function-mocker.h
+124 −177 googlemock/include/gmock/gmock-matchers.h
+6 −8 googlemock/include/gmock/gmock-more-actions.h
+6 −4 googlemock/include/gmock/gmock-spec-builders.h
+7 −8 googlemock/include/gmock/gmock.h
+6 −8 googlemock/include/gmock/internal/gmock-internal-utils.h
+4 −5 googlemock/include/gmock/internal/gmock-port.h
+4 −4 googlemock/src/gmock-cardinalities.cc
+2 −3 googlemock/src/gmock-internal-utils.cc
+15 −14 googlemock/src/gmock-matchers.cc
+1 −2 googlemock/src/gmock-spec-builders.cc
+1 −2 googlemock/src/gmock_main.cc
+4 −52 googlemock/test/gmock-actions_test.cc
+2 −2 googlemock/test/gmock-function-mocker_test.cc
+27 −27 googlemock/test/gmock-matchers-arithmetic_test.cc
+2 −14 googlemock/test/gmock-matchers-comparisons_test.cc
+11 −29 googlemock/test/gmock-matchers-containers_test.cc
+23 −63 googlemock/test/gmock-matchers-misc_test.cc
+1 −39 googlemock/test/gmock-more-actions_test.cc
+1 −1 googlemock/test/gmock-pp_test.cc
+1 −1 googlemock/test/gmock-spec-builders_test.cc
+0 −9 googlemock/test/gmock_link_test.h
+14 −14 googletest/CMakeLists.txt
+3 −3 googletest/README.md
+0 −4 googletest/cmake/Config.cmake.in
+20 −22 googletest/cmake/internal_utils.cmake
+1 −1 googletest/include/gtest/gtest-assertion-result.h
+4 −4 googletest/include/gtest/gtest-death-test.h
+2 −33 googletest/include/gtest/gtest-message.h
+4 −4 googletest/include/gtest/gtest-param-test.h
+22 −80 googletest/include/gtest/gtest-printers.h
+61 −65 googletest/include/gtest/gtest-typed-test.h
+21 −38 googletest/include/gtest/gtest.h
+26 −25 googletest/include/gtest/internal/gtest-death-test-internal.h
+1 −7 googletest/include/gtest/internal/gtest-filepath.h
+82 −44 googletest/include/gtest/internal/gtest-internal.h
+75 −79 googletest/include/gtest/internal/gtest-param-util.h
+0 −4 googletest/include/gtest/internal/gtest-port-arch.h
+99 −103 googletest/include/gtest/internal/gtest-port.h
+3 −3 googletest/include/gtest/internal/gtest-type-util.h
+17 −19 googletest/src/gtest-death-test.cc
+3 −5 googletest/src/gtest-filepath.cc
+18 −30 googletest/src/gtest-internal-inl.h
+28 −70 googletest/src/gtest-port.cc
+120 −174 googletest/src/gtest.cc
+1 −2 googletest/src/gtest_main.cc
+0 −1 googletest/test/BUILD.bazel
+0 −1 googletest/test/googletest-color-test.py
+37 −41 googletest/test/googletest-death-test-test.cc
+0 −15 googletest/test/googletest-json-output-unittest.py
+0 −23 googletest/test/googletest-message-test.cc
+1 −4 googletest/test/googletest-options-test.cc
+5 −0 googletest/test/googletest-output-test-golden-lin.txt
+3 −3 googletest/test/googletest-port-test.cc
+0 −44 googletest/test/googletest-printers-test.cc
+44 −52 googletest/test/gtest_environment_test.cc
+41 −23 googletest/test/gtest_help_test.py
+0 −3 googletest/test/gtest_json_test_utils.py
+3 −1 googletest/test/gtest_repeat_test.cc
+27 −19 googletest/test/gtest_unittest.cc
+6 −9 googletest/test/gtest_xml_output_unittest.py
+10 −16 googletest_deps.bzl
72 changes: 72 additions & 0 deletions include/faker-cxx/internet.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#pragma once

#include <array>
#include <ctime>
#include <map>
#include <optional>
#include <string>
#include <string_view>
Expand Down Expand Up @@ -350,4 +352,74 @@ FAKER_CXX_EXPORT std::string_view domainSuffix();
* @endcode
*/
FAKER_CXX_EXPORT std::string anonymousUsername(unsigned maxLength);

/**
* @brief Generates a JSON Web Token (JWT).
*
* This function generates a JWT using the provided header, payload, and reference date.
* If no header or payload is provided, default values will be used.
* The reference date is optional and can be used to set the "iat" (issued at) claim in the payload.
*
* @param header The optional header map to include in the JWT. Defaults to a standard header.
* @param payload The optional payload map to include in the JWT. Defaults to a standard payload.
* @param refDate The optional reference date to set the "iat" claim. Defaults to the current date and time.
*
* @returns A string representing the generated JWT.
*
* @code
* std::map<std::string, std::string> header = {{"alg", "HS256"}, {"typ", "JWT"}};
* std::map<std::string, std::string> payload = {{"sub", "1234567890"}, {"name", "John Doe"}, {"admin", "true"}};
* std::string token = faker::internet::getJWTToken(header, payload); // "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
* @endcode
*/
FAKER_CXX_EXPORT std::string getJWTToken(std::optional<std::map<std::string, std::string>> header = std::nullopt,
std::optional<std::map<std::string, std::string>> payload = std::nullopt,
std::optional<std::string> refDate = std::nullopt);
MartinOnufrak marked this conversation as resolved.
Show resolved Hide resolved

/**
* @brief Returns the algorithm used for signing the JWT.
*
* This function provides the algorithm that is used to sign the JSON Web Token (JWT).
*
* @returns A string view representing the JWT signing algorithm.
*
* @code
* std::string_view algorithm = faker::internet::getJWTAlgorithm(); // "HS256"
MartinOnufrak marked this conversation as resolved.
Show resolved Hide resolved
* @endcode
*/
FAKER_CXX_EXPORT std::string_view getJWTAlgorithm();

/**
* @brief Encodes a given string to Base64 URL format.
*
* This function takes an input string and converts it into a Base64 URL encoded string.
* Base64 URL encoding is a variant of Base64 encoding that is URL-safe.
*
* @param input The string to be encoded.
*
* @returns A Base64 URL encoded string.
*
* @code
* std::string input = "Hello, World!";
* std::string encoded = faker::internet::toBase64UrlEncode(input); // "SGVsbG8sIFdvcmxkIQ"
* @endcode
*/
FAKER_CXX_EXPORT std::string toBase64UrlEncode(std::string& input);
MartinOnufrak marked this conversation as resolved.
Show resolved Hide resolved

/**
* @brief Converts a map of key-value pairs to a JSON string.
*
* This function takes a map where both keys and values are strings and converts it into a JSON formatted string.
*
* @param data The map containing key-value pairs to be converted to JSON.
*
* @returns A JSON formatted string representing the input map.
*
* @code
* std::map<std::string, std::string> data = {{"name", "John"}, {"age", "30"}};
* std::string json = faker::internet::toJSON(data); // json is now "{\"name\":\"John\",\"age\":\"30\"}"
* @endcode
*/
FAKER_CXX_EXPORT std::string toJSON(std::map<std::string, std::string>& data);
MartinOnufrak marked this conversation as resolved.
Show resolved Hide resolved

}
89 changes: 89 additions & 0 deletions src/modules/internet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

#include <algorithm>
#include <array>
#include <cmath>
#include <initializer_list>
#include <map>
#include <optional>
#include <regex>
#include <string>
#include <string_view>
#include <utility>
Expand All @@ -13,6 +15,8 @@
#include "common/algo_helper.h"
#include "common/format_helper.h"
#include "common/string_helper.h"
#include "faker-cxx/company.h"
#include "faker-cxx/faker.h"
#include "faker-cxx/helper.h"
#include "faker-cxx/number.h"
#include "faker-cxx/person.h"
Expand Down Expand Up @@ -348,4 +352,89 @@ std::string anonymousUsername(unsigned maxLength)
return common::format("{}{}", word::adjective(adjectiveLength), word::noun(nounLength));
}

std::string toBase64UrlEncode(std::string& input)
{
const std::string base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
std::string encodedInput;

int value = 0;
int validBits = -6;

for (unsigned char character : input)
{
value = (value << 8) + character;
validBits += 8;
while (validBits >= 0)
{
encodedInput.push_back(base64Chars[(value >> validBits) & 0x3F]);
validBits -= 6;
}
}

if (validBits > -6)
encodedInput.push_back(base64Chars[((value << 8) >> validBits) & 0x3F]);
while (encodedInput.size() % 4)
encodedInput.push_back('=');
MartinOnufrak marked this conversation as resolved.
Show resolved Hide resolved

std::replace(encodedInput.begin(), encodedInput.end(), '+', '-');
std::replace(encodedInput.begin(), encodedInput.end(), '/', '_');
encodedInput = std::regex_replace(encodedInput, std::regex{"=+$"}, "");

return encodedInput;
}

std::string toJSON(std::map<std::string, std::string>& data)
{
std::string json = "{";
for (auto it = data.begin(); it != data.end(); ++it)
{
if (it != data.begin())
json += ",";
MartinOnufrak marked this conversation as resolved.
Show resolved Hide resolved
json += "\"" + it->first + "\":\"" + it->second + "\"";
}
json += "}";
return json;
}

std::string_view getJWTAlgorithm()
{
return helper::randomElement(jwtAlgorithms);
}

std::string getJWTToken(std::optional<std::map<std::string, std::string>> header,
std::optional<std::map<std::string, std::string>> payload, std::optional<std::string> refDate)
{
std::string refDateValue = refDate.value_or(faker::date::anytime());

// maybe add option to set ref date to date functions then refactor this
std::string iatDefault = faker::date::recentDate(faker::date::dayOfMonth(), faker::date::DateFormat::Timestamp);
std::string expDefault = faker::date::soonDate(faker::date::dayOfMonth(), faker::date::DateFormat::Timestamp);
std::string nbfDefault = faker::date::anytime(faker::date::DateFormat::Timestamp);

std::string algorithm(getJWTAlgorithm());

if (!header)
header = {{"alg", algorithm}, {"typ", "JWT"}};
MartinOnufrak marked this conversation as resolved.
Show resolved Hide resolved
if (!payload)
{
payload = {{"iat", std::to_string(std::round(std::stoll(iatDefault)))},
{"exp", std::to_string(std::round(std::stoll(expDefault)))},
{"nbf", std::to_string(std::round(std::stoll(nbfDefault)))},
{"iss", faker::company::companyName()},
{"sub", faker::string::uuid()},
{"aud", faker::string::uuid()},
{"jti", faker::string::uuid()}};
}

std::string headerToJSON = toJSON(header.value());
std::string encodedHeader = toBase64UrlEncode(headerToJSON);

std::string payloadToJSON = toJSON(payload.value());
std::string encodedPayload = toBase64UrlEncode(payloadToJSON);

std::string signature = faker::string::alphanumeric(64);
MartinOnufrak marked this conversation as resolved.
Show resolved Hide resolved

return encodedHeader + "." + encodedPayload + "." + signature;
}

}
Loading