From 339986b6660766cf1e45b41df20fbb2c34aa9ee3 Mon Sep 17 00:00:00 2001 From: Howard Date: Thu, 23 Feb 2023 14:37:39 -0800 Subject: [PATCH] Implement WebAuthn auth for minting PKP and storing encryption condition (#2) * Implement WebAuthn auth for minting PKP and storing encryption condition * Update copy * Update copy --- .prettierrc | 5 + package.json | 16 + public/index.html | 1 + src/App.js | 986 ++++++++++++++------- src/utils/cbor.ts | 33 + src/utils/decodeAttestationObject.ts | 39 + src/utils/decodeAuthenticatorExtensions.js | 19 + src/utils/parseAuthenticatorData.ts | 112 +++ tsconfig.json | 25 + yarn.lock | 461 +++++++++- 10 files changed, 1379 insertions(+), 318 deletions(-) create mode 100644 .prettierrc create mode 100644 src/utils/cbor.ts create mode 100644 src/utils/decodeAttestationObject.ts create mode 100644 src/utils/decodeAuthenticatorExtensions.js create mode 100644 src/utils/parseAuthenticatorData.ts create mode 100644 tsconfig.json 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.

+ -
- ); + // set in local state + setWebAuthnCredentialPublicKey( + hexlify( + parsedAuthData.credentialPublicKey + ) + ); + } + ); + }} + > + Register + +

Step 2: Authenticate using WebAuthn to mint PKP.

+ +

+ Step 3: Use Lit Network to obtain a session sig and then + store an encryption condition. +

+ + + )} +
+ ); } 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"