1- property _header : Object
2- property _payload : Object
3- property _cryptoKey : 4D.CryptoKey
1+ property key : 4D.CryptoKey
42
53Class constructor ($inParam : Variant)
64
7- This ._header := {}
8- This ._payload := {}
5+ This .key := This ._getCryptoKey ($inParam )
96
7+
8+ // Mark: - [Private]
9+ // ----------------------------------------------------
10+
11+
12+ Function _getCryptoKey ($inKey : Variant; $inDefaultKey : 4D.CryptoKey) : 4D.CryptoKey
13+
14+ var $key : 4D.CryptoKey
1015 Case of
11- : ((Value type ($inParam )= Is object) && OB Instance of ($inParam ; 4D.CryptoKey))
12- This . _cryptoKey := $inParam
16+ : ((Value type ($inKey )= Is object) && OB Instance of ($inKey ; 4D.CryptoKey))
17+ $key := $inKey // Use specified CryptoKey object
1318
14- : ((Value type ($inParam )= Is text) && (Length (String ($inParam ))> 0))
15- This . _cryptoKey := Try (4D.CryptoKey.new({type: "PEM"; pem: $inParam })) // Use specified PEM format Key
19+ : ((Value type ($inKey )= Is text) && (Length (String ($inKey ))> 0))
20+ $key := Try (4D.CryptoKey.new({type: "PEM"; pem: $inKey })) // Use specified PEM format Key
1621
1722 Else
18- This . _cryptoKey := Null
23+ $key := Null
1924 End case
2025
26+ // If no valid key provided, use default key if provided
27+ If (($key= Null) && ((Value type ($inDefaultKey )= Is object) && (OB Instance of ($inDefaultKey ; 4D.CryptoKey))))
28+ $key := $inDefaultKey
29+ End if
30+
31+ return $key
32+
33+
2134 // Mark: - [Public]
2235 // ----------------------------------------------------
2336
2437
2538Function decode ($inToken : Text) : Object
2639
40+ var $header : Object:= Null
41+ var $payload : Object:= Null
42+ var signature : Text
43+
2744 Case of
2845 : ((Value type ($inToken )# Is text) || (Length (String ($inToken ))= 0))
2946 This ._throwError (9 ; {which: "\" $inToken\" " ; function: "JWT.decode" })
@@ -32,25 +49,24 @@ Function decode($inToken : Text) : Object
3249 var $parts : Collection:= Split string ($inToken ; "." )
3350
3451 If ($parts .length > 2)
35- var $header ; $payload ; $signature : Text
36- BASE64 DECODE ($parts [0 ]; $header ; * )
37- BASE64 DECODE ($parts [1 ]; $payload ; * )
52+ var $decodedHeader ; $decodedPayload ; $signature : Text
53+ BASE64 DECODE ($parts [0 ]; $decodedHeader ; * )
54+ BASE64 DECODE ($parts [1 ]; $decodedPayload ; * )
3855 $signature := $parts [2 ]
3956
4057 // Note: If JSON parsing fails, Try(JSON Parse(...)) will return Null for header or payload.
41- This ._header := Try (JSON Parse ($header ))
42- This ._payload := Try (JSON Parse ($payload ))
43- return {header: This ._header ; payload: This ._payload ; signature: $signature }
58+ $header := Try (JSON Parse ($decodedHeader ))
59+ $payload := Try (JSON Parse ($decodedPayload ))
4460 End if
4561 End case
4662
47- return {header: Null ; payload: Null }
63+ return {header: $header ; payload: $payload ; signature: $signature }
4864
4965
5066 // ----------------------------------------------------
5167
5268
53- Function generate ($inParams : Object; $inPrivateKey : Text ) : Text
69+ Function generate ($inParams : Object; $inKey : Variant ) : Text
5470
5571 var $result : Text:= ""
5672
@@ -63,46 +79,50 @@ Function generate($inParams : Object; $inPrivateKey : Text) : Text
6379 var $typ : Text:= ((Value type ($inParams .header .typ )= Is text) && (Length ($inParams .header .typ )> 0)) ? $inParams .header .typ : "JWT"
6480 var $x5t : Text:= (Value type ($inParams .header .x5t )= Is text) ? $inParams .header .x5t : ""
6581
66- This . _header := ((Value type ($inParams .header )= Is object) && Not (OB Is empty ($inParams .header ))) ? $inParams .header : {}
67- This . _payload := ((Value type ($inParams .payload )= Is object) && Not (OB Is empty ($inParams .payload ))) ? $inParams .payload : {}
82+ var $header : Object := ((Value type ($inParams .header )= Is object) && Not (OB Is empty ($inParams .header ))) ? $inParams .header : {}
83+ var $payload : Object := ((Value type ($inParams .payload )= Is object) && Not (OB Is empty ($inParams .payload ))) ? $inParams .payload : {}
6884
69- If (Value type (This . _header .alg )= Is undefined)
70- This . _header .alg := $alg
85+ If (Value type ($header .alg )= Is undefined)
86+ $header .alg := $alg
7187 End if
72- If (Value type (This . _header .typ )= Is undefined)
73- This . _header .typ := $typ
88+ If (Value type ($header .typ )= Is undefined)
89+ $header .typ := $typ
7490 End if
75- If ((Value type (This . _header .x5t )= Is undefined) && (Length ($x5t )> 0))
76- This . _header .x5t := $x5t
91+ If ((Value type ($header .x5t )= Is undefined) && (Length ($x5t )> 0))
92+ $header .x5t := $x5t
7793 End if
7894
79- var $header ; $payload ; $signature : Text
95+ var $encodedHeader ; $encodedPayload ; $signature : Text
8096
8197 // Encode the Header and Payload
82- BASE64 ENCODE (JSON Stringify (This . _header ); $header ; * )
83- BASE64 ENCODE (JSON Stringify (This . _payload ); $payload ; * )
98+ BASE64 ENCODE (JSON Stringify ($header ); $encodedHeader ; * )
99+ BASE64 ENCODE (JSON Stringify ($payload ); $encodedPayload ; * )
84100
85101 // Parse Header for Algorithm Family
86- var $algorithm : Text:= This ._header .alg
102+ var $algorithm : Text:= $header .alg
103+ var $webToken : Object:= {header: $header ; payload: $payload }
104+ var $cryptoKey : 4D.CryptoKey:= Null
105+ var $key : Text:= ""
106+ If (Value type ($inKey )= Is text) && (Length (String ($inKey ))> 0)
107+ $key := $inKey
108+ End if
87109
88110 // Generate Verify Signature Hash based on Algorithm
89111 If ($algorithm= "HS@")
90- If ((Value type ($inPrivateKey )# Is text) || (Length (String ($inPrivateKey ))= 0))
91- This ._throwError (9 ; {which: "\" $inPrivateKey\" " ; function: "JWT.generate" })
92- Else
93- $signature := This ._hashHS (This ; $inPrivateKey ) // HMAC Hash
94- End if
112+ $signature := This ._hashHS ($webToken ; $key ) // HMAC Hash
95113 Else
96- If ((This ._cryptoKey = Null) && ((Value type ($inPrivateKey )# Is text) || (Length (String ($inPrivateKey ))= 0)))
97- This ._throwError (9 ; {which: "\" $inPrivateKey\" " ; function: "JWT.generate" })
114+ $cryptoKey := This ._getCryptoKey ($inKey ; This .key)
115+ If ($cryptoKey# Null)
116+ $signature := This ._hashSign ($webToken ; $cryptoKey ) // All other Hashes
98117 Else
99- $signature := This ._hashSign ( This ; $inPrivateKey ) // All other Hashes
118+ This ._throwError ( 15 ) // The private or public key doesn't seem to be valid PEM.
100119 End if
101120 End if
102121
103122 // Combine Encoded Header and Payload with Hashed Signature for the Token
104- $result := $header + "." + $payload + "." + $signature
105-
123+ If (Length ($signature )> 0)
124+ $result := $encodedHeader + "." + $encodedPayload + "." + $signature
125+ End if
106126 End case
107127
108128 return $result
@@ -111,7 +131,9 @@ Function generate($inParams : Object; $inPrivateKey : Text) : Text
111131 // ----------------------------------------------------
112132
113133
114- Function validate ($inJWT : Text; $inKey : Text) : Boolean
134+ Function validate ($inJWT : Text; $inKey : Variant) : Boolean
135+
136+ var $success : Boolean:= False
115137
116138 Case of
117139 : ((Value type ($inJWT )# Is text) || (Length (String ($inJWT ))= 0))
@@ -124,68 +146,57 @@ Function validate($inJWT : Text; $inKey : Text) : Boolean
124146 If ($parts .length > 2)
125147
126148 var $header ; $payload ; $signature : Text
127- var $key : Text:= ((Value type ($inKey )= Is text) && (Length ($inKey )> 0)) ? $inKey : ""
149+ var $cryptoKey : 4D.CryptoKey:= Null
150+ var $key : Text:= ""
151+ If (Value type ($inKey )= Is text) && (Length (String ($inKey ))> 0)
152+ $key := $inKey
153+ End if
128154
129155 // Decode Header and Payload into Objects
130156 BASE64 DECODE ($parts [0 ]; $header ; * )
131157 BASE64 DECODE ($parts [1 ]; $payload ; * )
132- var $jwt : Object:= {_header : Try (JSON Parse ($header )); _payload : Try (JSON Parse ($payload ))}
158+ var $webToken : Object:= {header : Try (JSON Parse ($header )); payload : Try (JSON Parse ($payload ))}
133159
134- If (OB Is empty (This ._header ))
135- This ._header := $jwt ._header
136- End if
137- If (OB Is empty (This ._payload ))
138- This ._payload := $jwt ._payload
139- End if
140-
141- var $algorithm : Text:= This ._header .alg
160+ var $algorithm : Text:= $webToken .header .alg
142161 If ($algorithm= "HS@")
143- If ((Value type ($inKey )# Is text) || (Length (String ($inKey ))= 0))
144- This ._throwError (9 ; {which: "\" $inKey\" " ; function: "JWT.validate" })
145- Else
146- $signature := This ._hashHS ($jwt ; $key ) // HMAC Hash
147- return ($signature= $parts[2 ])
148- End if
162+ $signature := This ._hashHS ($webToken ; $key ) // HMAC Hash
163+ $success := ($signature= $parts[2 ])
149164 Else
150- If ((This ._cryptoKey = Null) && ((Value type ($inKey )# Is text) || (Length (String ($inKey ))= 0)))
151- This ._throwError (9 ; {which: "\" $inKey\" " ; function: "JWT.validate" })
165+ $cryptoKey := This ._getCryptoKey ($inKey ; This .key)
166+ If ($cryptoKey# Null)
167+ var $status : Object
168+ var $message : Text:= $parts [0 ]+ "." + $parts [1 ]
169+ var $options : Object:= {hash: (Substring ($webToken .header .alg ; 3 )= "256") ? SHA256 digest : SHA512 digest; pss: Bool ($webToken .header .alg = "PS@" ); encoding: "Base64URL" }
170+ $signature := $parts [2 ]
171+ $status := $cryptoKey .verify ($message ; $signature ; $options )
172+ $success := $status .success
152173 Else
153- // Prepare CryptoKey settings
154- If ((Value type ($inKey )= Is text) && (Length (String ($inKey ))> 0))
155- This ._cryptoKey := Try (4D.CryptoKey.new({type: "PEM"; pem: $key})) // Use specified PEM format Key
156- End if
157- If (This ._cryptoKey = Null)
158- This ._throwError (15 ) // The private or public key doesn't seem to be valid PEM.
159- Else
160- var $result : Object:= This ._cryptoKey .verify (String ($parts [0 ]+ "." + $parts [1 ]); $parts [2 ]; {hash: (Substring ($jwt ._header .alg ; 3 )= "256") ? SHA256 digest : SHA512 digest; pss: Bool ($jwt ._header .alg = "PS@" ); encoding: "Base64URL" })
161- return Bool ($result .success )
162- End if
174+ This ._throwError (15 ) // The private or public key doesn't seem to be valid PEM.
163175 End if
164176 End if
165-
166177 End if
167178 End case
168179
169- return False
180+ return $success
170181
171182
172183 // Mark: - [Private]
173184 // ----------------------------------------------------
174185
175186
176- Function _hashHS ($inJWT : cs . NetKit . JWT ; $inPrivateKey : Text) : Text
187+ Function _hashHS ($inJWT : Object ; $inPrivateKey : Text) : Text
177188
178189 var $encodedHeader ; $encodedPayload : Text
179190 var $headerBlob ; $payloadBlob ; $intermediateBlob ; $privateBlob ; $dataBlob : Blob
180191 var $blockSize ; $i ; $byte ; $hashAlgorithm : Integer
181192
182193 // Encode Header and Payload to build Message in Blob format
183- BASE64 ENCODE (JSON Stringify ($inJWT ._header ); $encodedHeader ; * )
184- BASE64 ENCODE (JSON Stringify ($inJWT ._payload ); $encodedPayload ; * )
194+ BASE64 ENCODE (JSON Stringify ($inJWT .header ); $encodedHeader ; * )
195+ BASE64 ENCODE (JSON Stringify ($inJWT .payload ); $encodedPayload ; * )
185196 TEXT TO BLOB ($encodedHeader + "." + $encodedPayload ; $dataBlob ; UTF8 text without length)
186197
187198 // Parse Hashing Algorithm From Header
188- var $algorithm : Text:= Substring ($inJWT ._header .alg ; 3 )
199+ var $algorithm : Text:= Substring ($inJWT .header .alg ; 3 )
189200 If ($algorithm= "256")
190201 $hashAlgorithm := SHA256 digest
191202 $blockSize := 64
@@ -235,40 +246,38 @@ Function _hashHS($inJWT : cs.NetKit.JWT; $inPrivateKey : Text) : Text
235246 // ----------------------------------------------------
236247
237248
238- Function _hashSign ($inJWT : cs . NetKit . JWT ; $inPrivateKey : Text ) : Text
249+ Function _hashSign ($inJWT : Object ; $inCryptoKey : 4D.CryptoKey ) : Text
239250
240251 var $hash : Text
241252
242- If ((This ._cryptoKey = Null) && ((Value type ($inPrivateKey )# Is text) || (Length (String ($inPrivateKey ))= 0)))
243- This ._throwError (9 ; {which: "\" $inPrivateKey\" " ; function: "JWT.validate" })
253+ var $cryptoKey : 4D.CryptoKey:= Null
254+ If ((Value type ($inCryptoKey )= Is object) && (OB Instance of ($inCryptoKey ; 4D.CryptoKey)))
255+ $cryptoKey := $inCryptoKey
244256 Else
245- // Prepare CryptoKey settings
246- If (( Value type ( $inPrivateKey ) = Is text) && ( Length ( String ( $inPrivateKey )) > 0))
247- This . _cryptoKey := 4D.CryptoKey.new({type: "PEM"; pem: $inPrivateKey}) // Use specified PEM format Key
248- End if
257+ $cryptoKey := This . key
258+ End if
259+
260+ If ($cryptoKey # Null)
249261
250- If (This ._cryptoKey # Null)
251- var $encodedHead ; $encodedPayload : Text
252-
253- // Encode Header and Payload to build Message
254- BASE64 ENCODE (JSON Stringify ($inJWT ._header ); $encodedHead ; * )
255- BASE64 ENCODE (JSON Stringify ($inJWT ._payload ); $encodedPayload ; * )
256-
257- // Parse Header for Algorithm Family
258- var $algorithm : Text:= Substring ($inJWT ._header .alg ; 3 )
259- var $hashAlgorithm : Integer
260- If ($algorithm= "256")
261- $hashAlgorithm := SHA256 digest
262- Else
263- $hashAlgorithm := SHA512 digest
264- End if
265-
266- // Sign Message with CryptoKey to generate hashed verify signature
267- $hash := This ._cryptoKey .sign (String ($encodedHead + "." + $encodedPayload ); {hash: $hashAlgorithm ; pss: Bool ($inJWT ._header .alg = "PS@" ); encoding: "Base64URL" })
262+ var $encodedHead ; $encodedPayload : Text
263+
264+ // Encode Header and Payload to build Message
265+ BASE64 ENCODE (JSON Stringify ($inJWT .header ); $encodedHead ; * )
266+ BASE64 ENCODE (JSON Stringify ($inJWT .payload ); $encodedPayload ; * )
267+
268+ // Parse Header for Algorithm Family
269+ var $algorithm : Text:= Substring ($inJWT .header .alg ; 3 )
270+ var $hashAlgorithm : Integer
271+ If ($algorithm= "256")
272+ $hashAlgorithm := SHA256 digest
268273 Else
269- This . _throwError ( 15 ) // The private or public key doesn't seem to be valid PEM.
274+ $hashAlgorithm := SHA512 digest
270275 End if
271276
277+ // Sign Message with CryptoKey to generate hashed verify signature
278+ $hash := $cryptoKey .sign (String ($encodedHead + "." + $encodedPayload ); {hash: $hashAlgorithm ; pss: Bool ($inJWT .header .alg = "PS@" ); encoding: "Base64URL" })
279+ Else
280+ This ._throwError (15 ) // The private or public key doesn't seem to be valid PEM.
272281 End if
273282
274283 return $hash
@@ -283,4 +292,3 @@ Function _throwError($inCode : Integer; $inParameters : Object)
283292 var $error : Object:= cs .Tools .me .makeError ($inCode ; $inParameters )
284293 $error .deferred := True
285294 throw ($error)
286-
0 commit comments