Skip to content
This repository was archived by the owner on Mar 20, 2024. It is now read-only.

Commit 667cbc6

Browse files
committed
v0.2.0
1 parent 734da69 commit 667cbc6

File tree

4 files changed

+17
-52
lines changed

4 files changed

+17
-52
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@rbxts/jwt",
3-
"version": "0.1.1",
3+
"version": "0.2.0",
44
"description": "JWT lib for Luau",
55
"main": "out/init.lua",
66
"scripts": {

src/index.ts

+14-49
Original file line numberDiff line numberDiff line change
@@ -12,47 +12,17 @@ const algsSign = {
1212

1313
const algsVerify = {
1414
HS256: (message: string, key: string, signature: string) =>
15-
hash.hmac(hash.sha256, key, message, true) === signature,
15+
base64urlEncode(hash.hmac(hash.sha256, key, message, true)) === signature,
1616
HS384: (message: string, key: string, signature: string) =>
17-
hash.hmac(hash.sha384, key, message, true) === signature,
17+
base64urlEncode(hash.hmac(hash.sha384, key, message, true)) === signature,
1818
HS512: (message: string, key: string, signature: string) =>
19-
hash.hmac(hash.sha512, key, message, true) === signature,
19+
base64urlEncode(hash.hmac(hash.sha512, key, message, true)) === signature,
2020
} as {
2121
[key: string]: (message: string, key: string, signature: string) => boolean;
2222
};
2323

2424
function base64urlEncode(str: string) {
25-
return encode(str).gsub("+", "-")[0].gsub("/", "_")[0].gsub("=", "");
26-
}
27-
28-
function base64urlDecode(str: string) {
29-
const remainder = str.size() % 4;
30-
31-
if (remainder > 0) {
32-
str = str + string.rep("=", 4 - remainder);
33-
}
34-
35-
return decode(str.gsub("-", "+")[0].gsub("_", "/")[0].gsub("=", "")[0]);
36-
}
37-
38-
function tokenize(str: string, div: string, len: number): string[] {
39-
const result: string[] = [];
40-
let pos = 0;
41-
42-
while (len > 1) {
43-
const st = str.find(div, pos, true);
44-
if (!st[0]) break;
45-
const sp = st[0] + div.size() - 1;
46-
47-
result.push(str.sub(pos, st[0] - 1));
48-
pos = sp + 1;
49-
50-
len = len - 1;
51-
}
52-
53-
result.push(str.sub(pos));
54-
55-
return result;
25+
return encode(str).gsub("+", "-")[0].gsub("/", "_")[0].gsub("=", "")[0];
5626
}
5727

5828
function encodeJWT(data: unknown, key: string, alg: string | undefined = "HS256"): string {
@@ -73,7 +43,9 @@ function encodeJWT(data: unknown, key: string, alg: string | undefined = "HS256"
7343
}
7444

7545
const header = { typ: "JWT", alg: alg };
76-
const segments = [base64urlEncode(HttpService.JSONEncode(header)), base64urlEncode(HttpService.JSONEncode(data))];
46+
47+
const segments = [encode(HttpService.JSONEncode(header)), encode(HttpService.JSONEncode(data))];
48+
7749
const signingInput = segments.join(".");
7850
const signature = base64urlEncode(algsSign[alg](signingInput, key));
7951

@@ -89,7 +61,6 @@ function decodeJWT(
8961
): {
9062
header: { alg: string; typ: string };
9163
body: { exp: number; iat: number; nbf: number; [key: string]: unknown };
92-
signature: string;
9364
} {
9465
if (!key) {
9566
verify = false;
@@ -101,42 +72,36 @@ function decodeJWT(
10172
error("data must be a string");
10273
}
10374

104-
if (typeOf(key) !== "string" || !key) {
105-
error("key must be a string");
106-
}
107-
10875
if (typeOf(verify) !== "boolean") {
10976
error("verify must be a boolean");
11077
}
11178

112-
const segments = tokenize(data, ".", 3);
79+
const segments = data.split(".");
11380

11481
if (segments.size() !== 3) {
11582
error("not enough or too many segments");
11683
}
11784

11885
const headerSegment = segments[0];
11986
const payloadSegment = segments[1];
120-
const signatureSegment = segments[2];
12187

12288
const [success, payload] = pcall(() => {
12389
return {
124-
header: HttpService.JSONDecode(base64urlDecode(headerSegment)) as { alg: string; typ: string },
125-
body: HttpService.JSONDecode(base64urlDecode(payloadSegment)) as {
90+
header: HttpService.JSONDecode(decode(headerSegment)) as { alg: string; typ: string },
91+
body: HttpService.JSONDecode(decode(payloadSegment)) as {
12692
exp: number;
12793
iat: number;
12894
nbf: number;
12995
[key: string]: unknown;
13096
},
131-
signature: base64urlDecode(signatureSegment),
13297
};
13398
});
13499

135100
if (!success) {
136101
error("failed to decode JWT");
137102
}
138103

139-
if (verify) {
104+
if (verify && key) {
140105
verifyJWT(data, key, true);
141106
}
142107

@@ -152,7 +117,7 @@ function verifyJWT(data: string, key: string, throwErrors: boolean | undefined =
152117
error("key must be a string");
153118
}
154119

155-
const segments = tokenize(data, ".", 3);
120+
const segments = data.split(".");
156121

157122
if (segments.size() !== 3) {
158123
if (throwErrors) error("not enough or too many segments");
@@ -164,8 +129,8 @@ function verifyJWT(data: string, key: string, throwErrors: boolean | undefined =
164129
const payloadSegment = segments[1];
165130
const signatureSegment = segments[2];
166131

167-
const header = HttpService.JSONDecode(base64urlDecode(headerSegment)) as { alg: string; typ: string };
168-
const body = HttpService.JSONDecode(base64urlDecode(payloadSegment)) as { exp: number; iat: number; nbf: number };
132+
const header = HttpService.JSONDecode(decode(headerSegment)) as { alg: string; typ: string };
133+
const body = HttpService.JSONDecode(decode(payloadSegment)) as { exp: number; iat: number; nbf: number };
169134

170135
if (!header.typ || header.typ !== "JWT") {
171136
if (throwErrors) error("typ must be JWT");

wally.lock

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ registry = "test"
44

55
[[package]]
66
name = "metrik-tech/jwt"
7-
version = "0.1.1"
7+
version = "0.2.0"
88
dependencies = []

wally.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "metrik-tech/jwt"
3-
version = "0.1.1"
3+
version = "0.2.0"
44
license = "AGPL-3.0-or-later"
55
authors = ["cursecodes"]
66
registry = "https://github.com/UpliftGames/wally-index"

0 commit comments

Comments
 (0)