mirror of
https://github.com/ershisan99/DevToysWeb.git
synced 2025-12-16 20:49:23 +00:00
feat: add jwt decoder
This commit is contained in:
@@ -8,7 +8,7 @@ A web clone of [DevToys](https://github.com/veler/DevToys)
|
||||
- [x] Add all tools page mock
|
||||
- [ ] Implement tools
|
||||
- [x] Converters
|
||||
- [ ] Encoders / Decoders
|
||||
- [x] Encoders / Decoders
|
||||
- [ ] Formatters
|
||||
- [ ] Generators
|
||||
- [ ] Text
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
"fuse.js": "^6.5.3",
|
||||
"html-entities": "^2.3.3",
|
||||
"js-base64": "^3.7.2",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"next": "12.1.0",
|
||||
"react": "17.0.2",
|
||||
"react-ace": "^9.5.0",
|
||||
|
||||
19
src/components/pages/encoders-decoders/jwt/CodeEditor.tsx
Normal file
19
src/components/pages/encoders-decoders/jwt/CodeEditor.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import { ComponentPropsWithoutRef, memo } from "react";
|
||||
|
||||
import CodeEditor from "@/components/common/CodeEditor";
|
||||
|
||||
type Props = Omit<ComponentPropsWithoutRef<typeof CodeEditor>, "height" | "width">;
|
||||
|
||||
const StyledComponent = (props: Props) => (
|
||||
<CodeEditor
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
{...props}
|
||||
readOnly
|
||||
height="160px"
|
||||
width="100%"
|
||||
/>
|
||||
);
|
||||
|
||||
export const Component = memo(StyledComponent);
|
||||
|
||||
export default Component;
|
||||
@@ -0,0 +1,8 @@
|
||||
import { Skeleton } from "@mui/material";
|
||||
import { memo } from "react";
|
||||
|
||||
const StyledComponent = () => <Skeleton variant="rectangular" width="100%" height="160px" />;
|
||||
|
||||
export const Component = memo(StyledComponent);
|
||||
|
||||
export default Component;
|
||||
62
src/components/pages/encoders-decoders/jwt/Content.tsx
Normal file
62
src/components/pages/encoders-decoders/jwt/Content.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import dynamic from "next/dynamic";
|
||||
import { ComponentPropsWithoutRef, memo, useCallback, useState } from "react";
|
||||
|
||||
import { Main, MainItem, TextField } from "@/components/common";
|
||||
import { decode } from "@/libs/jwt";
|
||||
|
||||
import CodeEditorLoading from "./CodeEditorLoading";
|
||||
|
||||
// https://github.com/securingsincity/react-ace/issues/27
|
||||
const CodeEditor = dynamic(
|
||||
async () => {
|
||||
const ace = await import("./CodeEditor");
|
||||
await import("ace-builds/src-noconflict/mode-json");
|
||||
return ace;
|
||||
},
|
||||
{ ssr: false, loading: CodeEditorLoading }
|
||||
);
|
||||
|
||||
type TextFieldValue = ComponentPropsWithoutRef<typeof TextField>["value"];
|
||||
type CodeValue = NonNullable<ComponentPropsWithoutRef<typeof CodeEditor>["value"]>;
|
||||
type OnTextFieldChange = NonNullable<ComponentPropsWithoutRef<typeof TextField>["onChange"]>;
|
||||
|
||||
type Props = {
|
||||
jwt: TextFieldValue;
|
||||
header: CodeValue;
|
||||
payload: CodeValue;
|
||||
onJwtChange: OnTextFieldChange;
|
||||
};
|
||||
|
||||
const StyledComponent = ({ jwt, header, payload, onJwtChange }: Props) => (
|
||||
<Main title="JWT Decoder">
|
||||
<MainItem title="Jwt Token">
|
||||
<TextField multiline rows={5} value={jwt} onChange={onJwtChange} />
|
||||
</MainItem>
|
||||
<MainItem title="Header">
|
||||
<CodeEditor name="header" mode="json" value={header} />
|
||||
</MainItem>
|
||||
<MainItem title="Payload">
|
||||
<CodeEditor name="payload" mode="json" value={payload} />
|
||||
</MainItem>
|
||||
</Main>
|
||||
);
|
||||
|
||||
export const Component = memo(StyledComponent);
|
||||
|
||||
const Container = () => {
|
||||
const [jwt, setJwt] = useState(
|
||||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
|
||||
);
|
||||
|
||||
const onJwtChange: Props["onJwtChange"] = useCallback(({ currentTarget: { value } }) => {
|
||||
setJwt(value);
|
||||
}, []);
|
||||
|
||||
const { headerObj, payloadObj } = decode(jwt);
|
||||
const header = JSON.stringify(headerObj, null, 2) ?? "";
|
||||
const payload = JSON.stringify(payloadObj, null, 2) ?? "";
|
||||
|
||||
return <Component {...{ jwt, header, payload, onJwtChange }} />;
|
||||
};
|
||||
|
||||
export default Container;
|
||||
3
src/components/pages/encoders-decoders/jwt/index.ts
Normal file
3
src/components/pages/encoders-decoders/jwt/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import Content from "./Content";
|
||||
|
||||
export { Content };
|
||||
@@ -82,8 +82,8 @@ const toolGroups = [
|
||||
longTitle: "JWT Decoder",
|
||||
description: "Decode a JWT header, payload and signature",
|
||||
keywords: "jwt json web token decocder",
|
||||
href: pagesPath.$url(),
|
||||
disabled: true,
|
||||
href: pagesPath.encoders_decoders.jwt.$url(),
|
||||
disabled: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -26,6 +26,12 @@ export const pagesPath = {
|
||||
hash: url?.hash,
|
||||
}),
|
||||
},
|
||||
jwt: {
|
||||
$url: (url?: { hash?: string }) => ({
|
||||
pathname: "/encoders-decoders/jwt" as const,
|
||||
hash: url?.hash,
|
||||
}),
|
||||
},
|
||||
url: {
|
||||
$url: (url?: { hash?: string }) => ({
|
||||
pathname: "/encoders-decoders/url" as const,
|
||||
|
||||
22
src/libs/jwt.ts
Normal file
22
src/libs/jwt.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import jwt_decode from "jwt-decode";
|
||||
|
||||
export const decode = (token: string) => {
|
||||
let headerObj;
|
||||
let payloadObj;
|
||||
|
||||
if (token.split(".").length === 3) {
|
||||
/* eslint-disable no-empty */
|
||||
|
||||
try {
|
||||
headerObj = jwt_decode(token, { header: true });
|
||||
} catch {}
|
||||
|
||||
try {
|
||||
payloadObj = jwt_decode(token, { header: false });
|
||||
} catch {}
|
||||
|
||||
/* eslint-enable no-empty */
|
||||
}
|
||||
|
||||
return { headerObj, payloadObj };
|
||||
};
|
||||
7
src/pages/encoders-decoders/jwt.tsx
Normal file
7
src/pages/encoders-decoders/jwt.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { NextPage } from "next";
|
||||
|
||||
import { Content } from "@/components/pages/encoders-decoders/jwt";
|
||||
|
||||
const Page: NextPage = Content;
|
||||
|
||||
export default Page;
|
||||
@@ -1677,6 +1677,11 @@ json5@^1.0.1:
|
||||
array-includes "^3.1.3"
|
||||
object.assign "^4.1.2"
|
||||
|
||||
jwt-decode@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-3.1.2.tgz#3fb319f3675a2df0c2895c8f5e9fa4b67b04ed59"
|
||||
integrity sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==
|
||||
|
||||
language-subtag-registry@~0.3.2:
|
||||
version "0.3.21"
|
||||
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz#04ac218bea46f04cb039084602c6da9e788dd45a"
|
||||
|
||||
Reference in New Issue
Block a user