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

Failed to compile while using custom allocators #295

Open
1 task done
josephofthebread opened this issue Jun 16, 2023 · 2 comments
Open
1 task done

Failed to compile while using custom allocators #295

josephofthebread opened this issue Jun 16, 2023 · 2 comments
Assignees

Comments

@josephofthebread
Copy link

What happened?

Hey, I am implementing JWT authorization for my http server.
My server uses custom allocator and custom memory management system, since on Apple silicon there are not many tools for profiling. I am using nlohmann json implementation. Compilation fails with the following error message:

In file included from private/verification/authenticator.cpp:2:
In file included from public/verification/jwt.hpp:14:
dep/jwt/include/jwt-cpp/jwt.h:2852:45: error: no matching function for call to 'encode'
                                        return base::trim<alphabet::base64url>(base::encode<alphabet::base64url>(data));
                                                                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dep/jwt/include/jwt-cpp/jwt.h:2804:15: note: in instantiation of function template specialization 'jwt::builder<css::JwtJsonTraits>::sign<jwt::algorithm::hs256>' requested here
                        auto res = sign(algo, ec);
                                   ^
private/verification/authenticator.cpp:20:26: note: in instantiation of function template specialization 'jwt::builder<css::JwtJsonTraits>::sign<jwt::algorithm::hs256>' requested here
                        .sign(jwt::algorithm::hs256(m_Manager->getAccessTokenKey().c_str()));
                         ^
dep/jwt/include/jwt-cpp/base.h:252:15: note: candidate function template not viable: no known conversion from 'const basic_string<[2 * ...], Allocator<char, MemoryTag::STRING>>' to 'const basic_string<[2 * ...], allocator<char>>' for 1st argument
                std::string encode(const std::string& bin) {

What I am considering to be going on is that there is no specialization for base::encode to take std::string with custom allocator (code):

return sign(
algo,
[](const typename json_traits::string_type& data) {
	return base::trim<alphabet::base64url>(base::encode<alphabet::base64url>(data));
},
ec);

Compiler version: Apple clang version 14.0.3 (clang-1403.0.22.14.1)
Compilation options: -Wno-missing-braces -Wdouble-promotion -Wsign-conversion -Wunused-variable --std=c++20 -glldb

How To Reproduce?

Code:

String generateToken() {
        return jwt::create<JwtJsonTraits>()
                .set_issuer(CS_VERSION_STRING)
                .set_type("JWS")
                .set_payload_claim("type", "refresh")
                .set_payload_claim("username", username)
                .set_payload_claim("passwordHash", passwordHash)
                
                // "m_Manager->getRefreshTokenKey()"" returns String with native allocator
                // There .c_str is being called to convert string with native allocator
                // to std::string, because jwt::algorithm::hs256 accepts only std::string
                .sign(jwt::algorithm::hs256(m_Manager->getRefreshTokenKey().c_str()));
}

Json traits:

struct JwtJsonTraits
{
        using value_type        = Json;
        using object_type       = JsonObject;
        using array_type        = JsonArray;
        using string_type       = String;
        using number_type       = Json::number_float_t;
        using integer_type      = Json::number_integer_t;
        using boolean_type      = Json::boolean_t;

        static jwt::json::type get_type(const value_type &value)
        {
                using jwt_type = jwt::json::type;

                switch (value.type())
                {
                case nlohmann::detail::value_t::object:
                        return jwt_type::object;
                case nlohmann::detail::value_t::array:
                        return jwt_type::array;
                case nlohmann::detail::value_t::string:
                        return jwt_type::string;
                case nlohmann::detail::value_t::boolean:
                        return jwt_type::boolean;
                case nlohmann::detail::value_t::number_integer:
                        return jwt_type::number;
                case nlohmann::detail::value_t::null:
                case nlohmann::detail::value_t::number_unsigned:
                case nlohmann::detail::value_t::number_float:
                case nlohmann::detail::value_t::binary:
                case nlohmann::detail::value_t::discarded:
                        break;
                };

                throw std::invalid_argument("invalid json value type");
        }

        static object_type as_object(const value_type &val) { return val.get<object_type>(); }
        static array_type as_array(const value_type &val) { return val.get<array_type>(); }
        static string_type as_string(const value_type &val) { return val.get<string_type>(); }
        static number_type as_number(const value_type &val) { return val.get<number_type>(); }
        static integer_type as_integer(const value_type &val) { return val.get<integer_type>(); }
        static boolean_type as_boolean(const value_type &val) { return val.get<boolean_type>(); }

        static bool parse(value_type &val, string_type source) { return (val = jsonParse(std::move(source)), true); }
        static string_type serialize(const value_type &val) { return val.dump(); }
}

Aliases

template<class CharT>
using BasicString = std::basic_string<CharT, std::char_traits<CharT>, Allocator<CharT, MemoryTag::STRING>>;
using String = BasicString<char>;

template<class Type>
using JsonAllocator = Allocator<Type, MemoryTag::JSON>;
using Json = nlohmann::basic_json<std::map, std::vector, String, bool, int64_t, uint64_t, double, JsonAllocator>;

Version

0.6.0

What OS are you seeing the problem on?

MacOS

What compiler are you seeing the problem on?

Clang

Relevant log output

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct
@prince-chrismc
Copy link
Collaborator

This look really valid, feel free to submit a PR.

@josephofthebread
Copy link
Author

Unfortunately, I don't think there is any possible solution to provide support for custom strings without rewriting the whole
codebase. This will destroy backwards compatibility since, for example, all member of namespace algorithm should be template classes, which means that users would always have to provide boilerplate template deduction hint:

// this:
sign(jwt::algorithm::hs256<MyAwesomeStringType>{"secret"});
// instead of this:
sign(jwt::algorithm::hs256{"secret"});

This problem, however can be done with function aliases, as follows:

namespace jwt::algorithm {
  template<typename StringLike>
  struct hs256_struct {};  // instead of hs256

  template<typename StringLike>
  hs256_struct<StringLike> hs256(StringLike secret) {}
}

However, as I mentioned earlier, this will destroy backwards compatibility ...
I honestly don't think this library would ever support custom string types.

Btw, when I started exploring library source code, I found this.
Nlohmann json implementation supports custom string types for a long time already and I think deprecating support for them just because in 2017 it wasn't supporting that sounds kinda silly.

Anyway, thanks for support!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants