tokx-cli 0.1.0
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/LICENSE +21 -0
- package/README.md +67 -0
- package/dist/api.d.ts +1 -0
- package/dist/api.js +8 -0
- package/dist/api.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +559 -0
- package/dist/index.js.map +1 -0
- package/package.json +73 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Hammad Khan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# tokx
|
|
2
|
+
|
|
3
|
+
JWT decode, encode, verify from your terminal.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g tokx-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Commands
|
|
12
|
+
|
|
13
|
+
### Decode
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
tokx decode <token>
|
|
17
|
+
tokx decode <token> --json
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Pretty-prints header + payload with color-coded JWT parts, claim status icons, and relative expiry time.
|
|
21
|
+
|
|
22
|
+
### Encode
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
tokx encode --secret <secret> --payload '{"sub":"123"}'
|
|
26
|
+
tokx encode --secret <secret> --payload '{"sub":"123"}' --algorithm HS512 --expires 3600
|
|
27
|
+
tokx encode --secret <secret> --payload '{"sub":"123"}' --json
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Verify
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
tokx verify <token> --secret <secret>
|
|
34
|
+
tokx verify <token> --secret <secret> --json
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Auto-detects algorithm from token header. Shows a verification badge.
|
|
38
|
+
|
|
39
|
+
### Libraries
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
tokx libs
|
|
43
|
+
tokx libs --language Python
|
|
44
|
+
tokx libs --algorithm EdDSA
|
|
45
|
+
tokx libs --json
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Exit Codes
|
|
49
|
+
|
|
50
|
+
| Code | Meaning |
|
|
51
|
+
|------|---------|
|
|
52
|
+
| 0 | Success |
|
|
53
|
+
| 1 | Invalid input |
|
|
54
|
+
| 2 | Verification failed |
|
|
55
|
+
| 3 | Internal error |
|
|
56
|
+
|
|
57
|
+
## Features
|
|
58
|
+
|
|
59
|
+
- Color-coded JWT parts (header=red, payload=purple, signature=cyan)
|
|
60
|
+
- Box-framed output for decoded header/payload
|
|
61
|
+
- Spinner for async operations
|
|
62
|
+
- `--json` flag on all commands for machine-readable output
|
|
63
|
+
- Respects `NO_COLOR` environment variable
|
|
64
|
+
|
|
65
|
+
## License
|
|
66
|
+
|
|
67
|
+
MIT
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { DecodedJwt, EncodeOptions, VerifyOptions, VerifyResult, decode, encode, verify } from '@tokx/core';
|
package/dist/api.js
ADDED
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/api.ts"],"sourcesContent":["export type { DecodedJwt, EncodeOptions, VerifyOptions, VerifyResult } from '@tokx/core';\nexport { decode, encode, verify } from '@tokx/core';\n"],"mappings":";AACA,SAAS,QAAQ,QAAQ,cAAc;","names":[]}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { readFileSync } from "fs";
|
|
5
|
+
import { program } from "commander";
|
|
6
|
+
|
|
7
|
+
// src/commands/decode.ts
|
|
8
|
+
import { decode } from "@tokx/core";
|
|
9
|
+
|
|
10
|
+
// src/ui/colors.ts
|
|
11
|
+
import pc from "picocolors";
|
|
12
|
+
var noColor = process.env.NO_COLOR !== void 0;
|
|
13
|
+
function wrap(fn) {
|
|
14
|
+
return noColor ? (s) => s : fn;
|
|
15
|
+
}
|
|
16
|
+
var c = {
|
|
17
|
+
red: wrap(pc.red),
|
|
18
|
+
green: wrap(pc.green),
|
|
19
|
+
yellow: wrap(pc.yellow),
|
|
20
|
+
blue: wrap(pc.blue),
|
|
21
|
+
cyan: wrap(pc.cyan),
|
|
22
|
+
magenta: wrap(pc.magenta),
|
|
23
|
+
gray: wrap(pc.gray),
|
|
24
|
+
bold: wrap(pc.bold),
|
|
25
|
+
dim: wrap(pc.dim)
|
|
26
|
+
};
|
|
27
|
+
function isTTY() {
|
|
28
|
+
return !noColor && process.stdout.isTTY === true;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// src/ui/animation.ts
|
|
32
|
+
function sleep(ms) {
|
|
33
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
34
|
+
}
|
|
35
|
+
async function playDecodeAnimation(token) {
|
|
36
|
+
if (!isTTY()) return;
|
|
37
|
+
const parts = token.split(".");
|
|
38
|
+
if (parts.length !== 3) return;
|
|
39
|
+
const frames = [
|
|
40
|
+
` ${c.dim(token.slice(0, 40))}${c.dim("...")}`,
|
|
41
|
+
` ${c.red(parts[0].slice(0, 12))}${c.dim("...")} ${c.dim("\xB7")} ${c.magenta(parts[1].slice(0, 12))}${c.dim("...")} ${c.dim("\xB7")} ${c.cyan(parts[2].slice(0, 12))}${c.dim("...")}`,
|
|
42
|
+
` ${c.red("\u25A0 header")} ${c.dim("\xB7")} ${c.magenta("\u25A0 payload")} ${c.dim("\xB7")} ${c.cyan("\u25A0 signature")}`
|
|
43
|
+
];
|
|
44
|
+
process.stdout.write("\n");
|
|
45
|
+
for (const frame of frames) {
|
|
46
|
+
process.stdout.write(`\r${frame}${" ".repeat(20)}`);
|
|
47
|
+
await sleep(120);
|
|
48
|
+
}
|
|
49
|
+
process.stdout.write("\n\n");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/ui/box.ts
|
|
53
|
+
function drawBox(title, content, color) {
|
|
54
|
+
const lines = content.split("\n");
|
|
55
|
+
const maxLen = Math.max(title.length + 4, ...lines.map((l) => l.length));
|
|
56
|
+
const width = Math.min(maxLen + 4, 60);
|
|
57
|
+
const top = color(` \u250C\u2500 ${title} ${"\u2500".repeat(Math.max(0, width - title.length - 5))}\u2510`);
|
|
58
|
+
const bottom = color(` \u2514${"\u2500".repeat(width - 1)}\u2518`);
|
|
59
|
+
const body = lines.map((line) => {
|
|
60
|
+
const padded = line.padEnd(width - 4);
|
|
61
|
+
return ` ${color("\u2502")} ${padded} ${color("\u2502")}`;
|
|
62
|
+
});
|
|
63
|
+
return [top, ...body, bottom].join("\n");
|
|
64
|
+
}
|
|
65
|
+
function drawBadge(text, color, icon) {
|
|
66
|
+
const inner = ` ${icon} ${text} `;
|
|
67
|
+
const width = inner.length + 2;
|
|
68
|
+
const top = color(` \u2554${"\u2550".repeat(width)}\u2557`);
|
|
69
|
+
const mid = color(` \u2551${inner}\u2551`);
|
|
70
|
+
const bottom = color(` \u255A${"\u2550".repeat(width)}\u255D`);
|
|
71
|
+
return `${top}
|
|
72
|
+
${mid}
|
|
73
|
+
${bottom}`;
|
|
74
|
+
}
|
|
75
|
+
function tokenBar(header, payload, signature) {
|
|
76
|
+
const total = 50;
|
|
77
|
+
const hLen = Math.max(
|
|
78
|
+
2,
|
|
79
|
+
Math.round(header.length / (header.length + payload.length + signature.length) * total)
|
|
80
|
+
);
|
|
81
|
+
const pLen = Math.max(
|
|
82
|
+
2,
|
|
83
|
+
Math.round(payload.length / (header.length + payload.length + signature.length) * total)
|
|
84
|
+
);
|
|
85
|
+
const sLen = Math.max(2, total - hLen - pLen);
|
|
86
|
+
return ` ${c.red("\u2588".repeat(hLen))}${c.dim(".")}${c.magenta("\u2588".repeat(pLen))}${c.dim(".")}${c.cyan("\u2588".repeat(sLen))}`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// src/commands/decode.ts
|
|
90
|
+
function relativeTime(epoch) {
|
|
91
|
+
const diff = epoch - Date.now() / 1e3;
|
|
92
|
+
const abs = Math.abs(diff);
|
|
93
|
+
const past = diff < 0;
|
|
94
|
+
const units = [
|
|
95
|
+
[86400, "d"],
|
|
96
|
+
[3600, "h"],
|
|
97
|
+
[60, "m"]
|
|
98
|
+
];
|
|
99
|
+
const parts = [];
|
|
100
|
+
let remaining = abs;
|
|
101
|
+
for (const [sec, label] of units) {
|
|
102
|
+
if (remaining >= sec) {
|
|
103
|
+
parts.push(`${Math.floor(remaining / sec)}${label}`);
|
|
104
|
+
remaining %= sec;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const str = parts.length > 0 ? parts.slice(0, 2).join(" ") : "<1m";
|
|
108
|
+
return past ? `${str} ago` : `in ${str}`;
|
|
109
|
+
}
|
|
110
|
+
function claimIcon(present, valid) {
|
|
111
|
+
if (!present) return c.dim("\u25CB");
|
|
112
|
+
if (valid === false) return c.red("\u2717");
|
|
113
|
+
return c.green("\u2713");
|
|
114
|
+
}
|
|
115
|
+
async function decodeCommand(token, options) {
|
|
116
|
+
try {
|
|
117
|
+
const result = decode(token);
|
|
118
|
+
if (options.json) {
|
|
119
|
+
process.stdout.write(
|
|
120
|
+
`${JSON.stringify({ header: result.header, payload: result.payload }, null, 2)}
|
|
121
|
+
`
|
|
122
|
+
);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
await playDecodeAnimation(token);
|
|
126
|
+
process.stdout.write(
|
|
127
|
+
`${tokenBar(result.raw.header, result.raw.payload, result.raw.signature)}
|
|
128
|
+
|
|
129
|
+
`
|
|
130
|
+
);
|
|
131
|
+
const headerJson = JSON.stringify(result.header, null, 2);
|
|
132
|
+
process.stdout.write(
|
|
133
|
+
`${drawBox(`HEADER ${c.dim(`(${result.header.alg})`)}`, headerJson, c.red)}
|
|
134
|
+
|
|
135
|
+
`
|
|
136
|
+
);
|
|
137
|
+
const payloadJson = JSON.stringify(result.payload, null, 2);
|
|
138
|
+
process.stdout.write(`${drawBox("PAYLOAD", payloadJson, c.magenta)}
|
|
139
|
+
|
|
140
|
+
`);
|
|
141
|
+
const p = result.payload;
|
|
142
|
+
const now = Date.now() / 1e3;
|
|
143
|
+
process.stdout.write(` ${c.bold("Claims")}
|
|
144
|
+
`);
|
|
145
|
+
const expValid = p.exp ? p.exp > now : void 0;
|
|
146
|
+
const nbfValid = p.nbf ? p.nbf <= now : void 0;
|
|
147
|
+
const claims = [
|
|
148
|
+
{ key: "iss", val: p.iss },
|
|
149
|
+
{ key: "sub", val: p.sub },
|
|
150
|
+
{ key: "aud", val: p.aud },
|
|
151
|
+
{ key: "iat", val: p.iat ? new Date(p.iat * 1e3).toISOString() : void 0 },
|
|
152
|
+
{
|
|
153
|
+
key: "exp",
|
|
154
|
+
val: p.exp ? `${new Date(p.exp * 1e3).toISOString()} ${c.dim(`(${relativeTime(p.exp)})`)}` : void 0,
|
|
155
|
+
valid: expValid
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
key: "nbf",
|
|
159
|
+
val: p.nbf ? new Date(p.nbf * 1e3).toISOString() : void 0,
|
|
160
|
+
valid: nbfValid
|
|
161
|
+
},
|
|
162
|
+
{ key: "jti", val: p.jti }
|
|
163
|
+
];
|
|
164
|
+
for (const claim of claims) {
|
|
165
|
+
const icon = claimIcon(claim.val !== void 0, claim.valid);
|
|
166
|
+
const value = claim.val ? c.dim(String(claim.val)) : c.dim("\u2014");
|
|
167
|
+
process.stdout.write(` ${icon} ${c.bold(claim.key.padEnd(4))} ${value}
|
|
168
|
+
`);
|
|
169
|
+
}
|
|
170
|
+
process.stdout.write(`
|
|
171
|
+
${c.dim("Algorithm:")} ${c.cyan(result.header.alg)}
|
|
172
|
+
|
|
173
|
+
`);
|
|
174
|
+
} catch (err) {
|
|
175
|
+
process.stderr.write(
|
|
176
|
+
`${c.red("error")}: ${err instanceof Error ? err.message : "Failed to decode token"}
|
|
177
|
+
`
|
|
178
|
+
);
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// src/commands/encode.ts
|
|
184
|
+
import { encode } from "@tokx/core";
|
|
185
|
+
|
|
186
|
+
// src/ui/spinner.ts
|
|
187
|
+
var FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
188
|
+
function startSpinner(message) {
|
|
189
|
+
if (!isTTY()) {
|
|
190
|
+
return {
|
|
191
|
+
stop: (success, finalMsg) => {
|
|
192
|
+
const icon = success ? c.green("\u2713") : c.red("\u2717");
|
|
193
|
+
process.stderr.write(`${icon} ${finalMsg}
|
|
194
|
+
`);
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
let i = 0;
|
|
199
|
+
const interval = setInterval(() => {
|
|
200
|
+
process.stderr.write(`\r ${c.cyan(FRAMES[i % FRAMES.length])} ${message}`);
|
|
201
|
+
i++;
|
|
202
|
+
}, 80);
|
|
203
|
+
return {
|
|
204
|
+
stop: (success, finalMsg) => {
|
|
205
|
+
clearInterval(interval);
|
|
206
|
+
const icon = success ? c.green("\u2713") : c.red("\u2717");
|
|
207
|
+
process.stderr.write(`\r ${icon} ${finalMsg}${" ".repeat(20)}
|
|
208
|
+
`);
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// src/commands/encode.ts
|
|
214
|
+
async function encodeCommand(options) {
|
|
215
|
+
try {
|
|
216
|
+
if (!options.secret) {
|
|
217
|
+
process.stderr.write(`${c.red("error")}: --secret is required
|
|
218
|
+
`);
|
|
219
|
+
process.exit(1);
|
|
220
|
+
}
|
|
221
|
+
if (!options.payload) {
|
|
222
|
+
process.stderr.write(`${c.red("error")}: --payload is required
|
|
223
|
+
`);
|
|
224
|
+
process.exit(1);
|
|
225
|
+
}
|
|
226
|
+
let payloadObj;
|
|
227
|
+
try {
|
|
228
|
+
payloadObj = JSON.parse(options.payload);
|
|
229
|
+
} catch {
|
|
230
|
+
process.stderr.write(`${c.red("error")}: --payload must be valid JSON
|
|
231
|
+
`);
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
234
|
+
const spinner = startSpinner("Signing token...");
|
|
235
|
+
const token = await encode({
|
|
236
|
+
algorithm: options.algorithm,
|
|
237
|
+
payload: payloadObj,
|
|
238
|
+
secret: options.secret,
|
|
239
|
+
expiresIn: options.expires ? Number(options.expires) : void 0
|
|
240
|
+
});
|
|
241
|
+
spinner.stop(true, `Token signed ${c.dim(`(${options.algorithm})`)}`);
|
|
242
|
+
if (options.json) {
|
|
243
|
+
process.stdout.write(`${JSON.stringify({ token })}
|
|
244
|
+
`);
|
|
245
|
+
} else {
|
|
246
|
+
const parts = token.split(".");
|
|
247
|
+
process.stdout.write("\n");
|
|
248
|
+
if (parts.length === 3) {
|
|
249
|
+
process.stdout.write(`${tokenBar(parts[0], parts[1], parts[2])}
|
|
250
|
+
|
|
251
|
+
`);
|
|
252
|
+
process.stdout.write(
|
|
253
|
+
` ${c.red(parts[0])}
|
|
254
|
+
${c.dim(".")}
|
|
255
|
+
${c.magenta(parts[1])}
|
|
256
|
+
${c.dim(".")}
|
|
257
|
+
${c.cyan(parts[2])}
|
|
258
|
+
`
|
|
259
|
+
);
|
|
260
|
+
} else {
|
|
261
|
+
process.stdout.write(` ${token}
|
|
262
|
+
`);
|
|
263
|
+
}
|
|
264
|
+
process.stdout.write("\n");
|
|
265
|
+
}
|
|
266
|
+
} catch (err) {
|
|
267
|
+
process.stderr.write(
|
|
268
|
+
`${c.red("error")}: ${err instanceof Error ? err.message : "Failed to encode token"}
|
|
269
|
+
`
|
|
270
|
+
);
|
|
271
|
+
process.exit(1);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// src/commands/libs.ts
|
|
276
|
+
import Table from "cli-table3";
|
|
277
|
+
var LANG_TAGS = {
|
|
278
|
+
JavaScript: "JS",
|
|
279
|
+
Python: "PY",
|
|
280
|
+
Java: "JV",
|
|
281
|
+
Go: "GO",
|
|
282
|
+
Rust: "RS",
|
|
283
|
+
Ruby: "RB",
|
|
284
|
+
PHP: "PHP",
|
|
285
|
+
".NET": "NET",
|
|
286
|
+
Swift: "SW",
|
|
287
|
+
Kotlin: "KT",
|
|
288
|
+
Dart: "DT",
|
|
289
|
+
Erlang: "ER"
|
|
290
|
+
};
|
|
291
|
+
var LIBRARIES = [
|
|
292
|
+
{
|
|
293
|
+
name: "jose",
|
|
294
|
+
language: "JavaScript",
|
|
295
|
+
author: "panva",
|
|
296
|
+
url: "https://github.com/panva/jose",
|
|
297
|
+
stars: 6200,
|
|
298
|
+
install: "npm install jose",
|
|
299
|
+
signing: ["HS256", "RS256", "ES256", "EdDSA"],
|
|
300
|
+
verifying: ["HS256", "RS256", "ES256", "EdDSA"]
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
name: "jsonwebtoken",
|
|
304
|
+
language: "JavaScript",
|
|
305
|
+
author: "auth0",
|
|
306
|
+
url: "https://github.com/auth0/node-jsonwebtoken",
|
|
307
|
+
stars: 17500,
|
|
308
|
+
install: "npm install jsonwebtoken",
|
|
309
|
+
signing: ["HS256", "RS256", "ES256"],
|
|
310
|
+
verifying: ["HS256", "RS256", "ES256"]
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
name: "PyJWT",
|
|
314
|
+
language: "Python",
|
|
315
|
+
author: "jpadilla",
|
|
316
|
+
url: "https://github.com/jpadilla/pyjwt",
|
|
317
|
+
stars: 5100,
|
|
318
|
+
install: "pip install PyJWT",
|
|
319
|
+
signing: ["HS256", "RS256", "ES256", "EdDSA"],
|
|
320
|
+
verifying: ["HS256", "RS256", "ES256", "EdDSA"]
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
name: "java-jwt",
|
|
324
|
+
language: "Java",
|
|
325
|
+
author: "auth0",
|
|
326
|
+
url: "https://github.com/auth0/java-jwt",
|
|
327
|
+
stars: 5800,
|
|
328
|
+
install: "implementation 'com.auth0:java-jwt:4.4.0'",
|
|
329
|
+
signing: ["HS256", "RS256", "ES256"],
|
|
330
|
+
verifying: ["HS256", "RS256", "ES256"]
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
name: "jjwt",
|
|
334
|
+
language: "Java",
|
|
335
|
+
author: "jwtk",
|
|
336
|
+
url: "https://github.com/jwtk/jjwt",
|
|
337
|
+
stars: 10300,
|
|
338
|
+
install: "implementation 'io.jsonwebtoken:jjwt-api:0.12.6'",
|
|
339
|
+
signing: ["HS256", "RS256", "ES256", "EdDSA"],
|
|
340
|
+
verifying: ["HS256", "RS256", "ES256", "EdDSA"]
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
name: "golang-jwt",
|
|
344
|
+
language: "Go",
|
|
345
|
+
author: "golang-jwt",
|
|
346
|
+
url: "https://github.com/golang-jwt/jwt",
|
|
347
|
+
stars: 7200,
|
|
348
|
+
install: "go get github.com/golang-jwt/jwt/v5",
|
|
349
|
+
signing: ["HS256", "RS256", "ES256", "EdDSA"],
|
|
350
|
+
verifying: ["HS256", "RS256", "ES256", "EdDSA"]
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
name: "jsonwebtoken",
|
|
354
|
+
language: "Rust",
|
|
355
|
+
author: "Keats",
|
|
356
|
+
url: "https://github.com/Keats/jsonwebtoken",
|
|
357
|
+
stars: 1700,
|
|
358
|
+
install: "cargo add jsonwebtoken",
|
|
359
|
+
signing: ["HS256", "RS256", "ES256", "EdDSA"],
|
|
360
|
+
verifying: ["HS256", "RS256", "ES256", "EdDSA"]
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
name: "ruby-jwt",
|
|
364
|
+
language: "Ruby",
|
|
365
|
+
author: "jwt",
|
|
366
|
+
url: "https://github.com/jwt/ruby-jwt",
|
|
367
|
+
stars: 3600,
|
|
368
|
+
install: "gem install jwt",
|
|
369
|
+
signing: ["HS256", "RS256", "ES256", "EdDSA"],
|
|
370
|
+
verifying: ["HS256", "RS256", "ES256", "EdDSA"]
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
name: "php-jwt",
|
|
374
|
+
language: "PHP",
|
|
375
|
+
author: "firebase",
|
|
376
|
+
url: "https://github.com/firebase/php-jwt",
|
|
377
|
+
stars: 9400,
|
|
378
|
+
install: "composer require firebase/php-jwt",
|
|
379
|
+
signing: ["HS256", "RS256", "ES256"],
|
|
380
|
+
verifying: ["HS256", "RS256", "ES256"]
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
name: "System.IdentityModel.Tokens.Jwt",
|
|
384
|
+
language: ".NET",
|
|
385
|
+
author: "AzureAD",
|
|
386
|
+
url: "https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet",
|
|
387
|
+
stars: 1100,
|
|
388
|
+
install: "dotnet add package System.IdentityModel.Tokens.Jwt",
|
|
389
|
+
signing: ["HS256", "RS256", "ES256"],
|
|
390
|
+
verifying: ["HS256", "RS256", "ES256"]
|
|
391
|
+
}
|
|
392
|
+
];
|
|
393
|
+
function formatStars(n) {
|
|
394
|
+
return n >= 1e3 ? `${(n / 1e3).toFixed(1)}k` : String(n);
|
|
395
|
+
}
|
|
396
|
+
function libsCommand(options) {
|
|
397
|
+
try {
|
|
398
|
+
let results = LIBRARIES;
|
|
399
|
+
if (options.language) {
|
|
400
|
+
const lang = options.language.toLowerCase();
|
|
401
|
+
results = results.filter((l) => l.language.toLowerCase() === lang);
|
|
402
|
+
}
|
|
403
|
+
if (options.algorithm) {
|
|
404
|
+
const alg = options.algorithm.toUpperCase();
|
|
405
|
+
results = results.filter((l) => l.signing.includes(alg) || l.verifying.includes(alg));
|
|
406
|
+
}
|
|
407
|
+
results.sort((a, b) => b.stars - a.stars);
|
|
408
|
+
if (options.json) {
|
|
409
|
+
process.stdout.write(`${JSON.stringify(results, null, 2)}
|
|
410
|
+
`);
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
if (results.length === 0) {
|
|
414
|
+
process.stderr.write(` ${c.dim("No libraries match your filters.")}
|
|
415
|
+
`);
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
const table = new Table({
|
|
419
|
+
head: [c.bold("Library"), c.bold("Lang"), c.bold("\u2605"), c.bold("Install")],
|
|
420
|
+
style: { head: [], border: [] },
|
|
421
|
+
colWidths: [28, 7, 8, 48],
|
|
422
|
+
wordWrap: true
|
|
423
|
+
});
|
|
424
|
+
for (const lib of results) {
|
|
425
|
+
const tag = LANG_TAGS[lib.language] || lib.language.slice(0, 3).toUpperCase();
|
|
426
|
+
const langTag = c.blue(`[${tag}]`);
|
|
427
|
+
table.push([
|
|
428
|
+
c.cyan(lib.name),
|
|
429
|
+
langTag,
|
|
430
|
+
c.yellow(`\u2605 ${formatStars(lib.stars)}`),
|
|
431
|
+
c.dim(lib.install)
|
|
432
|
+
]);
|
|
433
|
+
}
|
|
434
|
+
process.stdout.write(`
|
|
435
|
+
${table.toString()}
|
|
436
|
+
|
|
437
|
+
`);
|
|
438
|
+
process.stderr.write(` ${c.dim(`${results.length} libraries found`)}
|
|
439
|
+
|
|
440
|
+
`);
|
|
441
|
+
} catch (err) {
|
|
442
|
+
process.stderr.write(
|
|
443
|
+
`${c.red("error")}: ${err instanceof Error ? err.message : "Failed to list libraries"}
|
|
444
|
+
`
|
|
445
|
+
);
|
|
446
|
+
process.exit(3);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// src/commands/verify.ts
|
|
451
|
+
import { decode as decode2, verify } from "@tokx/core";
|
|
452
|
+
async function verifyCommand(token, options) {
|
|
453
|
+
try {
|
|
454
|
+
if (!options.secret && !options.publicKey) {
|
|
455
|
+
process.stderr.write(`${c.red("error")}: --secret or --public-key is required
|
|
456
|
+
`);
|
|
457
|
+
process.exit(1);
|
|
458
|
+
}
|
|
459
|
+
let alg = options.algorithm;
|
|
460
|
+
if (!alg) {
|
|
461
|
+
try {
|
|
462
|
+
const decoded = decode2(token);
|
|
463
|
+
alg = decoded.header.alg;
|
|
464
|
+
} catch {
|
|
465
|
+
process.stderr.write(
|
|
466
|
+
`${c.red("error")}: Could not detect algorithm. Use --algorithm to specify.
|
|
467
|
+
`
|
|
468
|
+
);
|
|
469
|
+
process.exit(1);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
const spinner = startSpinner("Verifying signature...");
|
|
473
|
+
const result = await verify(token, {
|
|
474
|
+
algorithm: alg,
|
|
475
|
+
secret: options.secret || "",
|
|
476
|
+
publicKey: options.publicKey
|
|
477
|
+
});
|
|
478
|
+
if (options.json) {
|
|
479
|
+
spinner.stop(result.valid, result.valid ? "Valid" : "Invalid");
|
|
480
|
+
process.stdout.write(`${JSON.stringify(result)}
|
|
481
|
+
`);
|
|
482
|
+
if (!result.valid) process.exit(2);
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
if (result.valid) {
|
|
486
|
+
spinner.stop(true, "Verification complete");
|
|
487
|
+
process.stdout.write(`
|
|
488
|
+
${drawBadge("SIGNATURE VERIFIED", c.green, "\u2713")}
|
|
489
|
+
|
|
490
|
+
`);
|
|
491
|
+
} else {
|
|
492
|
+
spinner.stop(false, "Verification failed");
|
|
493
|
+
process.stdout.write(`
|
|
494
|
+
${drawBadge("INVALID SIGNATURE", c.red, "\u2717")}
|
|
495
|
+
`);
|
|
496
|
+
if (result.error) process.stderr.write(` ${c.dim(result.error)}
|
|
497
|
+
`);
|
|
498
|
+
if (result.expired) process.stderr.write(` ${c.yellow("Token has expired")}
|
|
499
|
+
`);
|
|
500
|
+
process.stdout.write("\n");
|
|
501
|
+
process.exit(2);
|
|
502
|
+
}
|
|
503
|
+
} catch (err) {
|
|
504
|
+
process.stderr.write(
|
|
505
|
+
`${c.red("error")}: ${err instanceof Error ? err.message : "Verification failed"}
|
|
506
|
+
`
|
|
507
|
+
);
|
|
508
|
+
process.exit(1);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// src/ui/banner.ts
|
|
513
|
+
function printBanner() {
|
|
514
|
+
if (!isTTY()) return;
|
|
515
|
+
const t = c.red("t");
|
|
516
|
+
const o = c.magenta("o");
|
|
517
|
+
const k = c.cyan("k");
|
|
518
|
+
const x = c.cyan("x");
|
|
519
|
+
process.stderr.write("\n");
|
|
520
|
+
process.stderr.write(` ${c.dim("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510")}
|
|
521
|
+
`);
|
|
522
|
+
process.stderr.write(
|
|
523
|
+
` ${c.dim("\u2502")} ${t} ${o} ${k} ${x} ${c.dim("\u2502")}
|
|
524
|
+
`
|
|
525
|
+
);
|
|
526
|
+
process.stderr.write(
|
|
527
|
+
` ${c.dim("\u2502")} ${c.dim("JWT decode \xB7 encode \xB7 verify")} ${c.dim("\u2502")}
|
|
528
|
+
`
|
|
529
|
+
);
|
|
530
|
+
process.stderr.write(` ${c.dim("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518")}
|
|
531
|
+
`);
|
|
532
|
+
process.stderr.write("\n");
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// src/index.ts
|
|
536
|
+
var pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
|
|
537
|
+
program.name("tokx").description("JWT decode, encode, verify from your terminal").version(pkg.version);
|
|
538
|
+
if (process.argv.length <= 2) {
|
|
539
|
+
printBanner();
|
|
540
|
+
}
|
|
541
|
+
async function readStdin() {
|
|
542
|
+
const chunks = [];
|
|
543
|
+
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
544
|
+
return Buffer.concat(chunks).toString().trim();
|
|
545
|
+
}
|
|
546
|
+
program.command("decode <token>").description("Decode a JWT and display header + payload (use - for stdin)").option("--json", "Output as JSON").action(async (token, options) => {
|
|
547
|
+
const t = token === "-" ? await readStdin() : token;
|
|
548
|
+
return decodeCommand(t, options);
|
|
549
|
+
});
|
|
550
|
+
program.command("encode").description("Encode (sign) a new JWT").requiredOption("--secret <secret>", "Signing secret (HMAC)").requiredOption("--payload <json>", "Payload as JSON string").option("--algorithm <alg>", "Algorithm", "HS256").option("--expires <seconds>", "Expiration in seconds from now").option("--json", "Output as JSON").action(encodeCommand);
|
|
551
|
+
program.command("verify <token>").description("Verify a JWT signature (use - for stdin)").option("--secret <secret>", "Verification secret (HMAC)").option("--public-key <path>", "Public key PEM file path").option("--algorithm <alg>", "Algorithm (auto-detected if omitted)").option("--json", "Output as JSON").action(
|
|
552
|
+
async (token, options) => {
|
|
553
|
+
const t = token === "-" ? await readStdin() : token;
|
|
554
|
+
return verifyCommand(t, options);
|
|
555
|
+
}
|
|
556
|
+
);
|
|
557
|
+
program.command("libs").description("List JWT libraries").option("--language <lang>", "Filter by language").option("--algorithm <alg>", "Filter by algorithm").option("--json", "Output as JSON").action(libsCommand);
|
|
558
|
+
program.parse();
|
|
559
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/decode.ts","../src/ui/colors.ts","../src/ui/animation.ts","../src/ui/box.ts","../src/commands/encode.ts","../src/ui/spinner.ts","../src/commands/libs.ts","../src/commands/verify.ts","../src/ui/banner.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { program } from 'commander';\nimport { decodeCommand } from './commands/decode.js';\nimport { encodeCommand } from './commands/encode.js';\nimport { libsCommand } from './commands/libs.js';\nimport { verifyCommand } from './commands/verify.js';\nimport { printBanner } from './ui/banner.js';\n\nconst pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf-8'));\n\nprogram\n .name('tokx')\n .description('JWT decode, encode, verify from your terminal')\n .version(pkg.version);\n\n// Show banner when no command provided\nif (process.argv.length <= 2) {\n printBanner();\n}\n\n// Helper: read token from stdin if '-' is passed\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) chunks.push(chunk as Buffer);\n return Buffer.concat(chunks).toString().trim();\n}\n\nprogram\n .command('decode <token>')\n .description('Decode a JWT and display header + payload (use - for stdin)')\n .option('--json', 'Output as JSON')\n .action(async (token: string, options: { json?: boolean }) => {\n const t = token === '-' ? await readStdin() : token;\n return decodeCommand(t, options);\n });\n\nprogram\n .command('encode')\n .description('Encode (sign) a new JWT')\n .requiredOption('--secret <secret>', 'Signing secret (HMAC)')\n .requiredOption('--payload <json>', 'Payload as JSON string')\n .option('--algorithm <alg>', 'Algorithm', 'HS256')\n .option('--expires <seconds>', 'Expiration in seconds from now')\n .option('--json', 'Output as JSON')\n .action(encodeCommand);\n\nprogram\n .command('verify <token>')\n .description('Verify a JWT signature (use - for stdin)')\n .option('--secret <secret>', 'Verification secret (HMAC)')\n .option('--public-key <path>', 'Public key PEM file path')\n .option('--algorithm <alg>', 'Algorithm (auto-detected if omitted)')\n .option('--json', 'Output as JSON')\n .action(\n async (\n token: string,\n options: { secret?: string; publicKey?: string; algorithm?: string; json?: boolean },\n ) => {\n const t = token === '-' ? await readStdin() : token;\n return verifyCommand(t, options);\n },\n );\n\nprogram\n .command('libs')\n .description('List JWT libraries')\n .option('--language <lang>', 'Filter by language')\n .option('--algorithm <alg>', 'Filter by algorithm')\n .option('--json', 'Output as JSON')\n .action(libsCommand);\n\nprogram.parse();\n","import { decode } from '@tokx/core';\nimport { playDecodeAnimation } from '../ui/animation.js';\nimport { drawBox, tokenBar } from '../ui/box.js';\nimport { c } from '../ui/colors.js';\n\ninterface DecodeOptions {\n json?: boolean;\n}\n\nfunction relativeTime(epoch: number): string {\n const diff = epoch - Date.now() / 1000;\n const abs = Math.abs(diff);\n const past = diff < 0;\n const units: [number, string][] = [\n [86400, 'd'],\n [3600, 'h'],\n [60, 'm'],\n ];\n const parts: string[] = [];\n let remaining = abs;\n for (const [sec, label] of units) {\n if (remaining >= sec) {\n parts.push(`${Math.floor(remaining / sec)}${label}`);\n remaining %= sec;\n }\n }\n const str = parts.length > 0 ? parts.slice(0, 2).join(' ') : '<1m';\n return past ? `${str} ago` : `in ${str}`;\n}\n\nfunction claimIcon(present: boolean, valid?: boolean): string {\n if (!present) return c.dim('○');\n if (valid === false) return c.red('✗');\n return c.green('✓');\n}\n\nexport async function decodeCommand(token: string, options: DecodeOptions): Promise<void> {\n try {\n const result = decode(token);\n\n if (options.json) {\n process.stdout.write(\n `${JSON.stringify({ header: result.header, payload: result.payload }, null, 2)}\\n`,\n );\n return;\n }\n\n await playDecodeAnimation(token);\n\n // Token bar\n process.stdout.write(\n `${tokenBar(result.raw.header, result.raw.payload, result.raw.signature)}\\n\\n`,\n );\n\n // Header box\n const headerJson = JSON.stringify(result.header, null, 2);\n process.stdout.write(\n `${drawBox(`HEADER ${c.dim(`(${result.header.alg})`)}`, headerJson, c.red)}\\n\\n`,\n );\n\n // Payload box\n const payloadJson = JSON.stringify(result.payload, null, 2);\n process.stdout.write(`${drawBox('PAYLOAD', payloadJson, c.magenta)}\\n\\n`);\n\n // Claims summary\n const p = result.payload;\n const now = Date.now() / 1000;\n process.stdout.write(` ${c.bold('Claims')}\\n`);\n\n const expValid = p.exp ? (p.exp as number) > now : undefined;\n const nbfValid = p.nbf ? (p.nbf as number) <= now : undefined;\n\n const claims = [\n { key: 'iss', val: p.iss as string | undefined },\n { key: 'sub', val: p.sub as string | undefined },\n { key: 'aud', val: p.aud as string | undefined },\n { key: 'iat', val: p.iat ? new Date((p.iat as number) * 1000).toISOString() : undefined },\n {\n key: 'exp',\n val: p.exp\n ? `${new Date((p.exp as number) * 1000).toISOString()} ${c.dim(`(${relativeTime(p.exp as number)})`)}`\n : undefined,\n valid: expValid,\n },\n {\n key: 'nbf',\n val: p.nbf ? new Date((p.nbf as number) * 1000).toISOString() : undefined,\n valid: nbfValid,\n },\n { key: 'jti', val: p.jti as string | undefined },\n ];\n\n for (const claim of claims) {\n const icon = claimIcon(claim.val !== undefined, (claim as { valid?: boolean }).valid);\n const value = claim.val ? c.dim(String(claim.val)) : c.dim('—');\n process.stdout.write(` ${icon} ${c.bold(claim.key.padEnd(4))} ${value}\\n`);\n }\n\n process.stdout.write(`\\n ${c.dim('Algorithm:')} ${c.cyan(result.header.alg)}\\n\\n`);\n } catch (err) {\n process.stderr.write(\n `${c.red('error')}: ${err instanceof Error ? err.message : 'Failed to decode token'}\\n`,\n );\n process.exit(1);\n }\n}\n","import pc from 'picocolors';\n\nconst noColor = process.env.NO_COLOR !== undefined;\n\nfunction wrap(fn: (s: string) => string): (s: string) => string {\n return noColor ? (s: string) => s : fn;\n}\n\nexport const c = {\n red: wrap(pc.red),\n green: wrap(pc.green),\n yellow: wrap(pc.yellow),\n blue: wrap(pc.blue),\n cyan: wrap(pc.cyan),\n magenta: wrap(pc.magenta),\n gray: wrap(pc.gray),\n bold: wrap(pc.bold),\n dim: wrap(pc.dim),\n};\n\nexport function isTTY(): boolean {\n return !noColor && process.stdout.isTTY === true;\n}\n","import { c, isTTY } from './colors.js';\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\nexport async function playDecodeAnimation(token: string): Promise<void> {\n if (!isTTY()) return;\n\n const parts = token.split('.');\n if (parts.length !== 3) return;\n\n const frames = [\n ` ${c.dim(token.slice(0, 40))}${c.dim('...')}`,\n ` ${c.red(parts[0].slice(0, 12))}${c.dim('...')} ${c.dim('·')} ${c.magenta(parts[1].slice(0, 12))}${c.dim('...')} ${c.dim('·')} ${c.cyan(parts[2].slice(0, 12))}${c.dim('...')}`,\n ` ${c.red('■ header')} ${c.dim('·')} ${c.magenta('■ payload')} ${c.dim('·')} ${c.cyan('■ signature')}`,\n ];\n\n process.stdout.write('\\n');\n for (const frame of frames) {\n process.stdout.write(`\\r${frame}${' '.repeat(20)}`);\n await sleep(120);\n }\n process.stdout.write('\\n\\n');\n}\n","import { c } from './colors.js';\n\ntype ColorFn = (s: string) => string;\n\nexport function drawBox(title: string, content: string, color: ColorFn): string {\n const lines = content.split('\\n');\n const maxLen = Math.max(title.length + 4, ...lines.map((l) => l.length));\n const width = Math.min(maxLen + 4, 60);\n\n const top = color(` ┌─ ${title} ${'─'.repeat(Math.max(0, width - title.length - 5))}┐`);\n const bottom = color(` └${'─'.repeat(width - 1)}┘`);\n\n const body = lines.map((line) => {\n const padded = line.padEnd(width - 4);\n return ` ${color('│')} ${padded} ${color('│')}`;\n });\n\n return [top, ...body, bottom].join('\\n');\n}\n\nexport function drawBadge(text: string, color: ColorFn, icon: string): string {\n const inner = ` ${icon} ${text} `;\n const width = inner.length + 2;\n const top = color(` ╔${'═'.repeat(width)}╗`);\n const mid = color(` ║${inner}║`);\n const bottom = color(` ╚${'═'.repeat(width)}╝`);\n return `${top}\\n${mid}\\n${bottom}`;\n}\n\nexport function tokenBar(header: string, payload: string, signature: string): string {\n const total = 50;\n const hLen = Math.max(\n 2,\n Math.round((header.length / (header.length + payload.length + signature.length)) * total),\n );\n const pLen = Math.max(\n 2,\n Math.round((payload.length / (header.length + payload.length + signature.length)) * total),\n );\n const sLen = Math.max(2, total - hLen - pLen);\n\n return ` ${c.red('█'.repeat(hLen))}${c.dim('.')}${c.magenta('█'.repeat(pLen))}${c.dim('.')}${c.cyan('█'.repeat(sLen))}`;\n}\n","import type { JwtAlgorithm } from '@tokx/core';\nimport { encode } from '@tokx/core';\nimport { tokenBar } from '../ui/box.js';\nimport { c } from '../ui/colors.js';\nimport { startSpinner } from '../ui/spinner.js';\n\ninterface EncodeOptions {\n algorithm: string;\n secret: string;\n payload: string;\n expires?: string;\n json?: boolean;\n}\n\nexport async function encodeCommand(options: EncodeOptions): Promise<void> {\n try {\n if (!options.secret) {\n process.stderr.write(`${c.red('error')}: --secret is required\\n`);\n process.exit(1);\n }\n if (!options.payload) {\n process.stderr.write(`${c.red('error')}: --payload is required\\n`);\n process.exit(1);\n }\n\n let payloadObj: Record<string, unknown>;\n try {\n payloadObj = JSON.parse(options.payload);\n } catch {\n process.stderr.write(`${c.red('error')}: --payload must be valid JSON\\n`);\n process.exit(1);\n }\n\n const spinner = startSpinner('Signing token...');\n\n const token = await encode({\n algorithm: options.algorithm as JwtAlgorithm,\n payload: payloadObj,\n secret: options.secret,\n expiresIn: options.expires ? Number(options.expires) : undefined,\n });\n\n spinner.stop(true, `Token signed ${c.dim(`(${options.algorithm})`)}`);\n\n if (options.json) {\n process.stdout.write(`${JSON.stringify({ token })}\\n`);\n } else {\n const parts = token.split('.');\n process.stdout.write('\\n');\n if (parts.length === 3) {\n process.stdout.write(`${tokenBar(parts[0], parts[1], parts[2])}\\n\\n`);\n process.stdout.write(\n ` ${c.red(parts[0])}\\n ${c.dim('.')}\\n ${c.magenta(parts[1])}\\n ${c.dim('.')}\\n ${c.cyan(parts[2])}\\n`,\n );\n } else {\n process.stdout.write(` ${token}\\n`);\n }\n process.stdout.write('\\n');\n }\n } catch (err) {\n process.stderr.write(\n `${c.red('error')}: ${err instanceof Error ? err.message : 'Failed to encode token'}\\n`,\n );\n process.exit(1);\n }\n}\n","import { c, isTTY } from './colors.js';\n\nconst FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n\nexport function startSpinner(message: string): {\n stop: (success: boolean, finalMsg: string) => void;\n} {\n if (!isTTY()) {\n return {\n stop: (success, finalMsg) => {\n const icon = success ? c.green('✓') : c.red('✗');\n process.stderr.write(`${icon} ${finalMsg}\\n`);\n },\n };\n }\n\n let i = 0;\n const interval = setInterval(() => {\n process.stderr.write(`\\r ${c.cyan(FRAMES[i % FRAMES.length])} ${message}`);\n i++;\n }, 80);\n\n return {\n stop: (success, finalMsg) => {\n clearInterval(interval);\n const icon = success ? c.green('✓') : c.red('✗');\n process.stderr.write(`\\r ${icon} ${finalMsg}${' '.repeat(20)}\\n`);\n },\n };\n}\n","import Table from 'cli-table3';\nimport { c } from '../ui/colors.js';\n\ninterface LibsOptions {\n language?: string;\n algorithm?: string;\n json?: boolean;\n}\n\ninterface LibEntry {\n name: string;\n language: string;\n author: string;\n url: string;\n stars: number;\n install: string;\n signing: string[];\n verifying: string[];\n}\n\nconst LANG_TAGS: Record<string, string> = {\n JavaScript: 'JS',\n Python: 'PY',\n Java: 'JV',\n Go: 'GO',\n Rust: 'RS',\n Ruby: 'RB',\n PHP: 'PHP',\n '.NET': 'NET',\n Swift: 'SW',\n Kotlin: 'KT',\n Dart: 'DT',\n Erlang: 'ER',\n};\n\nconst LIBRARIES: LibEntry[] = [\n {\n name: 'jose',\n language: 'JavaScript',\n author: 'panva',\n url: 'https://github.com/panva/jose',\n stars: 6200,\n install: 'npm install jose',\n signing: ['HS256', 'RS256', 'ES256', 'EdDSA'],\n verifying: ['HS256', 'RS256', 'ES256', 'EdDSA'],\n },\n {\n name: 'jsonwebtoken',\n language: 'JavaScript',\n author: 'auth0',\n url: 'https://github.com/auth0/node-jsonwebtoken',\n stars: 17500,\n install: 'npm install jsonwebtoken',\n signing: ['HS256', 'RS256', 'ES256'],\n verifying: ['HS256', 'RS256', 'ES256'],\n },\n {\n name: 'PyJWT',\n language: 'Python',\n author: 'jpadilla',\n url: 'https://github.com/jpadilla/pyjwt',\n stars: 5100,\n install: 'pip install PyJWT',\n signing: ['HS256', 'RS256', 'ES256', 'EdDSA'],\n verifying: ['HS256', 'RS256', 'ES256', 'EdDSA'],\n },\n {\n name: 'java-jwt',\n language: 'Java',\n author: 'auth0',\n url: 'https://github.com/auth0/java-jwt',\n stars: 5800,\n install: \"implementation 'com.auth0:java-jwt:4.4.0'\",\n signing: ['HS256', 'RS256', 'ES256'],\n verifying: ['HS256', 'RS256', 'ES256'],\n },\n {\n name: 'jjwt',\n language: 'Java',\n author: 'jwtk',\n url: 'https://github.com/jwtk/jjwt',\n stars: 10300,\n install: \"implementation 'io.jsonwebtoken:jjwt-api:0.12.6'\",\n signing: ['HS256', 'RS256', 'ES256', 'EdDSA'],\n verifying: ['HS256', 'RS256', 'ES256', 'EdDSA'],\n },\n {\n name: 'golang-jwt',\n language: 'Go',\n author: 'golang-jwt',\n url: 'https://github.com/golang-jwt/jwt',\n stars: 7200,\n install: 'go get github.com/golang-jwt/jwt/v5',\n signing: ['HS256', 'RS256', 'ES256', 'EdDSA'],\n verifying: ['HS256', 'RS256', 'ES256', 'EdDSA'],\n },\n {\n name: 'jsonwebtoken',\n language: 'Rust',\n author: 'Keats',\n url: 'https://github.com/Keats/jsonwebtoken',\n stars: 1700,\n install: 'cargo add jsonwebtoken',\n signing: ['HS256', 'RS256', 'ES256', 'EdDSA'],\n verifying: ['HS256', 'RS256', 'ES256', 'EdDSA'],\n },\n {\n name: 'ruby-jwt',\n language: 'Ruby',\n author: 'jwt',\n url: 'https://github.com/jwt/ruby-jwt',\n stars: 3600,\n install: 'gem install jwt',\n signing: ['HS256', 'RS256', 'ES256', 'EdDSA'],\n verifying: ['HS256', 'RS256', 'ES256', 'EdDSA'],\n },\n {\n name: 'php-jwt',\n language: 'PHP',\n author: 'firebase',\n url: 'https://github.com/firebase/php-jwt',\n stars: 9400,\n install: 'composer require firebase/php-jwt',\n signing: ['HS256', 'RS256', 'ES256'],\n verifying: ['HS256', 'RS256', 'ES256'],\n },\n {\n name: 'System.IdentityModel.Tokens.Jwt',\n language: '.NET',\n author: 'AzureAD',\n url: 'https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet',\n stars: 1100,\n install: 'dotnet add package System.IdentityModel.Tokens.Jwt',\n signing: ['HS256', 'RS256', 'ES256'],\n verifying: ['HS256', 'RS256', 'ES256'],\n },\n];\n\nfunction formatStars(n: number): string {\n return n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n);\n}\n\nexport function libsCommand(options: LibsOptions): void {\n try {\n let results = LIBRARIES;\n\n if (options.language) {\n const lang = options.language.toLowerCase();\n results = results.filter((l) => l.language.toLowerCase() === lang);\n }\n\n if (options.algorithm) {\n const alg = options.algorithm.toUpperCase();\n results = results.filter((l) => l.signing.includes(alg) || l.verifying.includes(alg));\n }\n\n results.sort((a, b) => b.stars - a.stars);\n\n if (options.json) {\n process.stdout.write(`${JSON.stringify(results, null, 2)}\\n`);\n return;\n }\n\n if (results.length === 0) {\n process.stderr.write(` ${c.dim('No libraries match your filters.')}\\n`);\n return;\n }\n\n const table = new Table({\n head: [c.bold('Library'), c.bold('Lang'), c.bold('★'), c.bold('Install')],\n style: { head: [], border: [] },\n colWidths: [28, 7, 8, 48],\n wordWrap: true,\n });\n\n for (const lib of results) {\n const tag = LANG_TAGS[lib.language] || lib.language.slice(0, 3).toUpperCase();\n const langTag = c.blue(`[${tag}]`);\n table.push([\n c.cyan(lib.name),\n langTag,\n c.yellow(`★ ${formatStars(lib.stars)}`),\n c.dim(lib.install),\n ]);\n }\n\n process.stdout.write(`\\n${table.toString()}\\n\\n`);\n process.stderr.write(` ${c.dim(`${results.length} libraries found`)}\\n\\n`);\n } catch (err) {\n process.stderr.write(\n `${c.red('error')}: ${err instanceof Error ? err.message : 'Failed to list libraries'}\\n`,\n );\n process.exit(3);\n }\n}\n","import type { JwtAlgorithm } from '@tokx/core';\nimport { decode, verify } from '@tokx/core';\nimport { drawBadge } from '../ui/box.js';\nimport { c } from '../ui/colors.js';\nimport { startSpinner } from '../ui/spinner.js';\n\ninterface VerifyOptions {\n algorithm?: string;\n secret?: string;\n publicKey?: string;\n json?: boolean;\n}\n\nexport async function verifyCommand(token: string, options: VerifyOptions): Promise<void> {\n try {\n if (!options.secret && !options.publicKey) {\n process.stderr.write(`${c.red('error')}: --secret or --public-key is required\\n`);\n process.exit(1);\n }\n\n let alg = options.algorithm as JwtAlgorithm | undefined;\n if (!alg) {\n try {\n const decoded = decode(token);\n alg = decoded.header.alg as JwtAlgorithm;\n } catch {\n process.stderr.write(\n `${c.red('error')}: Could not detect algorithm. Use --algorithm to specify.\\n`,\n );\n process.exit(1);\n }\n }\n\n const spinner = startSpinner('Verifying signature...');\n\n const result = await verify(token, {\n algorithm: alg as JwtAlgorithm,\n secret: options.secret || '',\n publicKey: options.publicKey,\n });\n\n if (options.json) {\n spinner.stop(result.valid, result.valid ? 'Valid' : 'Invalid');\n process.stdout.write(`${JSON.stringify(result)}\\n`);\n if (!result.valid) process.exit(2);\n return;\n }\n\n if (result.valid) {\n spinner.stop(true, 'Verification complete');\n process.stdout.write(`\\n${drawBadge('SIGNATURE VERIFIED', c.green, '✓')}\\n\\n`);\n } else {\n spinner.stop(false, 'Verification failed');\n process.stdout.write(`\\n${drawBadge('INVALID SIGNATURE', c.red, '✗')}\\n`);\n if (result.error) process.stderr.write(` ${c.dim(result.error)}\\n`);\n if (result.expired) process.stderr.write(` ${c.yellow('Token has expired')}\\n`);\n process.stdout.write('\\n');\n process.exit(2);\n }\n } catch (err) {\n process.stderr.write(\n `${c.red('error')}: ${err instanceof Error ? err.message : 'Verification failed'}\\n`,\n );\n process.exit(1);\n }\n}\n","import { c, isTTY } from './colors.js';\n\nexport function printBanner(): void {\n if (!isTTY()) return;\n\n const t = c.red('t');\n const o = c.magenta('o');\n const k = c.cyan('k');\n const x = c.cyan('x');\n\n process.stderr.write('\\n');\n process.stderr.write(` ${c.dim('┌─────────────────────────────────┐')}\\n`);\n process.stderr.write(\n ` ${c.dim('│')} ${t} ${o} ${k} ${x} ${c.dim('│')}\\n`,\n );\n process.stderr.write(\n ` ${c.dim('│')} ${c.dim('JWT decode · encode · verify')} ${c.dim('│')}\\n`,\n );\n process.stderr.write(` ${c.dim('└─────────────────────────────────┘')}\\n`);\n process.stderr.write('\\n');\n}\n"],"mappings":"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","names":["decode","decode"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tokx-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "JWT decode, encode, verify from your terminal",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"tokx": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/api.js",
|
|
12
|
+
"types": "./dist/api.d.ts"
|
|
13
|
+
},
|
|
14
|
+
"./cli": {
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"README.md",
|
|
22
|
+
"LICENSE"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsup",
|
|
26
|
+
"dev": "tsup --watch",
|
|
27
|
+
"test": "vitest run",
|
|
28
|
+
"test:watch": "vitest",
|
|
29
|
+
"test:coverage": "vitest run --coverage",
|
|
30
|
+
"typecheck": "tsc --noEmit",
|
|
31
|
+
"clean": "rm -rf dist",
|
|
32
|
+
"prepublishOnly": "pnpm build"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@tokx/core": "workspace:*",
|
|
36
|
+
"commander": "^13.1.0",
|
|
37
|
+
"picocolors": "^1.1.1",
|
|
38
|
+
"cli-table3": "^0.6.5"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^22.13.0",
|
|
42
|
+
"tsup": "^8.4.0",
|
|
43
|
+
"vitest": "^3.1.1"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=22"
|
|
47
|
+
},
|
|
48
|
+
"main": "./dist/api.js",
|
|
49
|
+
"keywords": [
|
|
50
|
+
"jwt",
|
|
51
|
+
"json-web-token",
|
|
52
|
+
"cli",
|
|
53
|
+
"decode",
|
|
54
|
+
"encode",
|
|
55
|
+
"verify",
|
|
56
|
+
"token",
|
|
57
|
+
"jose"
|
|
58
|
+
],
|
|
59
|
+
"repository": {
|
|
60
|
+
"type": "git",
|
|
61
|
+
"url": "git+https://github.com/hammadxcm/tokx.git",
|
|
62
|
+
"directory": "packages/cli"
|
|
63
|
+
},
|
|
64
|
+
"homepage": "https://tokx.fyniti.co.uk",
|
|
65
|
+
"bugs": {
|
|
66
|
+
"url": "https://github.com/hammadxcm/tokx/issues"
|
|
67
|
+
},
|
|
68
|
+
"license": "MIT",
|
|
69
|
+
"author": "Hammad Khan",
|
|
70
|
+
"publishConfig": {
|
|
71
|
+
"access": "public"
|
|
72
|
+
}
|
|
73
|
+
}
|