diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..c5d5bfc
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,5 @@
+{
+ "tabWidth": 4,
+ "useTabs": true,
+ "trailingComma": "es5"
+}
diff --git a/package.json b/package.json
index 2dd2cf1..afff676 100644
--- a/package.json
+++ b/package.json
@@ -3,10 +3,20 @@
"version": "0.1.0",
"private": true,
"dependencies": {
+ "@emotion/react": "^11.10.5",
+ "@emotion/styled": "^11.10.5",
+ "@mui/material": "^5.10.16",
"@react-oauth/google": "^0.4.0",
+ "@simplewebauthn/browser": "^6.2.2",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
+ "@types/jest": "24.0.17",
+ "@types/node": "12.6.9",
+ "@types/react": "16.8.24",
+ "@types/react-dom": "16.8.5",
+ "@types/react-router-dom": "^4.3.4",
+ "base64url": "^3.0.1",
"ethers": "^5.7.2",
"js-base64": "^3.7.2",
"lit-js-sdk": "^1.2.37",
@@ -15,6 +25,12 @@
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
+ "devDependencies": {
+ "prettier": "^1.18.2",
+ "tslint": "^5.19.0",
+ "tslint-config-prettier": "^1.18.0",
+ "typescript": "3.6.2"
+ },
"scripts": {
"start": "react-scripts start",
"build": "yarn fetchContracts && react-scripts build",
diff --git a/public/index.html b/public/index.html
index aa069f2..f03a2ce 100644
--- a/public/index.html
+++ b/public/index.html
@@ -25,6 +25,7 @@
Learn how to configure a non-root public URL by running `npm run build`.
-->
React App
+
diff --git a/src/App.js b/src/App.js
index 703c69f..4892ae3 100644
--- a/src/App.js
+++ b/src/App.js
@@ -3,324 +3,700 @@ import { ethers, utils } from "ethers";
import LitJsSdk from "lit-js-sdk";
import { useState } from "react";
import "./App.css";
+import { ButtonGroup, Button } from "@mui/material";
+import base64url from "base64url";
+import {
+ startRegistration,
+ startAuthentication,
+} from "@simplewebauthn/browser";
+import { parseAuthenticatorData } from "./utils/parseAuthenticatorData";
+import { decodeAttestationObject } from "./utils/decodeAttestationObject";
+import { hexlify } from "ethers/lib/utils";
window.LitJsSdk = LitJsSdk;
window.ethers = ethers;
const RELAY_API_URL =
- process.env.REACT_APP_RELAY_API_URL || "http://localhost:3001";
+ process.env.REACT_APP_RELAY_API_URL || "http://localhost:3001";
function App() {
- const [pkpEthAddress, setPkpEthAddress] = useState(null);
- const [googleCredentialResponse, setGoogleCredentialResponse] =
- useState(null);
- const [pkpPublicKey, setPkpPublicKey] = useState(null);
- const [status, setStatus] = useState("");
+ const [pkpEthAddress, setPkpEthAddress] = useState(null);
+ const [googleCredentialResponse, setGoogleCredentialResponse] = useState(
+ null
+ );
+ const [pkpPublicKey, setPkpPublicKey] = useState(null);
+ const [status, setStatus] = useState("");
+ const [selectedAuthMethod, setSelectedAuthMethod] = useState(6);
+ const [
+ webAuthnCredentialPublicKey,
+ setWebAuthnCredentialPublicKey,
+ ] = useState();
+ const [webAuthnSignature, setWebAuthnSignature] = useState();
+ const [webAuthnSignatureBase, setWebAuthnSignatureBase] = useState();
- const handleLoggedInToGoogle = async (credentialResponse) => {
- setStatus("Logged in to Google");
- console.log("Got response from google sign in: ", { credentialResponse });
- setGoogleCredentialResponse(credentialResponse);
- const requestId = await mintPkpWithRelayer(credentialResponse);
- await pollRequestUntilTerminalState(requestId);
- };
+ const handleLoggedInToGoogle = async credentialResponse => {
+ setStatus("Logged in to Google");
+ console.log("Got response from google sign in: ", {
+ credentialResponse,
+ });
+ setGoogleCredentialResponse(credentialResponse);
+ const requestId = await mintPkpUsingRelayerGoogleAuthVerificationEndpoint(
+ credentialResponse,
+ setStatus
+ );
+ await pollRequestUntilTerminalState(
+ requestId,
+ setStatus,
+ ({ pkpEthAddress, pkpPublicKey }) => {
+ setPkpEthAddress(pkpEthAddress);
+ setPkpPublicKey(pkpPublicKey);
+ }
+ );
+ };
- const mintPkpWithRelayer = async (credentialResponse) => {
- setStatus("Minting PKP with relayer...");
+ return (
+
+
+
Welcome To The PKP Demo!
+
+
Choose an authentication method to begin:
+
+
+
+
+
+
{status}
+
+ {selectedAuthMethod === 6 && (
+ <>
+
+ Step 1: log in with Google. Upon OAuth success, we will
+ mint a PKP on your behalf.
+
+
{
+ console.log("Login Failed");
+ }}
+ useOneTap
+ />
+ {pkpEthAddress && (
+ PKP Eth Address: {pkpEthAddress}
+ )}
+
+ Step 2: Use Lit Network to obtain a session sig and then
+ store an encryption condition.
+
+
+ >
+ )}
+ {selectedAuthMethod === 3 && (
+ <>
+ Step 1: Register using WebAuthn.
+
+ Step 2: Authenticate using WebAuthn to mint PKP.
+ {
+ await handleWebAuthnAuthenticate(
+ setStatus,
+ webAuthnCredentialPublicKey,
+ ({ pkpEthAddress, pkpPublicKey }) => {
+ setPkpEthAddress(pkpEthAddress);
+ setPkpPublicKey(pkpPublicKey);
+ },
+ setWebAuthnSignature,
+ setWebAuthnSignatureBase
+ );
+ }}
+ >
+ Authenticate
+
+
+ Step 3: Use Lit Network to obtain a session sig and then
+ store an encryption condition.
+
+
+ handleStoreEncryptionCondition(
+ setStatus,
+ selectedAuthMethod,
+ googleCredentialResponse,
+ {
+ signature: webAuthnSignature,
+ signatureBase: webAuthnSignatureBase,
+ credentialPublicKey: webAuthnCredentialPublicKey,
+ },
+ pkpEthAddress,
+ pkpPublicKey
+ )
+ }
+ >
+ Encrypt With Lit
+
+ >
+ )}
+
+ );
}
export default App;
+
+async function mintPkpUsingRelayerGoogleAuthVerificationEndpoint(
+ credentialResponse,
+ setStatusFn
+) {
+ setStatusFn("Minting PKP with relayer...");
+
+ const mintRes = await fetch(`${RELAY_API_URL}/auth/google`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ idToken: credentialResponse.credential,
+ }),
+ });
+
+ if (mintRes.status < 200 || mintRes.status >= 400) {
+ console.warn("Something wrong with the API call", await mintRes.json());
+ setStatusFn("Uh oh, something's not quite right.");
+ return null;
+ } else {
+ const resBody = await mintRes.json();
+ console.log("Response OK", { body: resBody });
+ setStatusFn("Successfully initiated minting PKP with relayer.");
+ return resBody.requestId;
+ }
+}
+
+async function mintPkpUsingRelayerWebAuthnVerificationEndpoint(
+ signature,
+ signatureBase,
+ credentialPublicKey,
+ setStatusFn
+) {
+ setStatusFn("Minting PKP with relayer...");
+
+ const mintRes = await fetch(`${RELAY_API_URL}/auth/webauthn`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ signature,
+ signatureBase,
+ credentialPublicKey,
+ }),
+ });
+
+ if (mintRes.status < 200 || mintRes.status >= 400) {
+ console.warn("Something wrong with the API call", await mintRes.json());
+ setStatusFn("Uh oh, something's not quite right.");
+ return null;
+ } else {
+ const resBody = await mintRes.json();
+ console.log("Response OK", { body: resBody });
+ setStatusFn("Successfully initiated minting PKP with relayer.");
+ return resBody.requestId;
+ }
+}
+
+async function pollRequestUntilTerminalState(
+ requestId,
+ setStatusFn,
+ onSuccess
+) {
+ if (!requestId) {
+ return;
+ }
+
+ const maxPollCount = 20;
+ for (let i = 0; i < maxPollCount; i++) {
+ setStatusFn(`Waiting for auth completion (poll #${i + 1})`);
+ const getAuthStatusRes = await fetch(
+ `${RELAY_API_URL}/auth/status/${requestId}`
+ );
+
+ if (getAuthStatusRes.status < 200 || getAuthStatusRes.status >= 400) {
+ console.warn(
+ "Something wrong with the API call",
+ await getAuthStatusRes.json()
+ );
+ setStatusFn("Uh oh, something's not quite right.");
+ return;
+ }
+
+ const resBody = await getAuthStatusRes.json();
+ console.log("Response OK", { body: resBody });
+
+ if (resBody.error) {
+ // exit loop since error
+ console.warn("Something wrong with the API call", {
+ error: resBody.error,
+ });
+ setStatusFn("Uh oh, something's not quite right.");
+ return;
+ } else if (resBody.status === "Succeeded") {
+ // exit loop since success
+ console.info("Successfully authed", { ...resBody });
+ setStatusFn("Successfully authed and minted PKP!");
+ onSuccess({
+ pkpEthAddress: resBody.pkpEthAddress,
+ pkpPublicKey: resBody.pkpPublicKey,
+ });
+ return;
+ }
+
+ // otherwise, sleep then continue polling
+ await new Promise(r => setTimeout(r, 15000));
+ }
+
+ // at this point, polling ended and still no success, set failure status
+ setStatusFn(`Hmm this is taking longer than expected...`);
+}
+
+async function handleStoreEncryptionCondition(
+ setStatusFn,
+ selectedAuthMethod,
+ googleCredentialResponse,
+ webAuthnVerificationMaterial,
+ pkpEthAddress,
+ pkpPublicKey
+) {
+ setStatusFn("Storing encryption condition...");
+ var unifiedAccessControlConditions = [
+ {
+ conditionType: "evmBasic",
+ contractAddress: "",
+ standardContractType: "",
+ chain: "mumbai",
+ method: "",
+ parameters: [":userAddress"],
+ returnValueTest: {
+ comparator: "=",
+ value: pkpEthAddress,
+ },
+ },
+ ];
+
+ // this will be fired if auth is needed. we can use this to prompt the user to sign in
+ const authNeededCallback = async ({
+ chain,
+ resources,
+ expiration,
+ uri,
+ litNodeClient,
+ }) => {
+ console.log("authNeededCallback fired");
+ const authMethods =
+ selectedAuthMethod === 6
+ ? [
+ {
+ authMethodType: 6,
+ accessToken: googleCredentialResponse.credential,
+ },
+ ]
+ : [
+ {
+ authMethodType: 3,
+ accessToken: JSON.stringify(
+ webAuthnVerificationMaterial
+ ),
+ },
+ ];
+ const sessionSig = await litNodeClient.signSessionKey({
+ sessionKey: uri,
+ authMethods,
+ pkpPublicKey,
+ expiration,
+ resources,
+ chain,
+ });
+ console.log("got session sig from node and PKP: ", sessionSig);
+ return sessionSig;
+ };
+
+ // get the user a session with it
+ const litNodeClient = new LitJsSdk.LitNodeClient({
+ litNetwork: "serrano",
+ });
+ await litNodeClient.connect();
+
+ const sessionSigs = await litNodeClient.getSessionSigs({
+ expiration: new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString(), // 24 hours
+ chain: "ethereum",
+ resources: [`litEncryptionCondition://*`],
+ sessionCapabilityObject: {
+ def: ["litEncryptionCondition"],
+ },
+ switchChain: false,
+ authNeededCallback,
+ });
+ console.log("sessionSigs before saving encryption key: ", sessionSigs);
+
+ const { encryptedZip, symmetricKey } = await LitJsSdk.zipAndEncryptString(
+ "this is a secret message"
+ );
+
+ // value parameter - hash unified conditions
+ const hashedAccessControlConditions = await LitJsSdk.hashUnifiedAccessControlConditions(
+ unifiedAccessControlConditions
+ );
+ console.log("hashedAccessControlConditions", {
+ hashedAccessControlConditions,
+ });
+ const hashedAccessControlConditionsStr = LitJsSdk.uint8arrayToString(
+ new Uint8Array(hashedAccessControlConditions),
+ "base16"
+ );
+
+ // key parameter - encrypt symmetric key then hash it
+ const encryptedSymmetricKey = LitJsSdk.encryptWithBlsPubkey({
+ pubkey: litNodeClient.networkPubKey,
+ data: symmetricKey,
+ });
+ const hashedEncryptedSymmetricKeyStr = await LitJsSdk.hashEncryptionKey({
+ encryptedSymmetricKey,
+ });
+
+ // securityHash parameter - encrypt symmetric key, concat with creator address
+ const pkpEthAddressBytes = utils.arrayify(pkpEthAddress);
+ const securityHashPreimage = new Uint8Array([
+ ...encryptedSymmetricKey,
+ ...pkpEthAddressBytes,
+ ]);
+ // TODO: LitJsSdk.hashEncryptionKey ought to be renamed to just .hashBytes
+ const securityHashStr = await LitJsSdk.hashEncryptionKey({
+ encryptedSymmetricKey: securityHashPreimage,
+ });
+
+ console.log("Storing encryption condition with relay", {
+ hashedEncryptedSymmetricKeyStr,
+ hashedAccessControlConditionsStr,
+ securityHashStr,
+ sessionSig: sessionSigs["https://serrano.litgateway.com:7370"],
+ });
+
+ // call centralized conditions relayer to write encryption conditions to chain.
+ const storeRes = await fetch(`${RELAY_API_URL}/store-condition`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ key: hashedEncryptedSymmetricKeyStr,
+ value: hashedAccessControlConditionsStr,
+ securityHash: securityHashStr,
+ chainId: "1",
+ permanent: false,
+ capabilityProtocolPrefix: "litEncryptionCondition",
+ // just choose any one session signature that is generated.
+ sessionSig: sessionSigs["https://serrano.litgateway.com:7370"],
+ }),
+ });
+
+ if (storeRes.status < 200 || storeRes.status >= 400) {
+ console.warn(
+ "Something wrong with the API call",
+ await storeRes.json()
+ );
+ setStatusFn("Uh oh, something's not quite right");
+ } else {
+ setStatusFn("Successfully stored encryption condition with relayer!");
+ }
+}
+
+async function handleEncryptThenDecrypt(
+ setStatusFn,
+ googleCredentialResponse,
+ pkpEthAddress,
+ pkpPublicKey
+) {
+ setStatusFn("Encrypting then decrypting...");
+ var unifiedAccessControlConditions = [
+ {
+ conditionType: "evmBasic",
+ contractAddress: "",
+ standardContractType: "",
+ chain: "mumbai",
+ method: "",
+ parameters: [":userAddress"],
+ returnValueTest: {
+ comparator: "=",
+ value: pkpEthAddress,
+ },
+ },
+ ];
+
+ // this will be fired if auth is needed. we can use this to prompt the user to sign in
+ const authNeededCallback = async ({
+ chain,
+ resources,
+ expiration,
+ uri,
+ litNodeClient,
+ }) => {
+ console.log("authNeededCallback fired");
+ const sessionSig = await litNodeClient.signSessionKey({
+ sessionKey: uri,
+ authMethods: [
+ {
+ authMethodType: 6,
+ accessToken: googleCredentialResponse.credential,
+ },
+ ],
+ pkpPublicKey,
+ expiration,
+ resources,
+ chain,
+ });
+ console.log("got session sig from node and PKP: ", sessionSig);
+ return sessionSig;
+ };
+
+ // get the user a session with it
+ const litNodeClient = new LitJsSdk.LitNodeClient({
+ litNetwork: "serrano",
+ });
+ await litNodeClient.connect();
+
+ const sessionSigs = await litNodeClient.getSessionSigs({
+ expiration: new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString(), // 24 hours
+ chain: "ethereum",
+ resources: [`litEncryptionCondition://*`],
+ switchChain: false,
+ authNeededCallback,
+ });
+ console.log("sessionSigs before saving encryption key: ", sessionSigs);
+
+ const { encryptedZip, symmetricKey } = await LitJsSdk.zipAndEncryptString(
+ "this is a secret message"
+ );
+
+ const encryptedSymmetricKey = await litNodeClient.saveEncryptionKey({
+ unifiedAccessControlConditions,
+ symmetricKey,
+ sessionSigs,
+ });
+
+ const hashOfKey = await LitJsSdk.hashEncryptionKey({
+ encryptedSymmetricKey,
+ });
+
+ console.log("encrypted symmetric key", encryptedSymmetricKey);
+
+ const retrievedSymmKey = await litNodeClient.getEncryptionKey({
+ unifiedAccessControlConditions,
+ toDecrypt: LitJsSdk.uint8arrayToString(encryptedSymmetricKey, "base16"),
+ sessionSigs,
+ });
+
+ const decryptedFiles = await LitJsSdk.decryptZip(
+ encryptedZip,
+ retrievedSymmKey
+ );
+ const decryptedString = await decryptedFiles["string.txt"].async("text");
+ console.log("decrypted string", decryptedString);
+
+ setStatusFn("Success!");
+}
+
+async function handleWebAuthnRegister(setStatusFn, onSuccess) {
+ const resp = await fetch(`${RELAY_API_URL}/generate-registration-options`);
+
+ let attResp;
+ try {
+ const opts = await resp.json();
+
+ // Require a resident key for this demo
+ opts.authenticatorSelection.residentKey = "required";
+ opts.authenticatorSelection.requireResidentKey = true;
+ opts.extensions = {
+ credProps: true,
+ };
+
+ attResp = await startRegistration(opts);
+ } catch (error) {
+ // TODO: Handle error
+ throw error;
+ }
+
+ console.log("attResp", { attResp });
+
+ const verificationResp = await fetch(
+ `${RELAY_API_URL}/verify-registration`,
+ {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(attResp),
+ }
+ );
+
+ const verificationJSON = await verificationResp.json();
+
+ if (verificationJSON && verificationJSON.verified) {
+ setStatusFn("Successfully registered using WebAuthn!");
+ onSuccess({ attResp });
+ } else {
+ setStatusFn(
+ "Oh no, something went wrong during WebAuthn registration."
+ );
+ console.error("Error during WebAuthn registration", {
+ err: JSON.stringify(verificationJSON),
+ });
+ }
+}
+
+async function handleWebAuthnAuthenticate(
+ setStatusFn,
+ webAuthnCredentialPublicKey,
+ onSuccess,
+ setWebAuthnSignatureFn,
+ setWebAuthnSignatureBaseFn
+) {
+ const resp = await fetch(
+ `${RELAY_API_URL}/generate-authentication-options`
+ );
+
+ let asseResp;
+ try {
+ const opts = await resp.json();
+
+ asseResp = await startAuthentication(opts);
+ } catch (error) {
+ // TODO: handle error
+ throw error;
+ }
+
+ const verificationResp = await fetch(
+ `${RELAY_API_URL}/verify-authentication`,
+ {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(asseResp),
+ }
+ );
+
+ const verificationJSON = await verificationResp.json();
+
+ if (verificationJSON && verificationJSON.verified) {
+ setStatusFn("Successfully authenticated using WebAuthn!");
+ } else {
+ setStatusFn(
+ "Oh no, something went wrong during WebAuthn authentication."
+ );
+ console.error("Error during WebAuthn authentication", {
+ err: JSON.stringify(verificationJSON),
+ });
+ }
+
+ const clientDataHash = await crypto.subtle.digest(
+ "SHA-256",
+ base64url.toBuffer(asseResp.response.clientDataJSON)
+ );
+
+ const authDataBuffer = base64url.toBuffer(
+ asseResp.response.authenticatorData
+ );
+
+ const signatureBase = Buffer.concat([
+ authDataBuffer,
+ Buffer.from(clientDataHash),
+ ]);
+
+ const signature = base64url.toBuffer(asseResp.response.signature);
+
+ // mint PKP using Relayer
+ console.log("Minting PKP using Relayer...", {
+ signature: hexlify(signature),
+ signatureBase: hexlify(signatureBase),
+ webAuthnCredentialPublicKey,
+ });
+ const requestId = await mintPkpUsingRelayerWebAuthnVerificationEndpoint(
+ hexlify(signature),
+ hexlify(signatureBase),
+ webAuthnCredentialPublicKey,
+ setStatusFn
+ );
+
+ // Poll until success
+ await pollRequestUntilTerminalState(requestId, setStatusFn, onSuccess);
+
+ // Update state
+ setWebAuthnSignatureFn(hexlify(signature));
+ setWebAuthnSignatureBaseFn(hexlify(signatureBase));
+}
diff --git a/src/utils/cbor.ts b/src/utils/cbor.ts
new file mode 100644
index 0000000..3bef211
--- /dev/null
+++ b/src/utils/cbor.ts
@@ -0,0 +1,33 @@
+// copy-🍝 from https://github.com/MasterKale/SimpleWebAuthn/blob/33528afe001d4aca62052dce204c0398c3127ffd/packages/server/src/helpers/decodeCbor.ts
+
+export function decodeCborFirst(
+ cbor: any,
+ input:
+ | string
+ | Buffer
+ | ArrayBuffer
+ | Uint8Array
+ | Uint8ClampedArray
+ | DataView
+): any {
+ try {
+ // throws if there are extra bytes
+ return cbor.decodeFirstSync(input);
+ } catch (err) {
+ const _err = err as CborDecoderError;
+ // if the error was due to extra bytes, return the unpacked value
+ if (_err.value) {
+ return _err.value;
+ }
+ throw err;
+ }
+}
+
+/**
+ * Intuited from a quick scan of `cbor.decodeFirstSync()` here:
+ *
+ * https://github.com/hildjj/node-cbor/blob/v5.1.0/lib/decoder.js#L189
+ */
+class CborDecoderError extends Error {
+ value: any;
+}
diff --git a/src/utils/decodeAttestationObject.ts b/src/utils/decodeAttestationObject.ts
new file mode 100644
index 0000000..f25111a
--- /dev/null
+++ b/src/utils/decodeAttestationObject.ts
@@ -0,0 +1,39 @@
+// copy-🍝 from https://github.com/MasterKale/SimpleWebAuthn/blob/33528afe001d4aca62052dce204c0398c3127ffd/packages/server/src/helpers/decodeAttestationObject.ts#L8
+
+/**
+ * Convert an AttestationObject buffer to a proper object
+ *
+ * @param base64AttestationObject Attestation Object buffer
+ */
+export function decodeAttestationObject(
+ cbor: any,
+ attestationObject: Buffer
+): AttestationObject {
+ const toCBOR: AttestationObject = cbor.decodeAllSync(attestationObject)[0];
+ return toCBOR;
+}
+
+export type AttestationFormat =
+ | "fido-u2f"
+ | "packed"
+ | "android-safetynet"
+ | "android-key"
+ | "tpm"
+ | "apple"
+ | "none";
+
+export type AttestationObject = {
+ fmt: AttestationFormat;
+ attStmt: AttestationStatement;
+ authData: Buffer;
+};
+
+export type AttestationStatement = {
+ sig?: Buffer;
+ x5c?: Buffer[];
+ response?: Buffer;
+ alg?: number;
+ ver?: string;
+ certInfo?: Buffer;
+ pubArea?: Buffer;
+};
diff --git a/src/utils/decodeAuthenticatorExtensions.js b/src/utils/decodeAuthenticatorExtensions.js
new file mode 100644
index 0000000..5a50cef
--- /dev/null
+++ b/src/utils/decodeAuthenticatorExtensions.js
@@ -0,0 +1,19 @@
+// copy-🍝 from https://github.com/MasterKale/SimpleWebAuthn/blob/33528afe001d4aca62052dce204c0398c3127ffd/packages/server/src/helpers/decodeAuthenticatorExtensions.ts
+
+/**
+ * Convert authenticator extension data buffer to a proper object
+ *
+ * @param extensionData Authenticator Extension Data buffer
+ */
+export function decodeAuthenticatorExtensions(cbor, extensionData) {
+ let toCBOR;
+ try {
+ toCBOR = cbor.decodeAllSync(extensionData)[0];
+ } catch (err) {
+ const _err = err;
+ throw new Error(
+ `Error decoding authenticator extensions: ${_err.message}`
+ );
+ }
+ return toCBOR;
+}
diff --git a/src/utils/parseAuthenticatorData.ts b/src/utils/parseAuthenticatorData.ts
new file mode 100644
index 0000000..ed0e667
--- /dev/null
+++ b/src/utils/parseAuthenticatorData.ts
@@ -0,0 +1,112 @@
+import { decodeCborFirst } from "./cbor";
+import { decodeAuthenticatorExtensions } from "./decodeAuthenticatorExtensions";
+
+/**
+ * Make sense of the authData buffer contained in an Attestation
+ */
+export function parseAuthenticatorData(
+ cbor: any,
+ authData: Buffer
+): ParsedAuthenticatorData {
+ if (authData.byteLength < 37) {
+ throw new Error(
+ `Authenticator data was ${authData.byteLength} bytes, expected at least 37 bytes`
+ );
+ }
+
+ let pointer = 0;
+
+ const rpIdHash = authData.slice(pointer, (pointer += 32));
+
+ const flagsBuf = authData.slice(pointer, (pointer += 1));
+ const flagsInt = flagsBuf[0];
+
+ // Bit positions can be referenced here:
+ // https://www.w3.org/TR/webauthn-2/#flags
+ const flags = {
+ up: !!(flagsInt & (1 << 0)), // User Presence
+ uv: !!(flagsInt & (1 << 2)), // User Verified
+ be: !!(flagsInt & (1 << 3)), // Backup Eligibility
+ bs: !!(flagsInt & (1 << 4)), // Backup State
+ at: !!(flagsInt & (1 << 6)), // Attested Credential Data Present
+ ed: !!(flagsInt & (1 << 7)), // Extension Data Present
+ flagsInt,
+ };
+
+ const counterBuf = authData.slice(pointer, (pointer += 4));
+ const counter = counterBuf.readUInt32BE(0);
+
+ let aaguid: Buffer | undefined = undefined;
+ let credentialID: Buffer | undefined = undefined;
+ let credentialPublicKey: Buffer | undefined = undefined;
+
+ if (flags.at) {
+ aaguid = authData.slice(pointer, (pointer += 16));
+
+ const credIDLenBuf = authData.slice(pointer, (pointer += 2));
+ const credIDLen = credIDLenBuf.readUInt16BE(0);
+
+ credentialID = authData.slice(pointer, (pointer += credIDLen));
+
+ // Decode the next CBOR item in the buffer, then re-encode it back to a Buffer
+ const firstDecoded = decodeCborFirst(cbor, authData.slice(pointer));
+ const firstEncoded = Buffer.from(cbor.encode(firstDecoded));
+ credentialPublicKey = firstEncoded;
+ pointer += firstEncoded.byteLength;
+ }
+
+ let extensionsData: any | undefined = undefined;
+ let extensionsDataBuffer: Buffer | undefined = undefined;
+
+ if (flags.ed) {
+ const firstDecoded = decodeCborFirst(cbor, authData.slice(pointer));
+ const firstEncoded = Buffer.from(cbor.encode(firstDecoded));
+ extensionsDataBuffer = firstEncoded;
+ extensionsData = decodeAuthenticatorExtensions(
+ cbor,
+ extensionsDataBuffer
+ );
+ pointer += firstEncoded.byteLength;
+ }
+
+ // Pointer should be at the end of the authenticator data, otherwise too much data was sent
+ if (authData.byteLength > pointer) {
+ throw new Error(
+ "Leftover bytes detected while parsing authenticator data"
+ );
+ }
+
+ return {
+ rpIdHash,
+ flagsBuf,
+ flags,
+ counter,
+ counterBuf,
+ aaguid,
+ credentialID,
+ credentialPublicKey,
+ extensionsData,
+ extensionsDataBuffer,
+ };
+}
+
+export type ParsedAuthenticatorData = {
+ rpIdHash: Buffer;
+ flagsBuf: Buffer;
+ flags: {
+ up: boolean;
+ uv: boolean;
+ be: boolean;
+ bs: boolean;
+ at: boolean;
+ ed: boolean;
+ flagsInt: number;
+ };
+ counter: number;
+ counterBuf: Buffer;
+ aaguid?: Buffer;
+ credentialID?: Buffer;
+ credentialPublicKey?: Buffer;
+ extensionsData?: any;
+ extensionsDataBuffer?: Buffer;
+};
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..89ccc6b
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,25 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "lib": [
+ "dom",
+ "dom.iterable",
+ "esnext"
+ ],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "preserve"
+ },
+ "include": [
+ "src"
+ ]
+}
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index 330a414..daef8b4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -167,7 +167,7 @@
dependencies:
"@babel/types" "^7.18.9"
-"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.18.6":
+"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e"
integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==
@@ -523,7 +523,7 @@
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
-"@babel/plugin-syntax-jsx@^7.18.6":
+"@babel/plugin-syntax-jsx@^7.17.12", "@babel/plugin-syntax-jsx@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0"
integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==
@@ -1040,6 +1040,13 @@
dependencies:
regenerator-runtime "^0.13.10"
+"@babel/runtime@^7.18.3", "@babel/runtime@^7.20.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.7":
+ version "7.20.6"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.6.tgz#facf4879bfed9b5326326273a64220f099b0fce3"
+ integrity sha512-Q+8MqP7TiHMWzSfwiJwXCjyf4GYA4Dgw3emg/7xmwsdLJOZUp+nMqcOwOzzYheuM1rhDu8FSj2l0aoMygEuXuA==
+ dependencies:
+ regenerator-runtime "^0.13.11"
+
"@babel/template@^7.18.10", "@babel/template@^7.3.3":
version "7.18.10"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71"
@@ -1190,6 +1197,114 @@
resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz#1bfafe4b7ed0f3e4105837e056e0a89b108ebe36"
integrity sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==
+"@emotion/babel-plugin@^11.10.5":
+ version "11.10.5"
+ resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.10.5.tgz#65fa6e1790ddc9e23cc22658a4c5dea423c55c3c"
+ integrity sha512-xE7/hyLHJac7D2Ve9dKroBBZqBT7WuPQmWcq7HSGb84sUuP4mlOWoB8dvVfD9yk5DHkU1m6RW7xSoDtnQHNQeA==
+ dependencies:
+ "@babel/helper-module-imports" "^7.16.7"
+ "@babel/plugin-syntax-jsx" "^7.17.12"
+ "@babel/runtime" "^7.18.3"
+ "@emotion/hash" "^0.9.0"
+ "@emotion/memoize" "^0.8.0"
+ "@emotion/serialize" "^1.1.1"
+ babel-plugin-macros "^3.1.0"
+ convert-source-map "^1.5.0"
+ escape-string-regexp "^4.0.0"
+ find-root "^1.1.0"
+ source-map "^0.5.7"
+ stylis "4.1.3"
+
+"@emotion/cache@^11.10.5":
+ version "11.10.5"
+ resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.10.5.tgz#c142da9351f94e47527ed458f7bbbbe40bb13c12"
+ integrity sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==
+ dependencies:
+ "@emotion/memoize" "^0.8.0"
+ "@emotion/sheet" "^1.2.1"
+ "@emotion/utils" "^1.2.0"
+ "@emotion/weak-memoize" "^0.3.0"
+ stylis "4.1.3"
+
+"@emotion/hash@^0.9.0":
+ version "0.9.0"
+ resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.0.tgz#c5153d50401ee3c027a57a177bc269b16d889cb7"
+ integrity sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==
+
+"@emotion/is-prop-valid@^1.2.0":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz#7f2d35c97891669f7e276eb71c83376a5dc44c83"
+ integrity sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==
+ dependencies:
+ "@emotion/memoize" "^0.8.0"
+
+"@emotion/memoize@^0.8.0":
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.0.tgz#f580f9beb67176fa57aae70b08ed510e1b18980f"
+ integrity sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==
+
+"@emotion/react@^11.10.5":
+ version "11.10.5"
+ resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.10.5.tgz#95fff612a5de1efa9c0d535384d3cfa115fe175d"
+ integrity sha512-TZs6235tCJ/7iF6/rvTaOH4oxQg2gMAcdHemjwLKIjKz4rRuYe1HJ2TQJKnAcRAfOUDdU8XoDadCe1rl72iv8A==
+ dependencies:
+ "@babel/runtime" "^7.18.3"
+ "@emotion/babel-plugin" "^11.10.5"
+ "@emotion/cache" "^11.10.5"
+ "@emotion/serialize" "^1.1.1"
+ "@emotion/use-insertion-effect-with-fallbacks" "^1.0.0"
+ "@emotion/utils" "^1.2.0"
+ "@emotion/weak-memoize" "^0.3.0"
+ hoist-non-react-statics "^3.3.1"
+
+"@emotion/serialize@^1.1.1":
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.1.tgz#0595701b1902feded8a96d293b26be3f5c1a5cf0"
+ integrity sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==
+ dependencies:
+ "@emotion/hash" "^0.9.0"
+ "@emotion/memoize" "^0.8.0"
+ "@emotion/unitless" "^0.8.0"
+ "@emotion/utils" "^1.2.0"
+ csstype "^3.0.2"
+
+"@emotion/sheet@^1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.1.tgz#0767e0305230e894897cadb6c8df2c51e61a6c2c"
+ integrity sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==
+
+"@emotion/styled@^11.10.5":
+ version "11.10.5"
+ resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.10.5.tgz#1fe7bf941b0909802cb826457e362444e7e96a79"
+ integrity sha512-8EP6dD7dMkdku2foLoruPCNkRevzdcBaY6q0l0OsbyJK+x8D9HWjX27ARiSIKNF634hY9Zdoedh8bJCiva8yZw==
+ dependencies:
+ "@babel/runtime" "^7.18.3"
+ "@emotion/babel-plugin" "^11.10.5"
+ "@emotion/is-prop-valid" "^1.2.0"
+ "@emotion/serialize" "^1.1.1"
+ "@emotion/use-insertion-effect-with-fallbacks" "^1.0.0"
+ "@emotion/utils" "^1.2.0"
+
+"@emotion/unitless@^0.8.0":
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.0.tgz#a4a36e9cbdc6903737cd20d38033241e1b8833db"
+ integrity sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==
+
+"@emotion/use-insertion-effect-with-fallbacks@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz#ffadaec35dbb7885bd54de3fa267ab2f860294df"
+ integrity sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==
+
+"@emotion/utils@^1.2.0":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.0.tgz#9716eaccbc6b5ded2ea5a90d65562609aab0f561"
+ integrity sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==
+
+"@emotion/weak-memoize@^0.3.0":
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz#ea89004119dc42db2e1dba0f97d553f7372f6fcb"
+ integrity sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==
+
"@eslint/eslintrc@^1.3.3":
version "1.3.3"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.3.tgz#2b044ab39fdfa75b4688184f9e573ce3c5b0ff95"
@@ -1896,6 +2011,92 @@
resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b"
integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==
+"@mui/base@5.0.0-alpha.108":
+ version "5.0.0-alpha.108"
+ resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-alpha.108.tgz#4e4639ba6769dd178ef475dba4cc36bf8a3f1dc6"
+ integrity sha512-KjzRUts2i/ODlMfywhFTqTzQl+Cr9nlDSZxJcnYjrbOV/iRyQNBTDoiFJt+XEdRi0fZBHnk74AFbnP56ehybsA==
+ dependencies:
+ "@babel/runtime" "^7.20.1"
+ "@emotion/is-prop-valid" "^1.2.0"
+ "@mui/types" "^7.2.2"
+ "@mui/utils" "^5.10.16"
+ "@popperjs/core" "^2.11.6"
+ clsx "^1.2.1"
+ prop-types "^15.8.1"
+ react-is "^18.2.0"
+
+"@mui/core-downloads-tracker@^5.10.16":
+ version "5.10.16"
+ resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.10.16.tgz#4c2d36bcab58cb6250596b20601f499bfadc0642"
+ integrity sha512-eK9+olw2ZbXX+vGrtKnN01/vLP1aX0Lq0xok35bqWM1aB93Dcmky/xPNf8h31oJ/C+IzJBjZaZMEDzVZg4Qc0A==
+
+"@mui/material@^5.10.16":
+ version "5.10.16"
+ resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.10.16.tgz#4ad6e69d81f11487f502591d8d060143d2e89b97"
+ integrity sha512-JSHcDQQ+k30NKkCM/0KX6jq4F5LOrbFKZpS+cEl7scZWOCJpUPH5ccAT5a7O8wzrgNZ8Y9PnwzNvWBrfShpJFw==
+ dependencies:
+ "@babel/runtime" "^7.20.1"
+ "@mui/base" "5.0.0-alpha.108"
+ "@mui/core-downloads-tracker" "^5.10.16"
+ "@mui/system" "^5.10.16"
+ "@mui/types" "^7.2.2"
+ "@mui/utils" "^5.10.16"
+ "@types/react-transition-group" "^4.4.5"
+ clsx "^1.2.1"
+ csstype "^3.1.1"
+ prop-types "^15.8.1"
+ react-is "^18.2.0"
+ react-transition-group "^4.4.5"
+
+"@mui/private-theming@^5.10.16":
+ version "5.10.16"
+ resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.10.16.tgz#181ab7568a3cf0c6b12cc12f5a91aeb4509df1ce"
+ integrity sha512-0MArkJaOHRCKqL/GWjngGZmyOeRz+uxffhx82bKcewr8swqV7xx7EFP02pk0L/gLdfcvYdqwH4YTVjG/+TaKrg==
+ dependencies:
+ "@babel/runtime" "^7.20.1"
+ "@mui/utils" "^5.10.16"
+ prop-types "^15.8.1"
+
+"@mui/styled-engine@^5.10.16":
+ version "5.10.16"
+ resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.10.16.tgz#52a2d31e4012958d21c92b42acaca4c3e79841b4"
+ integrity sha512-ZMSjXvtiGwGDKqrSlXhpxK2voUaF2/lpC/pSTfFmZvKH9j9a9h1/iwo3ybgjFVYGgbfNeW4h0xEchiRohu9xsw==
+ dependencies:
+ "@babel/runtime" "^7.20.1"
+ "@emotion/cache" "^11.10.5"
+ csstype "^3.1.1"
+ prop-types "^15.8.1"
+
+"@mui/system@^5.10.16":
+ version "5.10.16"
+ resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.10.16.tgz#2b07d78eb5e337463045b81a59f718795807fdc7"
+ integrity sha512-OqI9B1jZ9zQ/dmoqseku4CzdEs9DbLiiMOaWxC3WeAJxM1UavlCgXz0encqm93LIlmSL7TjuHN1/rW8BJCnU8A==
+ dependencies:
+ "@babel/runtime" "^7.20.1"
+ "@mui/private-theming" "^5.10.16"
+ "@mui/styled-engine" "^5.10.16"
+ "@mui/types" "^7.2.2"
+ "@mui/utils" "^5.10.16"
+ clsx "^1.2.1"
+ csstype "^3.1.1"
+ prop-types "^15.8.1"
+
+"@mui/types@^7.2.2":
+ version "7.2.2"
+ resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.2.tgz#723f6d40c25c89c2e0352a7e51794e8eb77cdbe3"
+ integrity sha512-siex8cZDtWeC916cXOoUOnEQQejuMYmHtc4hM6VkKVYaBICz3VIiqyiAomRboTQHt2jchxQ5Q5ATlbcDekTxDA==
+
+"@mui/utils@^5.10.16":
+ version "5.10.16"
+ resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.10.16.tgz#7a981444855968ebdb1830d76e298d1ac47eaaf6"
+ integrity sha512-3MB/SGsgiiu9Z55CFmAfiONUoR7AAue/H4F6w3mc2LnhFQCsoVvXhioDPcsiRpUMIQr34jDPzGXdCuqWooPCXQ==
+ dependencies:
+ "@babel/runtime" "^7.20.1"
+ "@types/prop-types" "^15.7.5"
+ "@types/react-is" "^16.7.1 || ^17.0.0"
+ prop-types "^15.8.1"
+ react-is "^18.2.0"
+
"@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1":
version "5.1.1-v1"
resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129"
@@ -1944,6 +2145,11 @@
schema-utils "^3.0.0"
source-map "^0.7.3"
+"@popperjs/core@^2.11.6":
+ version "2.11.6"
+ resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45"
+ integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==
+
"@react-oauth/google@^0.4.0":
version "0.4.0"
resolved "https://registry.yarnpkg.com/@react-oauth/google/-/google-0.4.0.tgz#ae4fe2724040bd11facdc53aad43a21e9f34b2c9"
@@ -1991,6 +2197,11 @@
resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz#8be36a1f66f3265389e90b5f9c9962146758f728"
integrity sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==
+"@simplewebauthn/browser@^6.2.2":
+ version "6.2.2"
+ resolved "https://registry.yarnpkg.com/@simplewebauthn/browser/-/browser-6.2.2.tgz#3cd773a9887734331251d1b8dec043547a7bbd57"
+ integrity sha512-VUtne7+s6BmW4usnbitjZEI1VNT/PNh6bYg+AI4OMdfpo5z+yAq+6iVAWBJlIUGVk5InetEQvTUp6OefBam8qg==
+
"@sinclair/typebox@^0.24.1":
version "0.24.51"
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.51.tgz#645f33fe4e02defe26f2f5c0410e1c094eac7f5f"
@@ -2335,6 +2546,18 @@
dependencies:
"@types/node" "*"
+"@types/history@*":
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/@types/history/-/history-5.0.0.tgz#29f919f0c8e302763798118f45b19cab4a886f14"
+ integrity sha512-hy8b7Y1J8OGe6LbAjj3xniQrj3v6lsivCcrmf4TzSgPzLkhIeKgc5IZnT7ReIqmEuodjfO8EYAuoFvIrHi/+jQ==
+ dependencies:
+ history "*"
+
+"@types/history@^4.7.11":
+ version "4.7.11"
+ resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64"
+ integrity sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==
+
"@types/html-minifier-terser@^6.0.0":
version "6.1.0"
resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35"
@@ -2366,6 +2589,13 @@
dependencies:
"@types/istanbul-lib-report" "*"
+"@types/jest-diff@*":
+ version "24.3.0"
+ resolved "https://registry.yarnpkg.com/@types/jest-diff/-/jest-diff-24.3.0.tgz#29e237a3d954babfe6e23cc59b57ecd8ca8d858d"
+ integrity sha512-vx1CRDeDUwQ0Pc7v+hS61O1ETA81kD04IMEC0hS1kPyVtHDdZrokAvpF7MT9VI/fVSzicelUZNCepDvhRV1PeA==
+ dependencies:
+ jest-diff "*"
+
"@types/jest@*":
version "29.2.2"
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.2.2.tgz#874e7dc6702fa6a3fe6107792aa98636dcc480b4"
@@ -2374,6 +2604,13 @@
expect "^29.0.0"
pretty-format "^29.0.0"
+"@types/jest@24.0.17":
+ version "24.0.17"
+ resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.0.17.tgz#b66ea026efb746eb5db1356ee28518aaff7af416"
+ integrity sha512-1cy3xkOAfSYn78dsBWy4M3h/QF/HeWPchNFDjysVtp3GHeTdSmtluNnELfCmfNRRHo0OWEcpf+NsEJQvwQfdqQ==
+ dependencies:
+ "@types/jest-diff" "*"
+
"@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
version "7.0.11"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
@@ -2394,6 +2631,11 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.9.tgz#02d013de7058cea16d36168ef2fc653464cfbad4"
integrity sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==
+"@types/node@12.6.9":
+ version "12.6.9"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-12.6.9.tgz#ffeee23afdc19ab16e979338e7b536fdebbbaeaf"
+ integrity sha512-+YB9FtyxXGyD54p8rXwWaN1EWEyar5L58GlGWgtH2I9rGmLGBQcw63+0jw+ujqVavNuO47S1ByAjm9zdHMnskw==
+
"@types/parse-json@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
@@ -2404,7 +2646,7 @@
resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.1.tgz#dfd20e2dc35f027cdd6c1908e80a5ddc7499670e"
integrity sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==
-"@types/prop-types@*":
+"@types/prop-types@*", "@types/prop-types@^15.7.5":
version "15.7.5"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf"
integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
@@ -2424,6 +2666,13 @@
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc"
integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==
+"@types/react-dom@16.8.5":
+ version "16.8.5"
+ resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.8.5.tgz#3e3f4d99199391a7fb40aa3a155c8dd99b899cbd"
+ integrity sha512-idCEjROZ2cqh29+trmTmZhsBAUNQuYrF92JHKzZ5+aiFM1mlSk3bb23CK7HhYuOY75Apgap5y2jTyHzaM2AJGA==
+ dependencies:
+ "@types/react" "*"
+
"@types/react-dom@^18.0.0":
version "18.0.8"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.8.tgz#d2606d855186cd42cc1b11e63a71c39525441685"
@@ -2431,6 +2680,37 @@
dependencies:
"@types/react" "*"
+"@types/react-is@^16.7.1 || ^17.0.0":
+ version "17.0.3"
+ resolved "https://registry.yarnpkg.com/@types/react-is/-/react-is-17.0.3.tgz#2d855ba575f2fc8d17ef9861f084acc4b90a137a"
+ integrity sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==
+ dependencies:
+ "@types/react" "*"
+
+"@types/react-router-dom@^4.3.4":
+ version "4.3.5"
+ resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-4.3.5.tgz#72f229967690c890d00f96e6b85e9ee5780db31f"
+ integrity sha512-eFajSUASYbPHg2BDM1G8Btx+YqGgvROPIg6sBhl3O4kbDdYXdFdfrgQFf/pcBuQVObjfT9AL/dd15jilR5DIEA==
+ dependencies:
+ "@types/history" "*"
+ "@types/react" "*"
+ "@types/react-router" "*"
+
+"@types/react-router@*":
+ version "5.1.19"
+ resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.19.tgz#9b404246fba7f91474d7008a3d48c17b6e075ad6"
+ integrity sha512-Fv/5kb2STAEMT3wHzdKQK2z8xKq38EDIGVrutYLmQVVLe+4orDFquU52hQrULnEHinMKv9FSA6lf9+uNT1ITtA==
+ dependencies:
+ "@types/history" "^4.7.11"
+ "@types/react" "*"
+
+"@types/react-transition-group@^4.4.5":
+ version "4.4.5"
+ resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.5.tgz#aae20dcf773c5aa275d5b9f7cdbca638abc5e416"
+ integrity sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==
+ dependencies:
+ "@types/react" "*"
+
"@types/react@*":
version "18.0.25"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.25.tgz#8b1dcd7e56fe7315535a4af25435e0bb55c8ae44"
@@ -2440,6 +2720,14 @@
"@types/scheduler" "*"
csstype "^3.0.2"
+"@types/react@16.8.24":
+ version "16.8.24"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-16.8.24.tgz#8d1ea1fcbfa214220da3d3c04e506f1077b0deac"
+ integrity sha512-VpFHUoD37YNY2+lr/+c7qL/tZsIU/bKuskUF3tmGUArbxIcQdb5j3zvo4cuuzu2A6UaVmVn7sJ4PgWYNFEBGzg==
+ dependencies:
+ "@types/prop-types" "*"
+ csstype "^2.2.0"
+
"@types/resolve@1.17.1":
version "1.17.1"
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6"
@@ -3416,6 +3704,11 @@ base64-js@^1.3.1:
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
+base64url@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/base64url/-/base64url-3.0.1.tgz#6399d572e2bc3f90a9a8b22d5dbb0a32d33f788d"
+ integrity sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==
+
batch@0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16"
@@ -3599,6 +3892,11 @@ bufferutil@^4.0.6:
dependencies:
node-gyp-build "^4.3.0"
+builtin-modules@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
+ integrity sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==
+
builtin-modules@^3.1.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
@@ -3670,7 +3968,7 @@ case-sensitive-paths-webpack-plugin@^2.4.0:
resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4"
integrity sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==
-chalk@^2.0.0, chalk@^2.4.1:
+chalk@^2.0.0, chalk@^2.3.0, chalk@^2.4.1:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@@ -3765,6 +4063,11 @@ cliui@^7.0.2:
strip-ansi "^6.0.0"
wrap-ansi "^7.0.0"
+clsx@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
+ integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
+
co@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
@@ -3825,7 +4128,7 @@ combined-stream@^1.0.8:
dependencies:
delayed-stream "~1.0.0"
-commander@^2.20.0:
+commander@^2.12.1, commander@^2.20.0:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
@@ -3902,7 +4205,7 @@ content-type@~1.0.4:
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
-convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
+convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f"
integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==
@@ -4187,7 +4490,12 @@ cssstyle@^2.3.0:
dependencies:
cssom "~0.3.6"
-csstype@^3.0.2:
+csstype@^2.2.0:
+ version "2.6.21"
+ resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.21.tgz#2efb85b7cc55c80017c66a5ad7cbd931fda3a90e"
+ integrity sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==
+
+csstype@^3.0.2, csstype@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9"
integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==
@@ -4375,6 +4683,16 @@ diff-sequences@^29.2.0:
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.2.0.tgz#4c55b5b40706c7b5d2c5c75999a50c56d214e8f6"
integrity sha512-413SY5JpYeSBZxmenGEmCVQ8mCgtFJF0w9PROdaS6z987XC2Pd2GOKqOITLtMftmyFZqgtCOb/QA7/Z3ZXfzIw==
+diff-sequences@^29.3.1:
+ version "29.3.1"
+ resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.3.1.tgz#104b5b95fe725932421a9c6e5b4bef84c3f2249e"
+ integrity sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ==
+
+diff@^4.0.1:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
+ integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
+
dijkstrajs@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/dijkstrajs/-/dijkstrajs-1.0.2.tgz#2e48c0d3b825462afe75ab4ad5e829c8ece36257"
@@ -4430,6 +4748,14 @@ dom-converter@^0.2.0:
dependencies:
utila "~0.4"
+dom-helpers@^5.0.1:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902"
+ integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==
+ dependencies:
+ "@babel/runtime" "^7.8.7"
+ csstype "^3.0.2"
+
dom-serializer@0:
version "0.2.2"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51"
@@ -5214,6 +5540,11 @@ find-cache-dir@^3.3.1:
make-dir "^3.0.2"
pkg-dir "^4.1.0"
+find-root@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
+ integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==
+
find-up@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
@@ -5567,6 +5898,13 @@ he@^1.2.0:
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
+history@*:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/history/-/history-5.3.0.tgz#1548abaa245ba47992f063a0783db91ef201c73b"
+ integrity sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==
+ dependencies:
+ "@babel/runtime" "^7.7.6"
+
hmac-drbg@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
@@ -5576,6 +5914,13 @@ hmac-drbg@^1.0.1:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1"
+hoist-non-react-statics@^3.3.1:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
+ integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
+ dependencies:
+ react-is "^16.7.0"
+
hoopy@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d"
@@ -6208,6 +6553,16 @@ jest-config@^27.5.1:
slash "^3.0.0"
strip-json-comments "^3.1.1"
+jest-diff@*:
+ version "29.3.1"
+ resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.3.1.tgz#d8215b72fed8f1e647aed2cae6c752a89e757527"
+ integrity sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==
+ dependencies:
+ chalk "^4.0.0"
+ diff-sequences "^29.3.1"
+ jest-get-type "^29.2.0"
+ pretty-format "^29.3.1"
+
jest-diff@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def"
@@ -7156,7 +7511,7 @@ minimist@^1.2.0, minimist@^1.2.6:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18"
integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==
-mkdirp@~0.5.1:
+mkdirp@^0.5.1, mkdirp@~0.5.1:
version "0.5.6"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6"
integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==
@@ -8200,6 +8555,11 @@ prelude-ls@~1.1.2:
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==
+prettier@^1.18.2:
+ version "1.19.1"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
+ integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
+
pretty-bytes@^5.3.0, pretty-bytes@^5.4.1:
version "5.6.0"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"
@@ -8241,6 +8601,15 @@ pretty-format@^29.0.0, pretty-format@^29.2.1:
ansi-styles "^5.0.0"
react-is "^18.0.0"
+pretty-format@^29.3.1:
+ version "29.3.1"
+ resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.3.1.tgz#1841cac822b02b4da8971dacb03e8a871b4722da"
+ integrity sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==
+ dependencies:
+ "@jest/schemas" "^29.0.0"
+ ansi-styles "^5.0.0"
+ react-is "^18.0.0"
+
process-nextick-args@~2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
@@ -8261,7 +8630,7 @@ prompts@^2.0.1, prompts@^2.4.2:
kleur "^3.0.3"
sisteransi "^1.0.5"
-prop-types@^15.8.1:
+prop-types@^15.6.2, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@@ -8421,7 +8790,7 @@ react-error-overlay@^6.0.11:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb"
integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==
-react-is@^16.13.1:
+react-is@^16.13.1, react-is@^16.7.0:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
@@ -8431,7 +8800,7 @@ react-is@^17.0.1:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
-react-is@^18.0.0:
+react-is@^18.0.0, react-is@^18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
@@ -8496,6 +8865,16 @@ react-scripts@5.0.1:
optionalDependencies:
fsevents "^2.3.2"
+react-transition-group@^4.4.5:
+ version "4.4.5"
+ resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1"
+ integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==
+ dependencies:
+ "@babel/runtime" "^7.5.5"
+ dom-helpers "^5.0.1"
+ loose-envify "^1.4.0"
+ prop-types "^15.6.2"
+
react@^18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
@@ -8571,6 +8950,11 @@ regenerator-runtime@^0.13.10, regenerator-runtime@^0.13.9:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz#ed07b19616bcbec5da6274ebc75ae95634bfc2ee"
integrity sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==
+regenerator-runtime@^0.13.11:
+ version "0.13.11"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
+ integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
+
regenerator-transform@^0.15.0:
version "0.15.0"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.0.tgz#cbd9ead5d77fae1a48d957cf889ad0586adb6537"
@@ -8690,7 +9074,7 @@ resolve.exports@^1.1.0:
resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9"
integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==
-resolve@^1.1.7, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.0, resolve@^1.22.1:
+resolve@^1.1.7, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.0, resolve@^1.22.1, resolve@^1.3.2:
version "1.22.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
@@ -8864,6 +9248,11 @@ selfsigned@^2.1.1:
dependencies:
node-forge "^1"
+semver@^5.3.0:
+ version "5.7.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
+ integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
+
semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
@@ -9039,6 +9428,11 @@ source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, sourc
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+source-map@^0.5.7:
+ version "0.5.7"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
+ integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==
+
source-map@^0.7.3:
version "0.7.4"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656"
@@ -9281,6 +9675,11 @@ stylehacks@^5.1.1:
browserslist "^4.21.4"
postcss-selector-parser "^6.0.4"
+stylis@4.1.3:
+ version "4.1.3"
+ resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.1.3.tgz#fd2fbe79f5fed17c55269e16ed8da14c84d069f7"
+ integrity sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==
+
supports-color@^5.3.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
@@ -9535,7 +9934,7 @@ tsconfig-paths@^3.14.1:
minimist "^1.2.6"
strip-bom "^3.0.0"
-tslib@^1.8.1:
+tslib@^1.8.0, tslib@^1.8.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
@@ -9545,6 +9944,37 @@ tslib@^2.0.3, tslib@^2.3.1:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e"
integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==
+tslint-config-prettier@^1.18.0:
+ version "1.18.0"
+ resolved "https://registry.yarnpkg.com/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz#75f140bde947d35d8f0d238e0ebf809d64592c37"
+ integrity sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg==
+
+tslint@^5.19.0:
+ version "5.20.1"
+ resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.20.1.tgz#e401e8aeda0152bc44dd07e614034f3f80c67b7d"
+ integrity sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==
+ dependencies:
+ "@babel/code-frame" "^7.0.0"
+ builtin-modules "^1.1.1"
+ chalk "^2.3.0"
+ commander "^2.12.1"
+ diff "^4.0.1"
+ glob "^7.1.1"
+ js-yaml "^3.13.1"
+ minimatch "^3.0.4"
+ mkdirp "^0.5.1"
+ resolve "^1.3.2"
+ semver "^5.3.0"
+ tslib "^1.8.0"
+ tsutils "^2.29.0"
+
+tsutils@^2.29.0:
+ version "2.29.0"
+ resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99"
+ integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==
+ dependencies:
+ tslib "^1.8.1"
+
tsutils@^3.21.0:
version "3.21.0"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
@@ -9611,6 +10041,11 @@ typedarray-to-buffer@3.1.5, typedarray-to-buffer@^3.1.5:
dependencies:
is-typedarray "^1.0.0"
+typescript@3.6.2:
+ version "3.6.2"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.2.tgz#105b0f1934119dde543ac8eb71af3a91009efe54"
+ integrity sha512-lmQ4L+J6mnu3xweP8+rOrUwzmN+MRAj7TgtJtDaXE5PMyX2kCrklhg3rvOsOIfNeAWMQWO2F1GPc1kMD2vLAfw==
+
unbox-primitive@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"