From 49205d0a44abd2082dc063f773d95cc6c6403333 Mon Sep 17 00:00:00 2001
From: Justin <328965+justinbarry@users.noreply.github.com>
Date: Tue, 16 Apr 2024 20:06:02 -0700
Subject: [PATCH] Add new api file which verifies signatures
---
apps/demo-app/next-env.d.ts | 1 +
apps/demo-app/package.json | 5 +-
apps/demo-app/pages/api/check-signature.ts | 189 +++++++++++++++++++++
apps/demo-app/tsconfig.json | 20 ++-
pnpm-lock.yaml | 166 ++++++++++++++----
5 files changed, 344 insertions(+), 37 deletions(-)
create mode 100644 apps/demo-app/pages/api/check-signature.ts
diff --git a/apps/demo-app/next-env.d.ts b/apps/demo-app/next-env.d.ts
index 4f11a03d..fd36f949 100644
--- a/apps/demo-app/next-env.d.ts
+++ b/apps/demo-app/next-env.d.ts
@@ -1,5 +1,6 @@
///
///
+///
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
diff --git a/apps/demo-app/package.json b/apps/demo-app/package.json
index 5c9a41e1..6db7e81f 100644
--- a/apps/demo-app/package.json
+++ b/apps/demo-app/package.json
@@ -10,9 +10,12 @@
},
"dependencies": {
"@burnt-labs/abstraxion": "workspace:*",
+ "@burnt-labs/constants": "workspace:*",
"@burnt-labs/signers": "workspace:*",
"@burnt-labs/ui": "workspace:*",
+ "@cosmjs/amino": "^0.32.3",
"@cosmjs/cosmwasm-stargate": "^0.32.2",
+ "@keplr-wallet/cosmos": "^0.12.80",
"next": "^14.0.3",
"react": "^18.2.0",
"react-dom": "^18.2.0"
@@ -31,4 +34,4 @@
"tailwindcss": "^3.2.4",
"typescript": "^5.2.2"
}
-}
\ No newline at end of file
+}
diff --git a/apps/demo-app/pages/api/check-signature.ts b/apps/demo-app/pages/api/check-signature.ts
new file mode 100644
index 00000000..3efa3be2
--- /dev/null
+++ b/apps/demo-app/pages/api/check-signature.ts
@@ -0,0 +1,189 @@
+import type { NextApiRequest, NextApiResponse } from "next";
+import { verifyADR36Amino } from "@keplr-wallet/cosmos";
+
+// This import will need to change based on the chain you are confirming against.
+import { testnetChainInfo } from "@burnt-labs/constants";
+import { CosmWasmClient } from "@cosmjs/cosmwasm-stargate";
+import { Pubkey } from "@cosmjs/amino";
+
+interface GrantsResponse {
+ grants: Grant[];
+ pagination: Pagination;
+}
+
+interface Grant {
+ granter: string;
+ grantee: string;
+ authorization: Authorization;
+ expiration: string;
+}
+
+interface Authorization {
+ "@type": string;
+ grants: GrantAuthorization[];
+}
+
+interface GrantAuthorization {
+ contract: string;
+ limit: Limit;
+ filter: Filter;
+}
+
+interface Limit {
+ "@type": string;
+ remaining: string;
+}
+
+interface Filter {
+ "@type": string;
+}
+
+interface Pagination {
+ next_key: null | string;
+ total: string;
+}
+
+function isString(test: any): test is string {
+ return typeof test === "string";
+}
+
+async function checkGrants(granter: string, grantee: string): Promise {
+ const res = await fetch(
+ `${testnetChainInfo.rest}/cosmos/authz/v1beta1/grants/grantee/${granter}`,
+ {
+ cache: "no-store",
+ },
+ );
+ const data = (await res.json()) as GrantsResponse;
+ return data.grants.map((grant) => grant.grantee).includes(grantee);
+}
+
+function checkSignature(
+ address: string,
+ pubKey: Pubkey,
+ messageString: string,
+ signature: string,
+): boolean {
+ const msg = Buffer.from(messageString, "hex").toString();
+
+ const signatureBuffer = Buffer.from(signature, "base64");
+
+ const uint8Signature = new Uint8Array(signatureBuffer); // Convert the buffer to an Uint8Array
+
+ const pubKeyValueBuffer = Buffer.from(pubKey, "base64"); // Decode the base64 encoded value
+
+ const pubKeyUint8Array = new Uint8Array(pubKeyValueBuffer); // Convert the buffer to an Uint8Array
+
+ return verifyADR36Amino(
+ testnetChainInfo.bech32Config.bech32PrefixAccAddr,
+ address,
+ msg,
+ pubKeyUint8Array,
+ uint8Signature,
+ );
+}
+
+export default async function handler(
+ req: NextApiRequest,
+ res: NextApiResponse,
+) {
+ const { query, method } = req;
+ const client = await CosmWasmClient.connect(testnetChainInfo.rpc);
+
+ if (method === "GET") {
+ const { userSessionAddress, metaAccountAddress, message, signature } =
+ query;
+
+ const errors: string[] = [];
+ if (!userSessionAddress) {
+ errors.push("userSessionAddress is required");
+ }
+
+ if (!metaAccountAddress && typeof metaAccountAddress === "string") {
+ errors.push("itemId is required");
+ }
+
+ if (!message && typeof message === "string") {
+ errors.push("message is required");
+ }
+
+ if (!signature && typeof signature === "string") {
+ errors.push("signature is required");
+ }
+
+ if (errors.length > 0) {
+ res.status(400).json({ errors });
+ return;
+ }
+
+ // These aid TS type inference. You can pull in a more complex validation package to handle this like io-ts
+ if (!isString(userSessionAddress)) {
+ res
+ .status(400)
+ .json({ errors: ["userSessionAddress is required to be a string"] });
+ return;
+ }
+
+ if (!isString(metaAccountAddress)) {
+ res
+ .status(400)
+ .json({ errors: ["metaAccountAddress is required to be a string"] });
+ return;
+ }
+
+ if (!isString(message)) {
+ res.status(400).json({ errors: ["message is required to be a string"] });
+ return;
+ }
+
+ if (!isString(signature)) {
+ res
+ .status(400)
+ .json({ errors: ["signature is required to be a string"] });
+ return;
+ }
+
+ /*
+ * Confirming account "ownership" is a three-step process
+ * 1. Confirm the signature passed is valid for the temporary userSessionAddress
+ * 2. Pull any grant bestowed to the userSessionAddress on chain
+ * 3. Check that AT LEAST one grant exists of any type exists between the userSessionAddress and the metaAccountAddress
+ **/
+ // Need to get the pub key from the chain.
+ const account = await client.getAccount(userSessionAddress);
+ if (!account) {
+ res.status(404).json({
+ errors: ["account not found"],
+ });
+ return;
+ }
+ const { pubkey } = account;
+ if (!pubkey) {
+ res.status(404).json({
+ errors: ["public key not found"],
+ });
+ return;
+ }
+
+ const isValid = checkSignature(
+ userSessionAddress,
+ pubkey.value,
+ message,
+ signature,
+ );
+ if (!isValid) {
+ res.status(400).json({
+ errors: ["invalid signature"],
+ });
+ return;
+ }
+
+ // handle GET request
+ res.status(200).json({
+ valid: await checkGrants(metaAccountAddress, userSessionAddress),
+ });
+ } else {
+ res.setHeader("Allow", ["GET"]);
+ res.status(405).end(`Method ${method} Not Allowed`);
+ }
+}
diff --git a/apps/demo-app/tsconfig.json b/apps/demo-app/tsconfig.json
index 10ba1595..e4d07053 100644
--- a/apps/demo-app/tsconfig.json
+++ b/apps/demo-app/tsconfig.json
@@ -1,9 +1,21 @@
{
"extends": "@burnt-labs/tsconfig/nextjs.json",
"compilerOptions": {
- "plugins": [{ "name": "next" }],
- "moduleResolution": "Bundler"
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ],
+ "moduleResolution": "Bundler",
+ "strictNullChecks": true
},
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
- "exclude": ["node_modules"]
+ "include": [
+ "next-env.d.ts",
+ "**/*.ts",
+ "**/*.tsx",
+ ".next/types/**/*.ts"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 16218b7f..c9d54ee1 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -28,7 +28,7 @@ importers:
version: 0.5.3(prettier@3.0.3)
turbo:
specifier: latest
- version: 1.11.2
+ version: 1.12.4
apps/abstraxion-dashboard:
dependencies:
@@ -156,15 +156,24 @@ importers:
'@burnt-labs/abstraxion':
specifier: workspace:*
version: link:../../packages/abstraxion
+ '@burnt-labs/constants':
+ specifier: workspace:*
+ version: link:../../packages/constants
'@burnt-labs/signers':
specifier: workspace:*
version: link:../../packages/signers
'@burnt-labs/ui':
specifier: workspace:*
version: link:../../packages/ui
+ '@cosmjs/amino':
+ specifier: ^0.32.3
+ version: 0.32.3
'@cosmjs/cosmwasm-stargate':
specifier: ^0.32.2
version: 0.32.2
+ '@keplr-wallet/cosmos':
+ specifier: ^0.12.80
+ version: 0.12.80
next:
specifier: ^14.0.3
version: 14.0.3(@babel/core@7.23.9)(react-dom@18.2.0)(react@18.2.0)
@@ -416,7 +425,7 @@ importers:
version: 5.0.5
tsup:
specifier: ^6.0.1
- version: 6.7.0(postcss@8.4.28)(typescript@5.2.2)
+ version: 6.7.0(postcss@8.4.31)(typescript@5.2.2)
typescript:
specifier: ^5.2.2
version: 5.2.2
@@ -510,7 +519,7 @@ importers:
version: 5.0.5
tsup:
specifier: ^6.0.1
- version: 6.7.0(postcss@8.4.28)(typescript@5.2.2)
+ version: 6.7.0(postcss@8.4.31)(typescript@5.2.2)
typescript:
specifier: ^5.2.2
version: 5.2.2
@@ -2435,6 +2444,15 @@ packages:
'@cosmjs/utils': 0.32.2
dev: false
+ /@cosmjs/amino@0.32.3:
+ resolution: {integrity: sha512-G4zXl+dJbqrz1sSJ56H/25l5NJEk/pAPIr8piAHgbXYw88OdAOlpA26PQvk2IbSN/rRgVbvlLTNgX2tzz1dyUA==}
+ dependencies:
+ '@cosmjs/crypto': 0.32.3
+ '@cosmjs/encoding': 0.32.3
+ '@cosmjs/math': 0.32.3
+ '@cosmjs/utils': 0.32.3
+ dev: false
+
/@cosmjs/cosmwasm-stargate@0.31.3:
resolution: {integrity: sha512-Uv9TmCn3650gdFeZm7SEfUZF3uX3lfJfFhXOk6I2ZLr/FrKximnlb+vwAfZaZnWYvlA7qrKtHIjeRNHvT23zcw==}
dependencies:
@@ -2458,7 +2476,7 @@ packages:
/@cosmjs/cosmwasm-stargate@0.32.2:
resolution: {integrity: sha512-OwJHzIx2CoJS6AULxOpNR6m+CI0GXxy8z9svHA1ZawzNM3ZGlL0GvHdhmF0WkpX4E7UdrYlJSLpKcgg5Fo6i7Q==}
dependencies:
- '@cosmjs/amino': 0.32.2
+ '@cosmjs/amino': 0.32.3
'@cosmjs/crypto': 0.32.2
'@cosmjs/encoding': 0.32.2
'@cosmjs/math': 0.32.2
@@ -2513,6 +2531,18 @@ packages:
libsodium-wrappers-sumo: 0.7.13
dev: false
+ /@cosmjs/crypto@0.32.3:
+ resolution: {integrity: sha512-niQOWJHUtlJm2GG4F00yGT7sGPKxfUwz+2qQ30uO/E3p58gOusTcH2qjiJNVxb8vScYJhFYFqpm/OA/mVqoUGQ==}
+ dependencies:
+ '@cosmjs/encoding': 0.32.3
+ '@cosmjs/math': 0.32.3
+ '@cosmjs/utils': 0.32.3
+ '@noble/hashes': 1.3.3
+ bn.js: 5.2.1
+ elliptic: 6.5.4
+ libsodium-wrappers-sumo: 0.7.13
+ dev: false
+
/@cosmjs/encoding@0.27.1:
resolution: {integrity: sha512-rayLsA0ojHeniaRfWWcqSsrE/T1rl1gl0OXVNtXlPwLJifKBeLEefGbOUiAQaT0wgJ8VNGBazVtAZBpJidfDhw==}
dependencies:
@@ -2537,6 +2567,14 @@ packages:
readonly-date: 1.0.0
dev: false
+ /@cosmjs/encoding@0.32.3:
+ resolution: {integrity: sha512-p4KF7hhv8jBQX3MkB3Defuhz/W0l3PwWVYU2vkVuBJ13bJcXyhU9nJjiMkaIv+XP+W2QgRceqNNgFUC5chNR7w==}
+ dependencies:
+ base64-js: 1.5.1
+ bech32: 1.1.4
+ readonly-date: 1.0.0
+ dev: false
+
/@cosmjs/json-rpc@0.31.3:
resolution: {integrity: sha512-7LVYerXjnm69qqYR3uA6LGCrBW2EO5/F7lfJxAmY+iII2C7xO3a0vAjMSt5zBBh29PXrJVS6c2qRP22W1Le2Wg==}
dependencies:
@@ -2583,6 +2621,12 @@ packages:
bn.js: 5.2.1
dev: false
+ /@cosmjs/math@0.32.3:
+ resolution: {integrity: sha512-amumUtZs8hCCnV+lSBaJIiZkGabQm22QGg/IotYrhcmoOEOjt82n7hMNlNXRs7V6WLMidGrGYcswB5zcmp0Meg==}
+ dependencies:
+ bn.js: 5.2.1
+ dev: false
+
/@cosmjs/proto-signing@0.31.3:
resolution: {integrity: sha512-24+10/cGl6lLS4VCrGTCJeDRPQTn1K5JfknzXzDIHOx8THR31JxA7/HV5eWGHqWgAbudA7ccdSvEK08lEHHtLA==}
dependencies:
@@ -2732,6 +2776,10 @@ packages:
resolution: {integrity: sha512-Gg5t+eR7vPJMAmhkFt6CZrzPd0EKpAslWwk5rFVYZpJsM8JG5KT9XQ99hgNM3Ov6ScNoIWbXkpX27F6A9cXR4Q==}
dev: false
+ /@cosmjs/utils@0.32.3:
+ resolution: {integrity: sha512-WCZK4yksj2hBDz4w7xFZQTRZQ/RJhBX26uFHmmQFIcNUUVAihrLO+RerqJgk0dZqC42wstM9pEUQGtPmLcIYvg==}
+ dev: false
+
/@cspotcode/source-map-support@0.8.1:
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
engines: {node: '>=12'}
@@ -3556,21 +3604,21 @@ packages:
'@jridgewell/sourcemap-codec': 1.4.15
dev: true
- /@keplr-wallet/common@0.12.46:
- resolution: {integrity: sha512-cu/H4g/f7zgxE+4sO/M8b1HC7Sv+9WccJoS1v5TqP7MnZUyTdh6nwZ1jM8Asbu2mMOxQJv7vdV1iydPWZ5dXNg==}
+ /@keplr-wallet/common@0.12.67:
+ resolution: {integrity: sha512-S3m+PM1eKxP3uBHWjb6c+t0luFTeDF3w7nSNCvs9Hn1vXxz11EUjPVbOAjoS4r6B0IByFz4wcx8efUmgiaxbPA==}
dependencies:
- '@keplr-wallet/crypto': 0.12.46
- '@keplr-wallet/types': 0.12.46
+ '@keplr-wallet/crypto': 0.12.67
+ '@keplr-wallet/types': 0.12.67
buffer: 6.0.3
delay: 4.4.1
mobx: 6.12.0
dev: false
- /@keplr-wallet/common@0.12.67:
- resolution: {integrity: sha512-S3m+PM1eKxP3uBHWjb6c+t0luFTeDF3w7nSNCvs9Hn1vXxz11EUjPVbOAjoS4r6B0IByFz4wcx8efUmgiaxbPA==}
+ /@keplr-wallet/common@0.12.80:
+ resolution: {integrity: sha512-HndiWKqNtPq6uGt7aY5FQEwegSG0SPN21W2M8XgEOwryzTKAMnFm8sjfvAAIjZW0Wmvkx1fX1e/MWQV27IfxJg==}
dependencies:
- '@keplr-wallet/crypto': 0.12.67
- '@keplr-wallet/types': 0.12.67
+ '@keplr-wallet/crypto': 0.12.80
+ '@keplr-wallet/types': 0.12.80
buffer: 6.0.3
delay: 4.4.1
mobx: 6.12.0
@@ -3592,6 +3640,22 @@ packages:
protobufjs: 6.11.4
dev: false
+ /@keplr-wallet/cosmos@0.12.80:
+ resolution: {integrity: sha512-MS3BGdy9Y0R8Rujr9CHkzoWpC8PmSDZOBBMRhljelChVAAfc1Dvz7nsJ66Sk9vpsiNUwCctcK+sxedtT7Mia9A==}
+ dependencies:
+ '@ethersproject/address': 5.7.0
+ '@keplr-wallet/common': 0.12.80
+ '@keplr-wallet/crypto': 0.12.80
+ '@keplr-wallet/proto-types': 0.12.80
+ '@keplr-wallet/simple-fetch': 0.12.80
+ '@keplr-wallet/types': 0.12.80
+ '@keplr-wallet/unit': 0.12.80
+ bech32: 1.1.4
+ buffer: 6.0.3
+ long: 4.0.0
+ protobufjs: 6.11.4
+ dev: false
+
/@keplr-wallet/crypto@0.12.67:
resolution: {integrity: sha512-ETLeRay4fUyJhN+emGz1wjA4OICct55wDTeKR4qfyYMn7WNbIKK+CSM71gaApZZAWZmXimglEYq5xAF8KSpPsg==}
dependencies:
@@ -3618,6 +3682,19 @@ packages:
sha.js: 2.4.11
dev: false
+ /@keplr-wallet/crypto@0.12.80:
+ resolution: {integrity: sha512-iJLxy3OJV1/ZDZ3y0ZKHHN46rwtSgyvVxVp0IiDVtZQ77sYw2yiQArux6cYwi8i2d2eZPJc2I//hvZagBdeoGA==}
+ dependencies:
+ '@ethersproject/keccak256': 5.7.0
+ bip32: 2.0.6
+ bip39: 3.1.0
+ bs58check: 2.1.2
+ buffer: 6.0.3
+ crypto-js: 4.2.0
+ elliptic: 6.5.4
+ sha.js: 2.4.11
+ dev: false
+
/@keplr-wallet/proto-types@0.12.67:
resolution: {integrity: sha512-rfsOBKH+UrkmA39mqiXYy6lz+YctWMtjaZ5Tqc1+E3qbt10z5gu220+pI+hc0XxIj481j0v5vjFhAL9yGIZMVg==}
dependencies:
@@ -3625,16 +3702,33 @@ packages:
protobufjs: 6.11.4
dev: false
+ /@keplr-wallet/proto-types@0.12.80:
+ resolution: {integrity: sha512-ZX0/O+P2zkjr6AwrppckeJfvDnsJnaoNBMxLQ5XZldLAzKb0ECEQnC8IgFkTWYqy9jgFbu2kJwqtrPnKSqKwMQ==}
+ dependencies:
+ long: 4.0.0
+ protobufjs: 6.11.4
+ dev: false
+
/@keplr-wallet/simple-fetch@0.12.67:
resolution: {integrity: sha512-xfu4S9HHqEH0AskG0eyLEAW10FaXD9C/tfSbpITMZU1FM9EnegLoHty+hXtMlIGDZbNZ8rsSpABMFLTEr2XB0g==}
dev: false
+ /@keplr-wallet/simple-fetch@0.12.80:
+ resolution: {integrity: sha512-GBOONbo5npz+t47cnjRnpO1Up+XGAPxjKLRtwYopZeV99KZa7oLb73RQBXT0XooQwq73bwy/Xv0qPCSYhWKUgA==}
+ dev: false
+
/@keplr-wallet/types@0.12.67:
resolution: {integrity: sha512-HDEYOezWq//ug/R0lkOQWsaOYh3b9ECA8LN+tAA+baWMo81X9m9L63ux7NYw0QmoLxWqWrRO/T9F28+q2dw6+A==}
dependencies:
long: 4.0.0
dev: false
+ /@keplr-wallet/types@0.12.80:
+ resolution: {integrity: sha512-GRMyOioocq2LaLAoaGegCOqgjKq4uXOPQ9QwoLpx0ZpsbccSr2wKN8PhFs/B9fwuhiJu1aroX7hXC0jlsE8XLg==}
+ dependencies:
+ long: 4.0.0
+ dev: false
+
/@keplr-wallet/unit@0.12.67:
resolution: {integrity: sha512-Mzlrh0j65i6+qoTNg1/Um4Hywpu9mmaZn8HRiX01HdPyaEcLREFkf18eJMklWuHx4nERg+EzvU5E/9J2fuRPdA==}
dependencies:
@@ -3643,6 +3737,14 @@ packages:
utility-types: 3.10.0
dev: false
+ /@keplr-wallet/unit@0.12.80:
+ resolution: {integrity: sha512-XpZe2i0iY8jtbA1GTsK4DV4KN5C2nXnSFdBn36F0TS/Ow1DO5KSqIyYsAU86pTzZfbkUzn5OPPmJUHGAg00GJg==}
+ dependencies:
+ '@keplr-wallet/types': 0.12.80
+ big-integer: 1.6.51
+ utility-types: 3.10.0
+ dev: false
+
/@lit-labs/ssr-dom-shim@1.1.2:
resolution: {integrity: sha512-jnOD+/+dSrfTWYfSXBXlo5l5f0q1UuJo3tkbMDCYA2lKUYq79jaxqtGEvnRoh049nt1vdo1+45RinipU6FGY2g==}
dev: false
@@ -12668,64 +12770,64 @@ packages:
yargs: 17.7.2
dev: false
- /turbo-darwin-64@1.11.2:
- resolution: {integrity: sha512-toFmRG/adriZY3hOps7nYCfqHAS+Ci6xqgX3fbo82kkLpC6OBzcXnleSwuPqjHVAaRNhVoB83L5njcE9Qwi2og==}
+ /turbo-darwin-64@1.12.4:
+ resolution: {integrity: sha512-dBwFxhp9isTa9RS/fz2gDVk5wWhKQsPQMozYhjM7TT4jTrnYn0ZJMzr7V3B/M/T8QF65TbniW7w1gtgxQgX5Zg==}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: false
optional: true
- /turbo-darwin-arm64@1.11.2:
- resolution: {integrity: sha512-FCsEDZ8BUSFYEOSC3rrARQrj7x2VOrmVcfrMUIhexTxproRh4QyMxLfr6LALk4ymx6jbDCxWa6Szal8ckldFbA==}
+ /turbo-darwin-arm64@1.12.4:
+ resolution: {integrity: sha512-1Uo5iI6xsJ1j9ObsqxYRsa3W26mEbUe6fnj4rQYV6kDaqYD54oAMJ6hM53q9rB8JvFxwdrUXGp3PwTw9A0qqkA==}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: false
optional: true
- /turbo-linux-64@1.11.2:
- resolution: {integrity: sha512-Vzda/o/QyEske5CxLf0wcu7UUS+7zB90GgHZV4tyN+WZtoouTvbwuvZ3V6b5Wgd3OJ/JwWR0CXDK7Sf4VEMr7A==}
+ /turbo-linux-64@1.12.4:
+ resolution: {integrity: sha512-ONg2aSqKP7LAQOg7ysmU5WpEQp4DGNxSlAiR7um+LKtbmC/UxogbR5+T+Uuq6zGuQ5kJyKjWJ4NhtvUswOqBsA==}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: false
optional: true
- /turbo-linux-arm64@1.11.2:
- resolution: {integrity: sha512-bRLwovQRz0yxDZrM4tQEAYV0fBHEaTzUF0JZ8RG1UmZt/CqtpnUrJpYb1VK8hj1z46z9YehARpYCwQ2K0qU4yw==}
+ /turbo-linux-arm64@1.12.4:
+ resolution: {integrity: sha512-9FPufkwdgfIKg/9jj87Cdtftw8o36y27/S2vLN7FTR2pp9c0MQiTBOLVYadUr1FlShupddmaMbTkXEhyt9SdrA==}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: false
optional: true
- /turbo-windows-64@1.11.2:
- resolution: {integrity: sha512-LgTWqkHAKgyVuLYcEPxZVGPInTjjeCnN5KQMdJ4uQZ+xMDROvMFS2rM93iQl4ieDJgidwHCxxCxaU9u8c3d/Kg==}
+ /turbo-windows-64@1.12.4:
+ resolution: {integrity: sha512-2mOtxHW5Vjh/5rDVu/aFwsMzI+chs8XcEuJHlY1sYOpEymYTz+u6AXbnzRvwZFMrLKr7J7fQOGl+v96sLKbNdA==}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: false
optional: true
- /turbo-windows-arm64@1.11.2:
- resolution: {integrity: sha512-829aVBU7IX0c/B4G7g1VI8KniAGutHhIupkYMgF6xPkYVev2G3MYe6DMS/vsLt9GGM9ulDtdWxWrH5P2ngK8IQ==}
+ /turbo-windows-arm64@1.12.4:
+ resolution: {integrity: sha512-nOY5wae9qnxPOpT1fRuYO0ks6dTwpKMPV6++VkDkamFDLFHUDVM/9kmD2UTeh1yyrKnrZksbb9zmShhmfj1wog==}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: false
optional: true
- /turbo@1.11.2:
- resolution: {integrity: sha512-jPC7LVQJzebs5gWf8FmEvsvXGNyKbN+O9qpvv98xpNaM59aS0/Irhd0H0KbcqnXfsz7ETlzOC3R+xFWthC4Z8A==}
+ /turbo@1.12.4:
+ resolution: {integrity: sha512-yUJ7elEUSToiGwFZogXpYKJpQ0BvaMbkEuQECIWtkBLcmWzlMOt6bActsIm29oN83mRU0WbzGt4e8H1KHWedhg==}
hasBin: true
optionalDependencies:
- turbo-darwin-64: 1.11.2
- turbo-darwin-arm64: 1.11.2
- turbo-linux-64: 1.11.2
- turbo-linux-arm64: 1.11.2
- turbo-windows-64: 1.11.2
- turbo-windows-arm64: 1.11.2
+ turbo-darwin-64: 1.12.4
+ turbo-darwin-arm64: 1.12.4
+ turbo-linux-64: 1.12.4
+ turbo-linux-arm64: 1.12.4
+ turbo-windows-64: 1.12.4
+ turbo-windows-arm64: 1.12.4
dev: false
/type-check@0.4.0: