@gcoredev/as-jwt 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -34
- package/assembly/index.ts +16 -9
- package/assembly/sha256/as-sha256.ts +257 -0
- package/assembly/sha256/index.ts +50 -0
- package/assembly/utils.ts +22 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# as-jwt
|
|
2
2
|
|
|
3
|
+
[](https://github.com/G-Core/as-jwt)
|
|
4
|
+
[](https://github.com/G-Core/as-jwt)
|
|
5
|
+
[](https://github.com/G-Core/as-jwt)
|
|
6
|
+
[](https://github.com/G-Core/as-jwt/blob/main/LICENSE)
|
|
7
|
+
[](https://www.npmjs.com/package/@gcoredev/as-jwt)
|
|
8
|
+
|
|
3
9
|
AssemblyScript package that provides simple jws handling for jwt tokens.
|
|
4
10
|
|
|
5
11
|
## Installation:
|
|
@@ -43,43 +49,10 @@ Validates `token` signature has been signed with a valid `secret`.
|
|
|
43
49
|
|
|
44
50
|
Does NOT validate any claims in the payload.
|
|
45
51
|
|
|
46
|
-
## Known Issues
|
|
47
|
-
|
|
48
|
-
At present there are some issues with JWS tokens signed using SHA256.
|
|
49
|
-
|
|
50
|
-
A basic token containing:
|
|
51
|
-
|
|
52
|
-
```json
|
|
53
|
-
{
|
|
54
|
-
"alg": "HS256",
|
|
55
|
-
"typ": "JWT"
|
|
56
|
-
}.{
|
|
57
|
-
"sub": "1234567890",
|
|
58
|
-
"name": "John Doe",
|
|
59
|
-
"iat": 1516239022
|
|
60
|
-
}
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
Will `pass` compactVerify(), however adding an extra field like `exp` value will cause it to fail. Claim payloads with more than 3 entries fails `SHA256` hashing. This is **NOT** a problem with `SHA512` and we would advise to use this at present.
|
|
64
|
-
|
|
65
|
-
It is possible to still use verifyJwt() with `SHA256` however you will need to keep to max 3 claims. e.g.
|
|
66
|
-
|
|
67
|
-
```json
|
|
68
|
-
{
|
|
69
|
-
"alg": "HS256",
|
|
70
|
-
"typ": "JWT"
|
|
71
|
-
}.{
|
|
72
|
-
"exp": 2051226061,
|
|
73
|
-
"name": "John Doe",
|
|
74
|
-
"iat": 1516239022
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
Issue: https://github.com/jedisct1/as-hmac-sha2/issues/4
|
|
79
|
-
|
|
80
52
|
### Internal Libraries:
|
|
81
53
|
|
|
82
54
|
Under the hood this package is powered by:
|
|
83
55
|
|
|
84
56
|
- [as-hmac-sha2](https://github.com/jedisct1/as-hmac-sha2)
|
|
85
57
|
- [as-base64](https://github.com/near/as-base64)
|
|
58
|
+
- [as-sha256](https://github.com/ChainSafe/as-sha256)
|
package/assembly/index.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { JSON } from "assemblyscript-json/assembly";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import { Sha512, verify } from "../modules/as-hmac-sha2/assembly";
|
|
4
|
+
|
|
5
|
+
import { sha256Hmac } from "./sha256";
|
|
6
|
+
import { decodeBase64, isValidJsonObj } from "./utils";
|
|
5
7
|
|
|
6
8
|
enum JwtValidation {
|
|
7
9
|
Ok = 0,
|
|
@@ -19,9 +21,12 @@ function compactVerify(token: string, secret: string): JwtValidation {
|
|
|
19
21
|
|
|
20
22
|
// Decode the JWT token
|
|
21
23
|
const header = decodeBase64(parts[0]);
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
const headerStr = String.UTF8.decode(header.buffer);
|
|
25
|
+
if (!isValidJsonObj(headerStr)) {
|
|
26
|
+
return JwtValidation.BadToken;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const jsonHeaderObj: JSON.Obj = <JSON.Obj>JSON.parse(headerStr);
|
|
25
30
|
|
|
26
31
|
const algOrNull: JSON.Str | null = jsonHeaderObj.getString("alg");
|
|
27
32
|
if (algOrNull == null) {
|
|
@@ -38,7 +43,7 @@ function compactVerify(token: string, secret: string): JwtValidation {
|
|
|
38
43
|
const secretUint8Array = Uint8Array.wrap(String.UTF8.encode(secret));
|
|
39
44
|
const expectedSignature =
|
|
40
45
|
alg === "HS256"
|
|
41
|
-
?
|
|
46
|
+
? sha256Hmac(dataUint8Array, secretUint8Array)
|
|
42
47
|
: Sha512.hmac(dataUint8Array, secretUint8Array);
|
|
43
48
|
const providedSignature = decodeBase64(parts[2]);
|
|
44
49
|
|
|
@@ -59,9 +64,11 @@ function jwtVerify(token: string, secret: string): JwtValidation {
|
|
|
59
64
|
|
|
60
65
|
// Decode the JWT token
|
|
61
66
|
const payload = decodeBase64(parts[1]);
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
const payloadStr = String.UTF8.decode(payload.buffer);
|
|
68
|
+
if (!isValidJsonObj(payloadStr)) {
|
|
69
|
+
return JwtValidation.BadToken;
|
|
70
|
+
}
|
|
71
|
+
const jsonClaimsObj: JSON.Obj = <JSON.Obj>JSON.parse(payloadStr);
|
|
65
72
|
|
|
66
73
|
// RFC 7519 states that the exp , nbf and iat claim values must be NumericDate values.
|
|
67
74
|
const expOrNull: JSON.Integer | null = jsonClaimsObj.getInteger("exp");
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The code in this file is from https://github.com/ChainSafe/as-sha256/blob/master/assembly/index.ts
|
|
3
|
+
* Copyright 2019 ChainSafe Systems
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
*
|
|
8
|
+
* All modifcations have been noted within the code.
|
|
9
|
+
*
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// constants used in the SHA256 compression function
|
|
13
|
+
const K: u32[] = [
|
|
14
|
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b,
|
|
15
|
+
0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01,
|
|
16
|
+
0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7,
|
|
17
|
+
0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
|
18
|
+
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152,
|
|
19
|
+
0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
|
20
|
+
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
|
|
21
|
+
0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
|
22
|
+
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819,
|
|
23
|
+
0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08,
|
|
24
|
+
0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f,
|
|
25
|
+
0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
|
26
|
+
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
|
27
|
+
];
|
|
28
|
+
const kPtr = K.dataStart;
|
|
29
|
+
|
|
30
|
+
// intermediate hash values stored in H0-H7
|
|
31
|
+
var H0: u32, H1: u32, H2: u32, H3: u32, H4: u32, H5: u32, H6: u32, H7: u32;
|
|
32
|
+
|
|
33
|
+
// hash registers
|
|
34
|
+
var a: u32, b: u32, c: u32, d: u32, e: u32, f: u32, g: u32, h: u32, i: u32, t1: u32, t2: u32;
|
|
35
|
+
|
|
36
|
+
// 16 32bit message blocks
|
|
37
|
+
const M = new ArrayBuffer(64);
|
|
38
|
+
const mPtr = changetype<usize>(M);
|
|
39
|
+
|
|
40
|
+
// 64 32bit extended message blocks
|
|
41
|
+
const W = new ArrayBuffer(256);
|
|
42
|
+
const wPtr = changetype<usize>(W);
|
|
43
|
+
|
|
44
|
+
// number of bytes in M buffer
|
|
45
|
+
var mLength = 0;
|
|
46
|
+
|
|
47
|
+
// number of total bytes hashed
|
|
48
|
+
var bytesHashed = 0;
|
|
49
|
+
|
|
50
|
+
@inline
|
|
51
|
+
function load32(ptr: usize, offset: usize): u32 {
|
|
52
|
+
return load<u32>(ptr + (offset << alignof<u32>()));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@inline
|
|
56
|
+
function load32be(ptr: usize, offset: usize): u32 {
|
|
57
|
+
const firstOffset = offset << alignof<u32>();
|
|
58
|
+
return (
|
|
59
|
+
(<u32>load8(ptr, firstOffset + 0) << 24) |
|
|
60
|
+
(<u32>load8(ptr, firstOffset + 1) << 16) |
|
|
61
|
+
(<u32>load8(ptr, firstOffset + 2) << 8) |
|
|
62
|
+
(<u32>load8(ptr, firstOffset + 3) << 0)
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@inline
|
|
67
|
+
function store32(ptr: usize, offset: usize, u: u32): void {
|
|
68
|
+
store<u32>(ptr + (offset << alignof<u32>()), u);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@inline
|
|
72
|
+
function store8(ptr: usize, offset: usize, u: u8): void {
|
|
73
|
+
store<u8>(ptr + offset, u);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@inline
|
|
77
|
+
function load8(ptr: usize, offset: usize): u8 {
|
|
78
|
+
return load<u8>(ptr + offset);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@inline
|
|
82
|
+
function fill(ptr: usize, value: u8, length: u32): void {
|
|
83
|
+
const finalPtr = ptr + length;
|
|
84
|
+
while(ptr < finalPtr) {
|
|
85
|
+
store<u8>(ptr, value);
|
|
86
|
+
ptr++;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@inline
|
|
91
|
+
function CH(x: u32, y: u32, z: u32): u32 {
|
|
92
|
+
return((x & y) ^ (~x & z));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
@inline
|
|
96
|
+
function MAJ(x: u32, y: u32, z:u32): u32 {
|
|
97
|
+
return ((x & y) ^ (x & z) ^ (y & z));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@inline
|
|
101
|
+
function EP0(x: u32): u32 {
|
|
102
|
+
return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@inline
|
|
106
|
+
function EP1(x: u32): u32 {
|
|
107
|
+
return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@inline
|
|
111
|
+
function SIG0(x: u32): u32 {
|
|
112
|
+
return rotr(x, 7) ^ rotr(x, 18) ^ (x >>> 3);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
@inline
|
|
116
|
+
function SIG1(x: u32): u32 {
|
|
117
|
+
return rotr(x, 17) ^ rotr(x, 19) ^ (x >>> 10);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Expand message blocks (16 32bit blocks), into extended message blocks (64 32bit blocks),
|
|
122
|
+
* Apply SHA256 compression function on extended message blocks
|
|
123
|
+
* Update intermediate hash values
|
|
124
|
+
* @param wPtr pointer to expanded message block memory
|
|
125
|
+
* @param mPtr pointer to message block memory, pass 0 if wPtr is precomputed for e.g. in digest64
|
|
126
|
+
*/
|
|
127
|
+
function hashBlocks(wPtr: usize, mPtr: usize): void {
|
|
128
|
+
a = H0;
|
|
129
|
+
b = H1;
|
|
130
|
+
c = H2;
|
|
131
|
+
d = H3;
|
|
132
|
+
e = H4;
|
|
133
|
+
f = H5;
|
|
134
|
+
g = H6;
|
|
135
|
+
h = H7;
|
|
136
|
+
|
|
137
|
+
// Load message blocks into first 16 expanded message blocks
|
|
138
|
+
for (i = 0; i < 16; i++) {
|
|
139
|
+
store32(wPtr, i, load32be(mPtr, i));
|
|
140
|
+
}
|
|
141
|
+
// Expand message blocks 17-64
|
|
142
|
+
for (i = 16; i < 64; i++) {
|
|
143
|
+
store32(
|
|
144
|
+
wPtr,
|
|
145
|
+
i,
|
|
146
|
+
SIG1(load32(wPtr, i - 2)) +
|
|
147
|
+
load32(wPtr, i - 7) +
|
|
148
|
+
SIG0(load32(wPtr, i - 15)) +
|
|
149
|
+
load32(wPtr, i - 16)
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Apply SHA256 compression function on expanded message blocks
|
|
154
|
+
for (i = 0; i < 64; i++) {
|
|
155
|
+
t1 = h + EP1(e) + CH(e, f, g) + load32(kPtr, i) + load32(wPtr, i);
|
|
156
|
+
t2 = EP0(a) + MAJ(a, b, c);
|
|
157
|
+
h = g;
|
|
158
|
+
g = f;
|
|
159
|
+
f = e;
|
|
160
|
+
e = d + t1;
|
|
161
|
+
d = c;
|
|
162
|
+
c = b;
|
|
163
|
+
b = a;
|
|
164
|
+
a = t1 + t2;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
H0 += a;
|
|
168
|
+
H1 += b;
|
|
169
|
+
H2 += c;
|
|
170
|
+
H3 += d;
|
|
171
|
+
H4 += e;
|
|
172
|
+
H5 += f;
|
|
173
|
+
H6 += g;
|
|
174
|
+
H7 += h;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export function init(): void {
|
|
178
|
+
H0 = 0x6a09e667;
|
|
179
|
+
H1 = 0xbb67ae85;
|
|
180
|
+
H2 = 0x3c6ef372;
|
|
181
|
+
H3 = 0xa54ff53a;
|
|
182
|
+
H4 = 0x510e527f;
|
|
183
|
+
H5 = 0x9b05688c;
|
|
184
|
+
H6 = 0x1f83d9ab;
|
|
185
|
+
H7 = 0x5be0cd19;
|
|
186
|
+
|
|
187
|
+
mLength = 0;
|
|
188
|
+
bytesHashed = 0;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function update(dataPtr: usize, dataLength: i32): void {
|
|
192
|
+
let dataPos = 0;
|
|
193
|
+
bytesHashed += dataLength;
|
|
194
|
+
// If message blocks buffer has data, fill to 64
|
|
195
|
+
if (mLength) {
|
|
196
|
+
if (64 - mLength <= dataLength) {
|
|
197
|
+
// we can fully fill the buffer with data left over
|
|
198
|
+
memory.copy(mPtr + mLength, dataPtr, 64 - mLength);
|
|
199
|
+
mLength += 64 - mLength;
|
|
200
|
+
dataPos += 64 - mLength;
|
|
201
|
+
dataLength -= 64 - mLength;
|
|
202
|
+
hashBlocks(wPtr, mPtr);
|
|
203
|
+
mLength = 0;
|
|
204
|
+
} else {
|
|
205
|
+
// we can't fully fill the buffer but we exhaust the whole data buffer
|
|
206
|
+
memory.copy(mPtr + mLength, dataPtr, dataLength);
|
|
207
|
+
mLength += dataLength;
|
|
208
|
+
dataPos += dataLength;
|
|
209
|
+
dataLength -= dataLength;
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
// If input has remaining 64-byte chunks, hash those
|
|
214
|
+
for (let i = 0; i < dataLength / 64; i++, dataPos += 64) {
|
|
215
|
+
hashBlocks(wPtr, dataPtr + dataPos);
|
|
216
|
+
}
|
|
217
|
+
// If any additional bytes remain, copy into message blocks buffer
|
|
218
|
+
if (dataLength & 63) {
|
|
219
|
+
const frac = dataLength & 63;
|
|
220
|
+
memory.copy(mPtr + mLength, dataPtr + dataPos, dataLength & 63);
|
|
221
|
+
mLength += dataLength & 63;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export function final(outPtr: usize): void {
|
|
226
|
+
// one additional round of hashes required
|
|
227
|
+
// because padding will not fit
|
|
228
|
+
if ((bytesHashed & 63) <= 63) { //! @gcoredev: This line has been modified from the original (message bodies of length 127 failed)
|
|
229
|
+
store8(mPtr, mLength, 0x80);
|
|
230
|
+
mLength++;
|
|
231
|
+
}
|
|
232
|
+
if ((bytesHashed & 63) >= 56) {
|
|
233
|
+
fill(mPtr + mLength, 0, 64 - mLength);
|
|
234
|
+
hashBlocks(wPtr, mPtr);
|
|
235
|
+
mLength = 0;
|
|
236
|
+
}
|
|
237
|
+
if ((bytesHashed & 63) > 63) { //! @gcoredev: This line has been modified from the original (message bodies of length 127 failed)
|
|
238
|
+
store8(mPtr, mLength, 0x80);
|
|
239
|
+
mLength++;
|
|
240
|
+
}
|
|
241
|
+
fill(mPtr + mLength, 0, 64 - mLength - 8);
|
|
242
|
+
|
|
243
|
+
store<u32>(mPtr + 64 - 8, bswap(bytesHashed / 0x20000000)); // length -- high bits
|
|
244
|
+
store<u32>(mPtr + 64 - 4, bswap(bytesHashed << 3)); // length -- low bits
|
|
245
|
+
|
|
246
|
+
// hash round for padding
|
|
247
|
+
hashBlocks(wPtr, mPtr);
|
|
248
|
+
|
|
249
|
+
store32(outPtr, 0, bswap(H0));
|
|
250
|
+
store32(outPtr, 1, bswap(H1));
|
|
251
|
+
store32(outPtr, 2, bswap(H2));
|
|
252
|
+
store32(outPtr, 3, bswap(H3));
|
|
253
|
+
store32(outPtr, 4, bswap(H4));
|
|
254
|
+
store32(outPtr, 5, bswap(H5));
|
|
255
|
+
store32(outPtr, 6, bswap(H6));
|
|
256
|
+
store32(outPtr, 7, bswap(H7));
|
|
257
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { final, init, update } from "./as-sha256";
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* The code in this file is largely based on https://github.com/jedisct1/as-hmac-sha2
|
|
5
|
+
* which is licensed under the ISC license.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** This function is a direct copy of the one in as-hmac-sha2 */
|
|
10
|
+
function setU8(t: Uint8Array, s: Uint8Array, o: isize = 0): void {
|
|
11
|
+
memory.copy(t.dataStart + o, s.dataStart, s.length);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* This function is based on the one in as-hmac-sha2, but has been modified to use the crypto functions in as-sha256.
|
|
16
|
+
* HMAC-SHA-256
|
|
17
|
+
* @param m Message
|
|
18
|
+
* @param k Key
|
|
19
|
+
* @returns `HMAC-SHA-256(m, k)`
|
|
20
|
+
*/
|
|
21
|
+
function sha256Hmac(m: Uint8Array, k: Uint8Array): Uint8Array {
|
|
22
|
+
if (k.length > 64) {
|
|
23
|
+
// k = Sha256.hash(k); todo: should become??
|
|
24
|
+
// init()
|
|
25
|
+
// update()
|
|
26
|
+
// final()
|
|
27
|
+
}
|
|
28
|
+
let b = new Uint8Array(64);
|
|
29
|
+
setU8(b, k);
|
|
30
|
+
for (let i = 0; i < b.length; ++i) {
|
|
31
|
+
b[i] ^= 0x36;
|
|
32
|
+
}
|
|
33
|
+
let out = new Uint8Array(32);
|
|
34
|
+
init();
|
|
35
|
+
update(b.dataStart, b.length);
|
|
36
|
+
update(m.dataStart, m.length);
|
|
37
|
+
final(out.dataStart);
|
|
38
|
+
|
|
39
|
+
for (let i = 0; i < b.length; ++i) {
|
|
40
|
+
b[i] ^= 0x6a;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
init();
|
|
44
|
+
update(b.dataStart, b.length);
|
|
45
|
+
update(out.dataStart, out.length);
|
|
46
|
+
final(out.dataStart);
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export { sha256Hmac };
|
package/assembly/utils.ts
CHANGED
|
@@ -28,4 +28,25 @@ function decodeBase64(input: string): Uint8Array {
|
|
|
28
28
|
return decode(base64);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
function isValidJsonObj(str: string): boolean {
|
|
32
|
+
if (str.charAt(0) !== "{" || str.charAt(str.length - 1) !== "}") {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
let brackets = 0;
|
|
36
|
+
let braces = 0;
|
|
37
|
+
for (let i = 0; i < str.length; i++) {
|
|
38
|
+
const char = str.charAt(i);
|
|
39
|
+
if (char === "[") {
|
|
40
|
+
brackets += 1;
|
|
41
|
+
} else if (char === "]") {
|
|
42
|
+
brackets -= 1;
|
|
43
|
+
} else if (char === "{") {
|
|
44
|
+
braces += 1;
|
|
45
|
+
} else if (char === "}") {
|
|
46
|
+
braces -= 1;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return brackets === 0 && braces === 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export { decodeBase64, encodeBase64, isValidJsonObj };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gcoredev/as-jwt",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "AssemblyScript package that provides simple jws handling for jwt tokens/",
|
|
5
5
|
"main": "assembly/index.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"registry": "https://registry.npmjs.org/"
|
|
31
31
|
},
|
|
32
32
|
"files": [
|
|
33
|
-
"assembly
|
|
33
|
+
"assembly/**/*.*",
|
|
34
34
|
"modules/as-base64/assembly",
|
|
35
35
|
"modules/as-base64/README.md",
|
|
36
36
|
"modules/as-base64/package.json",
|