From 97b2668c433be7b5ce2b31d25773d63bf527dc17 Mon Sep 17 00:00:00 2001 From: Marcos Roque Date: Thu, 9 Jul 2026 05:01:11 -0300 Subject: [PATCH 1/2] build: add stylua tooling Pin stylua to spaces/double-quotes to match the existing style, add make fmt / fmt-check targets, and a CI job that fails on unformatted Lua. --- .github/workflows/test.yml | 10 ++++++++++ Makefile | 10 +++++++++- stylua.toml | 7 +++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 stylua.toml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c8151cd..b2de5c3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,6 +6,16 @@ on: pull_request: jobs: + fmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: JohnnyMorganz/stylua-action@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + version: latest + args: --check jsonwebtoken/ spec/ + spec: strategy: matrix: diff --git a/Makefile b/Makefile index 8f5a56f..5f73d83 100644 --- a/Makefile +++ b/Makefile @@ -7,4 +7,12 @@ test: lint: luacheck jsonwebtoken spec -.PHONY: test lint +# Format Lua sources in place with stylua. +fmt: + stylua jsonwebtoken/ spec/ + +# Verify formatting without writing; fails if anything is out of style. +fmt-check: + stylua --check jsonwebtoken/ spec/ + +.PHONY: test lint fmt fmt-check diff --git a/stylua.toml b/stylua.toml new file mode 100644 index 0000000..3f79723 --- /dev/null +++ b/stylua.toml @@ -0,0 +1,7 @@ +column_width = 120 +line_endings = "Unix" +indent_type = "Spaces" +indent_width = 4 +quote_style = "AutoPreferDouble" +call_parentheses = "Always" +collapse_simple_statement = "Never" From 9ed28041ff1713dfcfbe407b23a2c071c04da59c Mon Sep 17 00:00:00 2001 From: Marcos Roque Date: Thu, 9 Jul 2026 05:01:11 -0300 Subject: [PATCH 2/2] style: apply stylua to Lua sources --- jsonwebtoken/base64url.lua | 19 ++- jsonwebtoken/init.lua | 30 ++--- jsonwebtoken/json.lua | 19 ++- jsonwebtoken/sha2.lua | 249 ++++++++++++++++++++++++++----------- spec/base64url_spec.lua | 3 +- spec/json_spec.lua | 41 ++++-- spec/jsonwebtoken_spec.lua | 39 +++--- 7 files changed, 256 insertions(+), 144 deletions(-) diff --git a/jsonwebtoken/base64url.lua b/jsonwebtoken/base64url.lua index 89dc5dd..1a411aa 100644 --- a/jsonwebtoken/base64url.lua +++ b/jsonwebtoken/base64url.lua @@ -2,8 +2,7 @@ local base64url = {} -local ALPHABET = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" +local ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" local ENCODE = {} -- 6-bit value -> character local DECODE = {} -- character -> 6-bit value @@ -22,8 +21,7 @@ function base64url.encode(s) for i = 1, whole, 3 do local a, b, c = s:byte(i, i + 2) local v = a << 16 | b << 8 | c - out[#out + 1] = ENCODE[v >> 18] .. ENCODE[v >> 12 & 63] - .. ENCODE[v >> 6 & 63] .. ENCODE[v & 63] + out[#out + 1] = ENCODE[v >> 18] .. ENCODE[v >> 12 & 63] .. ENCODE[v >> 6 & 63] .. ENCODE[v & 63] end local rem = #s % 3 if rem == 1 then @@ -32,8 +30,7 @@ function base64url.encode(s) elseif rem == 2 then local a, b = s:byte(whole + 1, whole + 2) local v = a << 8 | b - out[#out + 1] = ENCODE[v >> 10] .. ENCODE[v >> 4 & 63] - .. ENCODE[v << 2 & 63] + out[#out + 1] = ENCODE[v >> 10] .. ENCODE[v >> 4 & 63] .. ENCODE[v << 2 & 63] end return table.concat(out) end @@ -51,8 +48,8 @@ function base64url.decode(s) local out = {} local whole = #s - rem for i = 1, whole, 4 do - local a, b, c, d = DECODE[s:sub(i, i)], DECODE[s:sub(i + 1, i + 1)], - DECODE[s:sub(i + 2, i + 2)], DECODE[s:sub(i + 3, i + 3)] + local a, b, c, d = + DECODE[s:sub(i, i)], DECODE[s:sub(i + 1, i + 1)], DECODE[s:sub(i + 2, i + 2)], DECODE[s:sub(i + 3, i + 3)] if not (a and b and c and d) then return nil end @@ -60,14 +57,14 @@ function base64url.decode(s) out[#out + 1] = string.char(v >> 16, v >> 8 & 255, v & 255) end if rem == 2 then - local a, b = DECODE[s:sub(whole + 1, whole + 1)], - DECODE[s:sub(whole + 2, whole + 2)] + local a, b = DECODE[s:sub(whole + 1, whole + 1)], DECODE[s:sub(whole + 2, whole + 2)] if not (a and b) then return nil end out[#out + 1] = string.char(a << 2 | b >> 4) elseif rem == 3 then - local a, b, c = DECODE[s:sub(whole + 1, whole + 1)], + local a, b, c = + DECODE[s:sub(whole + 1, whole + 1)], DECODE[s:sub(whole + 2, whole + 2)], DECODE[s:sub(whole + 3, whole + 3)] if not (a and b and c) then diff --git a/jsonwebtoken/init.lua b/jsonwebtoken/init.lua index 26e9998..9e7645b 100644 --- a/jsonwebtoken/init.lua +++ b/jsonwebtoken/init.lua @@ -40,8 +40,7 @@ end local function checked_alg(opts) local alg = opts.alg or DEFAULT_ALG if not HMAC_HASH[alg] then - error(("Unsupported algorithm %q (HS256, HS384 or HS512)") - :format(tostring(alg)), 3) + error(("Unsupported algorithm %q (HS256, HS384 or HS512)"):format(tostring(alg)), 3) end return alg end @@ -93,15 +92,13 @@ function jwt.sign(claims, secret, opts) if opts.header then for k, v in pairs(opts.header) do if k == "alg" or k == "typ" then - error(("%q cannot be overridden through opts.header") - :format(k), 2) + error(("%q cannot be overridden through opts.header"):format(k), 2) end header[k] = v end end - local signing_input = base64url.encode(json.encode(header)) - .. "." .. base64url.encode(json.encode(claims)) + local signing_input = base64url.encode(json.encode(header)) .. "." .. base64url.encode(json.encode(claims)) local signature = sha2.hmac(HMAC_HASH[alg], secret, signing_input) return signing_input .. "." .. base64url.encode(signature) end @@ -136,8 +133,7 @@ function jwt.verify(token, secret, opts) opts = opts or {} local alg = checked_alg(opts) - local header_b64, claims_b64, signature_b64 = - token:match("^([^.]+)%.([^.]+)%.([^.]+)$") + local header_b64, claims_b64, signature_b64 = token:match("^([^.]+)%.([^.]+)%.([^.]+)$") if not header_b64 then return fail("malformed", "Token is not three dot-separated parts") end @@ -148,17 +144,14 @@ function jwt.verify(token, secret, opts) return fail("malformed", "Header is not base64url-encoded JSON") end if header.alg ~= alg then - return fail("invalid_algorithm", - ("Token is signed with %s, expected %s") - :format(tostring(header.alg), alg)) + return fail("invalid_algorithm", ("Token is signed with %s, expected %s"):format(tostring(header.alg), alg)) end local signature = base64url.decode(signature_b64) if not signature then return fail("malformed", "Signature is not valid base64url") end - local expected = sha2.hmac(HMAC_HASH[alg], secret, - header_b64 .. "." .. claims_b64) + local expected = sha2.hmac(HMAC_HASH[alg], secret, header_b64 .. "." .. claims_b64) if not constant_time_equal(signature, expected) then return fail("invalid_signature", "Signature does not match") end @@ -190,18 +183,13 @@ function jwt.verify(token, secret, opts) end if opts.iss ~= nil and claims.iss ~= opts.iss then - return fail("invalid_issuer", - ("Issuer is %s, expected %s") - :format(tostring(claims.iss), opts.iss)) + return fail("invalid_issuer", ("Issuer is %s, expected %s"):format(tostring(claims.iss), opts.iss)) end if opts.aud ~= nil and not audience_matches(claims.aud, opts.aud) then - return fail("invalid_audience", - ("Audience does not include %s"):format(opts.aud)) + return fail("invalid_audience", ("Audience does not include %s"):format(opts.aud)) end if opts.sub ~= nil and claims.sub ~= opts.sub then - return fail("invalid_subject", - ("Subject is %s, expected %s") - :format(tostring(claims.sub), opts.sub)) + return fail("invalid_subject", ("Subject is %s, expected %s"):format(tostring(claims.sub), opts.sub)) end return claims diff --git a/jsonwebtoken/json.lua b/jsonwebtoken/json.lua index b64d052..e5a75ef 100644 --- a/jsonwebtoken/json.lua +++ b/jsonwebtoken/json.lua @@ -15,8 +15,13 @@ local json = {} -- Encoding -------------------------------------------------------------- local ESCAPE = { - ['"'] = '\\"', ["\\"] = "\\\\", ["\b"] = "\\b", ["\f"] = "\\f", - ["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t", + ['"'] = '\\"', + ["\\"] = "\\\\", + ["\b"] = "\\b", + ["\f"] = "\\f", + ["\n"] = "\\n", + ["\r"] = "\\r", + ["\t"] = "\\t", } local function escape_char(c) @@ -97,8 +102,14 @@ end -- Decoding -------------------------------------------------------------- local UNESCAPE = { - ['"'] = '"', ["\\"] = "\\", ["/"] = "/", - b = "\b", f = "\f", n = "\n", r = "\r", t = "\t", + ['"'] = '"', + ["\\"] = "\\", + ["/"] = "/", + b = "\b", + f = "\f", + n = "\n", + r = "\r", + t = "\t", } local function fail_at(pos, msg) diff --git a/jsonwebtoken/sha2.lua b/jsonwebtoken/sha2.lua index 2d4cbf5..ed41017 100644 --- a/jsonwebtoken/sha2.lua +++ b/jsonwebtoken/sha2.lua @@ -10,84 +10,186 @@ local sha2 = {} -- hash values) and cube roots (round constants) of the first primes. local H256 = { - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, - 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, + 0x6a09e667, + 0xbb67ae85, + 0x3c6ef372, + 0xa54ff53a, + 0x510e527f, + 0x9b05688c, + 0x1f83d9ab, + 0x5be0cd19, } local K256 = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, + 0x428a2f98, + 0x71374491, + 0xb5c0fbcf, + 0xe9b5dba5, + 0x3956c25b, + 0x59f111f1, + 0x923f82a4, + 0xab1c5ed5, + 0xd807aa98, + 0x12835b01, + 0x243185be, + 0x550c7dc3, + 0x72be5d74, + 0x80deb1fe, + 0x9bdc06a7, + 0xc19bf174, + 0xe49b69c1, + 0xefbe4786, + 0x0fc19dc6, + 0x240ca1cc, + 0x2de92c6f, + 0x4a7484aa, + 0x5cb0a9dc, + 0x76f988da, + 0x983e5152, + 0xa831c66d, + 0xb00327c8, + 0xbf597fc7, + 0xc6e00bf3, + 0xd5a79147, + 0x06ca6351, + 0x14292967, + 0x27b70a85, + 0x2e1b2138, + 0x4d2c6dfc, + 0x53380d13, + 0x650a7354, + 0x766a0abb, + 0x81c2c92e, + 0x92722c85, + 0xa2bfe8a1, + 0xa81a664b, + 0xc24b8b70, + 0xc76c51a3, + 0xd192e819, + 0xd6990624, + 0xf40e3585, + 0x106aa070, + 0x19a4c116, + 0x1e376c08, + 0x2748774c, + 0x34b0bcb5, + 0x391c0cb3, + 0x4ed8aa4a, + 0x5b9cca4f, + 0x682e6ff3, + 0x748f82ee, + 0x78a5636f, + 0x84c87814, + 0x8cc70208, + 0x90befffa, + 0xa4506ceb, + 0xbef9a3f7, + 0xc67178f2, } local H384 = { - 0xcbbb9d5dc1059ed8, 0x629a292a367cd507, - 0x9159015a3070dd17, 0x152fecd8f70e5939, - 0x67332667ffc00b31, 0x8eb44a8768581511, - 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4, + 0xcbbb9d5dc1059ed8, + 0x629a292a367cd507, + 0x9159015a3070dd17, + 0x152fecd8f70e5939, + 0x67332667ffc00b31, + 0x8eb44a8768581511, + 0xdb0c2e0d64f98fa7, + 0x47b5481dbefa4fa4, } local H512 = { - 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, - 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, - 0x510e527fade682d1, 0x9b05688c2b3e6c1f, - 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, + 0x6a09e667f3bcc908, + 0xbb67ae8584caa73b, + 0x3c6ef372fe94f82b, + 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, + 0x9b05688c2b3e6c1f, + 0x1f83d9abfb41bd6b, + 0x5be0cd19137e2179, } local K512 = { - 0x428a2f98d728ae22, 0x7137449123ef65cd, - 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, - 0x3956c25bf348b538, 0x59f111f1b605d019, - 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, - 0xd807aa98a3030242, 0x12835b0145706fbe, - 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, - 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, - 0x9bdc06a725c71235, 0xc19bf174cf692694, - 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, - 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, - 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, - 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, - 0x983e5152ee66dfab, 0xa831c66d2db43210, - 0xb00327c898fb213f, 0xbf597fc7beef0ee4, - 0xc6e00bf33da88fc2, 0xd5a79147930aa725, - 0x06ca6351e003826f, 0x142929670a0e6e70, - 0x27b70a8546d22ffc, 0x2e1b21385c26c926, - 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, - 0x650a73548baf63de, 0x766a0abb3c77b2a8, - 0x81c2c92e47edaee6, 0x92722c851482353b, - 0xa2bfe8a14cf10364, 0xa81a664bbc423001, - 0xc24b8b70d0f89791, 0xc76c51a30654be30, - 0xd192e819d6ef5218, 0xd69906245565a910, - 0xf40e35855771202a, 0x106aa07032bbd1b8, - 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, - 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, - 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, - 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, - 0x748f82ee5defb2fc, 0x78a5636f43172f60, - 0x84c87814a1f0ab72, 0x8cc702081a6439ec, - 0x90befffa23631e28, 0xa4506cebde82bde9, - 0xbef9a3f7b2c67915, 0xc67178f2e372532b, - 0xca273eceea26619c, 0xd186b8c721c0c207, - 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, - 0x06f067aa72176fba, 0x0a637dc5a2c898a6, - 0x113f9804bef90dae, 0x1b710b35131c471b, - 0x28db77f523047d84, 0x32caab7b40c72493, - 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, - 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, - 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, + 0x428a2f98d728ae22, + 0x7137449123ef65cd, + 0xb5c0fbcfec4d3b2f, + 0xe9b5dba58189dbbc, + 0x3956c25bf348b538, + 0x59f111f1b605d019, + 0x923f82a4af194f9b, + 0xab1c5ed5da6d8118, + 0xd807aa98a3030242, + 0x12835b0145706fbe, + 0x243185be4ee4b28c, + 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, + 0x80deb1fe3b1696b1, + 0x9bdc06a725c71235, + 0xc19bf174cf692694, + 0xe49b69c19ef14ad2, + 0xefbe4786384f25e3, + 0x0fc19dc68b8cd5b5, + 0x240ca1cc77ac9c65, + 0x2de92c6f592b0275, + 0x4a7484aa6ea6e483, + 0x5cb0a9dcbd41fbd4, + 0x76f988da831153b5, + 0x983e5152ee66dfab, + 0xa831c66d2db43210, + 0xb00327c898fb213f, + 0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2, + 0xd5a79147930aa725, + 0x06ca6351e003826f, + 0x142929670a0e6e70, + 0x27b70a8546d22ffc, + 0x2e1b21385c26c926, + 0x4d2c6dfc5ac42aed, + 0x53380d139d95b3df, + 0x650a73548baf63de, + 0x766a0abb3c77b2a8, + 0x81c2c92e47edaee6, + 0x92722c851482353b, + 0xa2bfe8a14cf10364, + 0xa81a664bbc423001, + 0xc24b8b70d0f89791, + 0xc76c51a30654be30, + 0xd192e819d6ef5218, + 0xd69906245565a910, + 0xf40e35855771202a, + 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, + 0x1e376c085141ab53, + 0x2748774cdf8eeb99, + 0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63, + 0x4ed8aa4ae3418acb, + 0x5b9cca4f7763e373, + 0x682e6ff3d6b2b8a3, + 0x748f82ee5defb2fc, + 0x78a5636f43172f60, + 0x84c87814a1f0ab72, + 0x8cc702081a6439ec, + 0x90befffa23631e28, + 0xa4506cebde82bde9, + 0xbef9a3f7b2c67915, + 0xc67178f2e372532b, + 0xca273eceea26619c, + 0xd186b8c721c0c207, + 0xeada7dd6cde0eb1e, + 0xf57d4f7fee6ed178, + 0x06f067aa72176fba, + 0x0a637dc5a2c898a6, + 0x113f9804bef90dae, + 0x1b710b35131c471b, + 0x28db77f523047d84, + 0x32caab7b40c72493, + 0x3c9ebe0a15c9bebc, + 0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6, + 0x597f299cfc657e2a, + 0x5fcb6fab3ad6faec, + 0x6c44198c4a475817, } local UNPACK_16x32 = ">" .. ("I4"):rep(16) @@ -100,8 +202,7 @@ local UNPACK_16x64 = ">" .. ("i8"):rep(16) local function pad(msg, block, lenbytes) local bits = #msg * 8 local zeros = (block - (#msg + 1 + lenbytes) % block) % block - return msg .. "\128" .. ("\0"):rep(zeros + lenbytes - 8) - .. string.pack(">I8", bits) + return msg .. "\128" .. ("\0"):rep(zeros + lenbytes - 8) .. string.pack(">I8", bits) end local function rotr32(x, n) @@ -135,10 +236,8 @@ function sha2.sha256(msg) h, g, f, e = g, f, e, (d + t1) & 0xffffffff d, c, b, a = c, b, a, (t1 + t2) & 0xffffffff end - h1, h2, h3, h4 = (h1 + a) & 0xffffffff, (h2 + b) & 0xffffffff, - (h3 + c) & 0xffffffff, (h4 + d) & 0xffffffff - h5, h6, h7, h8 = (h5 + e) & 0xffffffff, (h6 + f) & 0xffffffff, - (h7 + g) & 0xffffffff, (h8 + h) & 0xffffffff + h1, h2, h3, h4 = (h1 + a) & 0xffffffff, (h2 + b) & 0xffffffff, (h3 + c) & 0xffffffff, (h4 + d) & 0xffffffff + h5, h6, h7, h8 = (h5 + e) & 0xffffffff, (h6 + f) & 0xffffffff, (h7 + g) & 0xffffffff, (h8 + h) & 0xffffffff end return string.pack(">I4I4I4I4I4I4I4I4", h1, h2, h3, h4, h5, h6, h7, h8) end @@ -170,8 +269,7 @@ local function sha512_core(msg, iv, outwords) h5, h6, h7, h8 = h5 + e, h6 + f, h7 + g, h8 + h end local words = { h1, h2, h3, h4, h5, h6, h7, h8 } - return string.pack(">" .. ("i8"):rep(outwords), - table.unpack(words, 1, outwords)) + return string.pack(">" .. ("i8"):rep(outwords), table.unpack(words, 1, outwords)) end --- SHA-384. Returns the 48-byte digest. @@ -208,8 +306,7 @@ end function sha2.hmac(alg, key, msg) local h = HASH[alg] if not h then - error(("Unknown hash %q (sha256, sha384 or sha512)") - :format(tostring(alg)), 2) + error(("Unknown hash %q (sha256, sha384 or sha512)"):format(tostring(alg)), 2) end if #key > h.block then key = h.digest(key) diff --git a/spec/base64url_spec.lua b/spec/base64url_spec.lua index 7d97859..86a0dd4 100644 --- a/spec/base64url_spec.lua +++ b/spec/base64url_spec.lua @@ -47,8 +47,7 @@ describe("base64url.decode", function() end) it("decodes a real JWT header", function() - assert.equal('{"alg":"HS256","typ":"JWT"}', - base64url.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9")) + assert.equal('{"alg":"HS256","typ":"JWT"}', base64url.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9")) end) it("rejects padded input", function() diff --git a/spec/json_spec.lua b/spec/json_spec.lua index 7b10d5b..414ba12 100644 --- a/spec/json_spec.lua +++ b/spec/json_spec.lua @@ -2,8 +2,7 @@ local json = require("jsonwebtoken.json") describe("json.encode", function() it("sorts object keys, so equal tables encode identically", function() - assert.equal('{"alg":"HS256","typ":"JWT"}', - json.encode({ typ = "JWT", alg = "HS256" })) + assert.equal('{"alg":"HS256","typ":"JWT"}', json.encode({ typ = "JWT", alg = "HS256" })) end) it("encodes an empty table as an empty object", function() @@ -32,15 +31,25 @@ describe("json.encode", function() end) it("encodes nested structures", function() - assert.equal('{"user":{"roles":["admin"],"sub":"42"}}', - json.encode({ user = { sub = "42", roles = { "admin" } } })) + assert.equal( + '{"user":{"roles":["admin"],"sub":"42"}}', + json.encode({ user = { sub = "42", roles = { "admin" } } }) + ) end) it("rejects values JSON cannot represent", function() - assert.error_matches(function() json.encode(print) end, "function") - assert.error_matches(function() json.encode(nil) end, "nil") - assert.error_matches(function() json.encode(0 / 0) end, "NaN") - assert.error_matches(function() json.encode(math.huge) end, "NaN") + assert.error_matches(function() + json.encode(print) + end, "function") + assert.error_matches(function() + json.encode(nil) + end, "nil") + assert.error_matches(function() + json.encode(0 / 0) + end, "NaN") + assert.error_matches(function() + json.encode(math.huge) + end, "NaN") end) it("rejects non-string object keys", function() @@ -52,7 +61,9 @@ describe("json.encode", function() it("rejects reference cycles instead of looping forever", function() local t = {} t.self = t - assert.error_matches(function() json.encode(t) end, "nesting too deep") + assert.error_matches(function() + json.encode(t) + end, "nesting too deep") end) end) @@ -105,8 +116,16 @@ describe("json.decode", function() it("rejects malformed input with a position", function() for _, bad in ipairs({ - '{"a":}', '{"a" 1}', "[1,]", '"unterminated', '"bad \\q escape"', - "tru", "01x", "-", '{"a":1,}', '{1:2}', + '{"a":}', + '{"a" 1}', + "[1,]", + '"unterminated', + '"bad \\q escape"', + "tru", + "01x", + "-", + '{"a":1,}', + "{1:2}", }) do local v, err = json.decode(bad) assert.is_nil(v, "accepted: " .. bad) diff --git a/spec/jsonwebtoken_spec.lua b/spec/jsonwebtoken_spec.lua index 735f09e..e50fcc0 100644 --- a/spec/jsonwebtoken_spec.lua +++ b/spec/jsonwebtoken_spec.lua @@ -54,12 +54,15 @@ describe("jwt.sign", function() end) it("rejects bad arguments loudly", function() - assert.error_matches(function() jwt.sign("s", SECRET) end, - "Claims must be a table") - assert.error_matches(function() jwt.sign(CLAIMS, nil) end, - "Secret must be a string") - assert.error_matches(function() jwt.sign(CLAIMS, "") end, - "Secret must not be empty") + assert.error_matches(function() + jwt.sign("s", SECRET) + end, "Claims must be a table") + assert.error_matches(function() + jwt.sign(CLAIMS, nil) + end, "Secret must be a string") + assert.error_matches(function() + jwt.sign(CLAIMS, "") + end, "Secret must not be empty") assert.error_matches(function() jwt.sign(CLAIMS, SECRET, { alg = "RS256" }) end, "Unsupported algorithm") @@ -93,10 +96,8 @@ describe("jwt.verify", function() it("rejects a tampered payload", function() local header, _, signature = GOLDEN.HS256:match("([^.]+)%.([^.]+)%.([^.]+)") - local forged = require("jsonwebtoken.base64url") - .encode('{"sub":"admin"}') - local claims, err = jwt.verify( - header .. "." .. forged .. "." .. signature, SECRET) + local forged = require("jsonwebtoken.base64url").encode('{"sub":"admin"}') + local claims, err = jwt.verify(header .. "." .. forged .. "." .. signature, SECRET) assert.is_nil(claims) assert.equal("invalid_signature", err.code) end) @@ -112,10 +113,8 @@ describe("jwt.verify", function() local base64url = require("jsonwebtoken.base64url") local payload = base64url.encode('{"sub":"admin"}') for _, spelling in ipairs({ "none", "None", "NONE" }) do - local header = base64url.encode( - ('{"alg":"%s","typ":"JWT"}'):format(spelling)) - local claims, err = jwt.verify( - header .. "." .. payload .. ".sig", SECRET) + local header = base64url.encode(('{"alg":"%s","typ":"JWT"}'):format(spelling)) + local claims, err = jwt.verify(header .. "." .. payload .. ".sig", SECRET) assert.is_nil(claims) assert.equal("invalid_algorithm", err.code) end @@ -128,7 +127,11 @@ describe("jwt.verify", function() it("rejects structurally broken tokens as malformed", function() for _, bad in ipairs({ - "", "abc", "a.b", "a.b.c.d", "!!!.b.c", + "", + "abc", + "a.b", + "a.b.c.d", + "!!!.b.c", }) do local claims, err = jwt.verify(bad, SECRET) assert.is_nil(claims, "accepted: " .. bad) @@ -142,10 +145,8 @@ describe("jwt.verify", function() local header = base64url.encode('{"alg":"HS256","typ":"JWT"}') local payload = base64url.encode("not json") local signing_input = header .. "." .. payload - local signature = base64url.encode( - sha2.hmac("sha256", SECRET, signing_input)) - local claims, err = jwt.verify( - signing_input .. "." .. signature, SECRET) + local signature = base64url.encode(sha2.hmac("sha256", SECRET, signing_input)) + local claims, err = jwt.verify(signing_input .. "." .. signature, SECRET) assert.is_nil(claims) assert.equal("malformed", err.code) end)