• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Thalhammer / jwt-cpp / 11876093722

17 Nov 2024 04:58AM UTC coverage: 94.974%. Remained the same
11876093722

push

github

web-flow
Ensure array_type has front() method + fix array_type on jsoncpp (#361)

* Use operator[] instead of front to support jsoncpp

Replace the `front()` with `[0]` as front is not supported by jsoncpp on
array types.

Signed-off-by: Omar Mohamed <mohamed.omar67492@gmail.com>

* Revert "Use operator[] instead of front to support jsoncpp"

This reverts commit dfa7d29da.

* Implement `front()` in jsoncpp array_type

Signed-off-by: Omar Mohamed <mohamed.omar67492@gmail.com>

* Check if array_type has a front() method

Signed-off-by: Omar Mohamed <mohamed.omar67492@gmail.com>

* Add `front()` to jsoncons array_type

* Remove non-const overloads of front()

Signed-off-by: Omar Mohamed <mohamed.omar67492@gmail.com>

* Fix check for front() in array_type

Signed-off-by: Omar Mohamed <mohamed.omar67492@gmail.com>

* Use std::decay

Signed-off-by: Omar Mohamed <mohamed.omar67492@gmail.com>

* fix example to print array value

* expose base class ctors

* update as_array traits helper

* fixup linter

---------

Signed-off-by: Omar Mohamed <mohamed.omar67492@gmail.com>
Co-authored-by: Chris Mc <prince.chrismc@gmail.com>

1285 of 1353 relevant lines covered (94.97%)

255.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.77
/include/jwt-cpp/base.h
1
#ifndef JWT_CPP_BASE_H
2
#define JWT_CPP_BASE_H
3

4
#include <algorithm>
5
#include <array>
6
#include <cstdint>
7
#include <stdexcept>
8
#include <string>
9
#include <vector>
10

11
#ifdef __has_cpp_attribute
12
#if __has_cpp_attribute(fallthrough)
13
#define JWT_FALLTHROUGH [[fallthrough]]
14
#endif
15
#endif
16

17
#ifndef JWT_FALLTHROUGH
18
#define JWT_FALLTHROUGH
19
#endif
20

21
namespace jwt {
22
        /**
23
         * \brief character maps when encoding and decoding
24
         */
25
        namespace alphabet {
26
                /**
27
                 * \brief valid list of character when working with [Base64](https://datatracker.ietf.org/doc/html/rfc4648#section-4)
28
                 *
29
                 * As directed in [X.509 Parameter](https://datatracker.ietf.org/doc/html/rfc7517#section-4.7) certificate chains are
30
                 * base64-encoded as per [Section 4 of RFC4648](https://datatracker.ietf.org/doc/html/rfc4648#section-4)
31
                 */
32
                struct base64 {
33
                        static const std::array<char, 64>& data() {
7✔
34
                                static constexpr std::array<char, 64> data{
35
                                        {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
36
                                         'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
37
                                         'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
38
                                         'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}};
39
                                return data;
7✔
40
                        }
41
                        static const std::array<int8_t, 256>& rdata() {
602✔
42
                                static constexpr std::array<int8_t, 256> rdata{{
43
                                        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
44
                                        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
45
                                        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0,        1,        2,        3,        4,        5,        6,
46
                                        7,        8,        9,        10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
47
                                        -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
48
                                        49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
49
                                        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
50
                                        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
51
                                        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
52
                                        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
53
                                        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
54
                                }};
55
                                return rdata;
602✔
56
                        }
57
                        static const std::string& fill() {
47✔
58
                                static const std::string fill{"="};
47✔
59
                                return fill;
47✔
60
                        }
61
                };
62
                /**
63
                 * \brief valid list of character when working with [Base64URL](https://tools.ietf.org/html/rfc4648#section-5)
64
                 *
65
                 * As directed by [RFC 7519 Terminology](https://datatracker.ietf.org/doc/html/rfc7519#section-2) set the definition of Base64URL
66
                 * encoding as that in [RFC 7515](https://datatracker.ietf.org/doc/html/rfc7515#section-2) that states:
67
                 *
68
                 * > Base64 encoding using the URL- and filename-safe character set defined in
69
                 * > [Section 5 of RFC 4648 RFC4648](https://tools.ietf.org/html/rfc4648#section-5), with all trailing '=' characters omitted
70
                 */
71
                struct base64url {
72
                        static const std::array<char, 64>& data() {
153✔
73
                                static constexpr std::array<char, 64> data{
74
                                        {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
75
                                         'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
76
                                         'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
77
                                         'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'}};
78
                                return data;
153✔
79
                        }
80
                        static const std::array<int8_t, 256>& rdata() {
903✔
81
                                static constexpr std::array<int8_t, 256> rdata{{
82
                                        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
83
                                        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
84
                                        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0,        1,        2,        3,        4,        5,        6,
85
                                        7,        8,        9,        10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
86
                                        -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
87
                                        49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
88
                                        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
89
                                        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
90
                                        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
91
                                        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
92
                                        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
93
                                }};
94
                                return rdata;
903✔
95
                        }
96
                        static const std::string& fill() {
946✔
97
                                static const std::string fill{"%3d"};
946✔
98
                                return fill;
946✔
99
                        }
100
                };
101
                namespace helper {
102
                        /**
103
                         * \brief A General purpose base64url alphabet respecting the
104
                         * [URI Case Normalization](https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2.1)
105
                         *
106
                         * This is useful in situations outside of JWT encoding/decoding and is provided as a helper
107
                         */
108
                        struct base64url_percent_encoding {
109
                                static const std::array<char, 64>& data() {
110
                                        static constexpr std::array<char, 64> data{
111
                                                {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
112
                                                 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
113
                                                 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
114
                                                 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'}};
115
                                        return data;
116
                                }
117
                                static const std::array<int8_t, 256>& rdata() {
7✔
118
                                        static constexpr std::array<int8_t, 256> rdata{{
119
                                                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
120
                                                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
121
                                                52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0,        1,        2,        3,        4,        5,        6,
122
                                                7,        8,        9,        10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
123
                                                -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
124
                                                49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
125
                                                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
126
                                                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
127
                                                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
128
                                                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
129
                                                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
130
                                        }};
131
                                        return rdata;
7✔
132
                                }
133
                                static const std::vector<std::string>& fill() {
7✔
134
                                        static const std::vector<std::string> fill{"%3D", "%3d"};
9✔
135
                                        return fill;
7✔
136
                                }
137
                        };
138
                } // namespace helper
139

140
                inline uint32_t index(const std::array<int8_t, 256>& rdata, char symbol) {
35,691✔
141
                        auto index = rdata[static_cast<unsigned char>(symbol)];
35,691✔
142
                        if (index <= -1) { throw std::runtime_error("Invalid input: not within alphabet"); }
35,691✔
143
                        return static_cast<uint32_t>(index);
35,691✔
144
                }
145
        } // namespace alphabet
146

147
        /**
148
         * \brief A collection of fellable functions for working with base64 and base64url
149
         */
150
        namespace base {
151
                namespace details {
152
                        struct padding {
153
                                size_t count = 0;
154
                                size_t length = 0;
155

156
                                padding() = default;
377✔
157
                                padding(size_t count, size_t length) : count(count), length(length) {}
515✔
158

159
                                padding operator+(const padding& p) { return padding(count + p.count, length + p.length); }
250✔
160

161
                                friend bool operator==(const padding& lhs, const padding& rhs) {
21✔
162
                                        return lhs.count == rhs.count && lhs.length == rhs.length;
21✔
163
                                }
164
                        };
165

166
                        inline padding count_padding(const std::string& base, const std::vector<std::string>& fills) {
621✔
167
                                for (const auto& fill : fills) {
1,031✔
168
                                        if (base.size() < fill.size()) continue;
660✔
169
                                        // Does the end of the input exactly match the fill pattern?
170
                                        if (base.substr(base.size() - fill.size()) == fill) {
634✔
171
                                                return padding{1, fill.length()} +
250✔
172
                                                           count_padding(base.substr(0, base.size() - fill.size()), fills);
500✔
173
                                        }
174
                                }
175

176
                                return {};
371✔
177
                        }
178

179
                        inline std::string encode(const std::string& bin, const std::array<char, 64>& alphabet,
156✔
180
                                                                          const std::string& fill) {
181
                                size_t size = bin.size();
156✔
182
                                std::string res;
156✔
183

184
                                // clear incomplete bytes
185
                                size_t fast_size = size - size % 3;
156✔
186
                                for (size_t i = 0; i < fast_size;) {
1,771✔
187
                                        uint32_t octet_a = static_cast<unsigned char>(bin[i++]);
1,615✔
188
                                        uint32_t octet_b = static_cast<unsigned char>(bin[i++]);
1,615✔
189
                                        uint32_t octet_c = static_cast<unsigned char>(bin[i++]);
1,615✔
190

191
                                        uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
1,615✔
192

193
                                        res += alphabet[(triple >> 3 * 6) & 0x3F];
1,615✔
194
                                        res += alphabet[(triple >> 2 * 6) & 0x3F];
1,615✔
195
                                        res += alphabet[(triple >> 1 * 6) & 0x3F];
1,615✔
196
                                        res += alphabet[(triple >> 0 * 6) & 0x3F];
1,615✔
197
                                }
198

199
                                if (fast_size == size) return res;
156✔
200

201
                                size_t mod = size % 3;
78✔
202

203
                                uint32_t octet_a = fast_size < size ? static_cast<unsigned char>(bin[fast_size++]) : 0;
78✔
204
                                uint32_t octet_b = fast_size < size ? static_cast<unsigned char>(bin[fast_size++]) : 0;
78✔
205
                                uint32_t octet_c = fast_size < size ? static_cast<unsigned char>(bin[fast_size++]) : 0;
78✔
206

207
                                uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
78✔
208

209
                                switch (mod) {
78✔
210
                                case 1:
24✔
211
                                        res += alphabet[(triple >> 3 * 6) & 0x3F];
24✔
212
                                        res += alphabet[(triple >> 2 * 6) & 0x3F];
24✔
213
                                        res += fill;
24✔
214
                                        res += fill;
24✔
215
                                        break;
24✔
216
                                case 2:
54✔
217
                                        res += alphabet[(triple >> 3 * 6) & 0x3F];
54✔
218
                                        res += alphabet[(triple >> 2 * 6) & 0x3F];
54✔
219
                                        res += alphabet[(triple >> 1 * 6) & 0x3F];
54✔
220
                                        res += fill;
54✔
221
                                        break;
54✔
222
                                default: break;
×
223
                                }
224

225
                                return res;
78✔
226
                        }
×
227

228
                        inline std::string decode(const std::string& base, const std::array<int8_t, 256>& rdata,
350✔
229
                                                                          const std::vector<std::string>& fill) {
230
                                const auto pad = count_padding(base, fill);
350✔
231
                                if (pad.count > 2) throw std::runtime_error("Invalid input: too much fill");
350✔
232

233
                                const size_t size = base.size() - pad.length;
349✔
234
                                if ((size + pad.count) % 4 != 0) throw std::runtime_error("Invalid input: incorrect total size");
349✔
235

236
                                size_t out_size = size / 4 * 3;
349✔
237
                                std::string res;
349✔
238
                                res.reserve(out_size);
349✔
239

240
                                auto get_sextet = [&](size_t offset) { return alphabet::index(rdata, base[offset]); };
35,557✔
241

242
                                size_t fast_size = size - size % 4;
349✔
243
                                for (size_t i = 0; i < fast_size;) {
9,145✔
244
                                        uint32_t sextet_a = get_sextet(i++);
8,796✔
245
                                        uint32_t sextet_b = get_sextet(i++);
8,796✔
246
                                        uint32_t sextet_c = get_sextet(i++);
8,796✔
247
                                        uint32_t sextet_d = get_sextet(i++);
8,796✔
248

249
                                        uint32_t triple =
8,796✔
250
                                                (sextet_a << 3 * 6) + (sextet_b << 2 * 6) + (sextet_c << 1 * 6) + (sextet_d << 0 * 6);
8,796✔
251

252
                                        res += static_cast<char>((triple >> 2 * 8) & 0xFFU);
8,796✔
253
                                        res += static_cast<char>((triple >> 1 * 8) & 0xFFU);
8,796✔
254
                                        res += static_cast<char>((triple >> 0 * 8) & 0xFFU);
8,796✔
255
                                }
256

257
                                if (pad.count == 0) return res;
349✔
258

259
                                uint32_t triple = (get_sextet(fast_size) << 3 * 6) + (get_sextet(fast_size + 1) << 2 * 6);
146✔
260

261
                                switch (pad.count) {
146✔
262
                                case 1:
81✔
263
                                        triple |= (get_sextet(fast_size + 2) << 1 * 6);
81✔
264
                                        res += static_cast<char>((triple >> 2 * 8) & 0xFFU);
81✔
265
                                        res += static_cast<char>((triple >> 1 * 8) & 0xFFU);
81✔
266
                                        break;
81✔
267
                                case 2: res += static_cast<char>((triple >> 2 * 8) & 0xFFU); break;
65✔
268
                                default: break;
×
269
                                }
270

271
                                return res;
146✔
272
                        }
×
273

274
                        inline std::string decode(const std::string& base, const std::array<int8_t, 256>& rdata,
343✔
275
                                                                          const std::string& fill) {
276
                                return decode(base, rdata, std::vector<std::string>{fill});
1,030✔
277
                        }
278

279
                        inline std::string pad(const std::string& base, const std::string& fill) {
339✔
280
                                std::string padding;
339✔
281
                                switch (base.size() % 4) {
339✔
282
                                case 1: padding += fill; JWT_FALLTHROUGH;
1✔
283
                                case 2: padding += fill; JWT_FALLTHROUGH;
53✔
284
                                case 3: padding += fill; JWT_FALLTHROUGH;
126✔
285
                                default: break;
339✔
286
                                }
287

288
                                return base + padding;
678✔
289
                        }
339✔
290

291
                        inline std::string trim(const std::string& base, const std::string& fill) {
155✔
292
                                auto pos = base.find(fill);
155✔
293
                                return base.substr(0, pos);
155✔
294
                        }
295
                } // namespace details
296

297
                /**
298
                 * \brief Generic base64 encoding
299
                 * 
300
                 * A Generic base64 encode function that supports any "alphabet"
301
                 * such as jwt::alphabet::base64 
302
                 * 
303
                 * \code
304
                 * const auto b64 = jwt::base::encode<jwt::alphabet::base64>("example_data")
305
                 * \endcode
306
                 */
307
                template<typename T>
308
                std::string encode(const std::string& bin) {
156✔
309
                        return details::encode(bin, T::data(), T::fill());
156✔
310
                }
311
                /**
312
                 * \brief Generic base64 decoding
313
                 * 
314
                 * A Generic base64 decoding function that supports any "alphabet"
315
                 * such as jwt::alphabet::base64 
316
                 * 
317
                 * \code
318
                 * const auto b64 = jwt::base::decode<jwt::alphabet::base64>("ZXhhbXBsZV9kYXRh")
319
                 * \endcode
320
                 */
321
                template<typename T>
322
                std::string decode(const std::string& base) {
350✔
323
                        return details::decode(base, T::rdata(), T::fill());
350✔
324
                }
325
                /**
326
                 * \brief Generic base64 padding
327
                 * 
328
                 * A Generic base64 pad function that supports any "alphabet"
329
                 * such as jwt::alphabet::base64 
330
                 * 
331
                 * \code
332
                 * const auto b64 = jwt::base::pad<jwt::alphabet::base64>("ZXhhbXBsZV9kYQ")
333
                 * \endcode
334
                 */
335
                template<typename T>
336
                std::string pad(const std::string& base) {
339✔
337
                        return details::pad(base, T::fill());
339✔
338
                }
339
                /**
340
                 * \brief Generic base64 trimming
341
                 * 
342
                 * A Generic base64 trim function that supports any "alphabet"
343
                 * such as jwt::alphabet::base64 
344
                 * 
345
                 * \code
346
                 * const auto b64 = jwt::base::trim<jwt::alphabet::base64>("ZXhhbXBsZV9kYQ==")
347
                 * \endcode
348
                 */
349
                template<typename T>
350
                std::string trim(const std::string& base) {
155✔
351
                        return details::trim(base, T::fill());
155✔
352
                }
353
        } // namespace base
354
} // namespace jwt
355

356
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc