diff --git a/config-overrides.js b/config-overrides.js index 9a70ad3..ad7cf70 100644 --- a/config-overrides.js +++ b/config-overrides.js @@ -4,6 +4,7 @@ const TerserPlugin = require("terser-webpack-plugin"); module.exports = function override(config) { config.resolve.fallback = { fs: require.resolve("browserify-fs"), + crypto: require.resolve('crypto-browserify'), path: require.resolve("path-browserify"), assert: require.resolve("assert"), util: require.resolve("util/"), @@ -17,7 +18,7 @@ module.exports = function override(config) { tls: false, net: false, dns: false, - fs: false, + vm: false }; config.module.rules.push({ diff --git a/package.json b/package.json index c7e9756..7580513 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "dependencies": { "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", + "@getstation/electron-google-oauth2": "^14.0.0", "@grpc/grpc-js": "^1.10.8", "@grpc/proto-loader": "^0.7.13", "@mui/icons-material": "^5.16.0", @@ -19,11 +20,15 @@ "@testing-library/react": "^16.0.0", "@testing-library/user-event": "^14.5.2", "assert": "^2.1.0", + "base64-arraybuffer": "^1.0.2", "browserify-fs": "^1.0.0", "buffer": "^6.0.3", "constants-browserify": "^1.0.0", + "crypto": "^1.0.1", + "crypto-browserify": "^3.12.0", "electron-json-storage": "^4.6.0", "electron-store": "^10.0.0", + "fernet": "^0.3.2", "google-protobuf": "^3.21.2", "i18next": "^23.11.4", "keytar": "^7.9.0", @@ -42,6 +47,7 @@ "stream-browserify": "^3.0.0", "tweetnacl": "^1.0.3", "tweetnacl-util": "^0.15.1", + "utf8": "^3.0.0", "util": "^0.12.5", "web-vitals": "^2.1.0" }, @@ -121,5 +127,8 @@ "category": "Communication", "icon": "./public/icon.png" } + }, + "config": { + "forge": "/config-overrides.js" } } diff --git a/public/electron.js b/public/electron.js index 3d39f95..fb92e87 100644 --- a/public/electron.js +++ b/public/electron.js @@ -5,11 +5,14 @@ const url = require("url"); const storage = require("electron-json-storage"); const vault = require("./vault"); const publisher = require("./publisher"); -const safestorage = require('./storage'); +const safestorage = require("./storage"); +const os = require("os"); +const GoogleOAuth2 = require("@getstation/electron-google-oauth2").default; +let mainWindow; function createWindow() { - const mainWindow = new BrowserWindow({ + mainWindow = new BrowserWindow({ width: 1200, height: 800, webPreferences: { @@ -149,16 +152,11 @@ ipcMain.handle( ipcMain.handle( "list-entity-stored-tokens", - async ( - event, - { - long_lived_token - } - ) => { + async (event, { long_lived_token }) => { return new Promise((resolve, reject) => { vault.listEntityStoredTokens( { - long_lived_token: long_lived_token, + long_lived_token: long_lived_token, }, (err, response) => { if (err) { @@ -176,15 +174,10 @@ ipcMain.handle( "get-oauth2-authorization-url", async ( event, - { - platform, - state, - code_verifier, - autogenerate_code_verifier, - } + { platform, state, code_verifier, autogenerate_code_verifier } ) => { return new Promise((resolve, reject) => { - publisher.getOAuth2AuthorizationUrl( + publisher.getOAuth2AuthorizationUrl( { platform: platform, state: state, @@ -203,6 +196,32 @@ ipcMain.handle( } ); +ipcMain.handle( + "exchange-oauth2-code-and-store", + async ( + event, + { long_lived_token, platform, authorization_code, code_verifier } + ) => { + return new Promise((resolve, reject) => { + publisher.exchangeOAuth2CodeAndStore( + { + long_lived_token: long_lived_token, + platform: platform, + authorization_code: authorization_code, + code_verifier: code_verifier, + }, + (err, response) => { + if (err) { + reject(err); + } else { + resolve(response); + } + } + ); + }); + } +); + ipcMain.handle("store-params", async (event, { key, params }) => { return new Promise((resolve, reject) => { const encryptedParams = safestorage.encryptString(JSON.stringify(params)); @@ -252,7 +271,6 @@ ipcMain.handle("delete-session", async () => { }); }); - ipcMain.handle("retrieve-params", async (event, { key }) => { return new Promise((resolve, reject) => { storage.get(key, (error, data) => { @@ -298,63 +316,61 @@ ipcMain.handle("retrieve-onboarding-step", async () => { }); }); -ipcMain.handle("store-server-keys", async (event, { clientDeviceIdPrivKey, clientPublishPrivKey }) => { - return new Promise((resolve, reject) => { - try { - const encryptedDeviceKey = safestorage.encryptString(clientDeviceIdPrivKey); - const encryptedPublishKey = safestorage.encryptString(clientPublishPrivKey); - storage.set("clientDeviceIdPrivKey", { data: encryptedDeviceKey }, (error) => { - if (error) { - reject(error); - } else { - storage.set("clientPublishPrivKey", { data: encryptedPublishKey }, (error) => { - if (error) { - reject(error); - } else { - resolve(); - } - }); - } - }); - } catch (error) { - reject(error); - } - }); -}); +// ipcMain.handle("open-external-url", async (event, url) => { +// try { +// await shell.openExternal(url); +// return true; +// } catch (error) { +// console.error("Failed to open external URL:", error); +// return false; +// } +// }); -ipcMain.handle("retrieve-server-keys", async () => { - return new Promise((resolve, reject) => { - storage.get("clientDeviceIdPrivKey", (error, deviceKeyData) => { - if (error) { - reject(error); - } else { - storage.get("clientPublishPrivKey", (error, publishKeyData) => { - if (error) { - reject(error); - } else { - try { - const decryptedDeviceKey = safestorage.decryptString(deviceKeyData.data); - const decryptedPublishKey = safestorage.decryptString(publishKeyData.data); - resolve({ - clientDeviceIdPrivKey: decryptedDeviceKey, - clientPublishPrivKey: decryptedPublishKey, - }); - } catch (decryptionError) { - reject(decryptionError); - } - } - }); - } +// Handle open-oauth invocation from renderer +ipcMain.handle( + "open-oauth", + async (event, { oauthUrl, expectedRedirect, clientID, scope }) => { + const googleOAuth2 = new GoogleOAuth2(clientID, "", scope, { + successRedirectURL: expectedRedirect, }); - }); -}); -ipcMain.handle("open-external-url", async (event, url) => { - try { - await shell.openExternal(url); - event.returnValue = true; // Optional: return a value if needed - } catch (error) { - console.error("Failed to open external URL:", error); - event.returnValue = false; // Optional: handle failure if needed + const code = await googleOAuth2.openAuthWindowAndGetAuthorizationCode( + oauthUrl + ); + console.log(code); + + // Get system architecture and app name + // const arch = os.arch(); + // const appName = app.getName(); + + // console.log(os.platform()); + // console.log(arch); + // console.log(appName); + + // // Set user agent to mimic the latest version of Firefox with dynamic values + // const userAgent = `Mozilla/5.0 (${os.platform()}; ${arch}; rv:91.0) Gecko/20100101 Firefox/91.0 ${appName}`; + // authWindow.webContents.userAgent = userAgent; + + // authWindow.loadURL(oauthUrl); + // // authWindow.webContents.on("did-redirect-navigation", (event, newUrl) => { + // // const parsedUrl = new URL(newUrl); + // // console.log(">>>1", parsedUrl); + // // // Send the full URL including query parameters to the renderer process + // // mainWindow.webContents.send("oauth-url", newUrl); + // // authWindow.close(); + // // }); + + // authWindow.webContents.on("will-navigate", (event, newUrl) => { + // const parsedUrl = new URL(newUrl); + // const parsedRedirectUrl = new URL(expectedRedirect); + // console.log(newUrl); + // if ( + // parsedUrl.hostname === parsedRedirectUrl.hostname && + // parsedUrl.pathname === parsedRedirectUrl.pathname + // ) { + // mainWindow.webContents.send("oauth-url", newUrl); + // authWindow.close(); + // } + // }); } -}); +); diff --git a/public/preload.js b/public/preload.js index 048a31b..d51e5e9 100644 --- a/public/preload.js +++ b/public/preload.js @@ -1,5 +1,5 @@ const { contextBridge, ipcRenderer } = require("electron"); -const safestorage = require('./storage'); +const safestorage = require("./storage"); contextBridge.exposeInMainWorld("api", { createEntity: async ( @@ -41,7 +41,7 @@ contextBridge.exposeInMainWorld("api", { ) => { try { console.log("Authenticating entity with the following details:"); - console.log("Phone Number:", phoneNumber); + console.log("Phone Number:", phoneNumber); const response = await ipcRenderer.invoke("authenticate-entity", { phoneNumber, password, @@ -65,12 +65,56 @@ contextBridge.exposeInMainWorld("api", { console.log("platform:", platform); console.log("state:", state); console.log("code_verifier", code_verifier); - console.log("autogenerate_code_verifier", autogenerate_code_verifier) - const response = await ipcRenderer.invoke("get-oauth2-authorization-url", { - platform, - state, - code_verifier, - autogenerate_code_verifier, + console.log("autogenerate_code_verifier", autogenerate_code_verifier); + const response = await ipcRenderer.invoke( + "get-oauth2-authorization-url", + { + platform, + state, + code_verifier, + autogenerate_code_verifier, + } + ); + console.log("response:", response); + return response; + } catch (error) { + console.error("gRPC call error:", error); + throw error; + } + }, + + exchangeOAuth2CodeAndStore: async ( + long_lived_token, + platform, + authorization_code, + code_verifier + ) => { + try { + console.log("platform:", platform); + console.log("long_lived_token:", long_lived_token); + console.log("authorization_code", authorization_code); + console.log("code_verifier", code_verifier); + const response = await ipcRenderer.invoke( + "exchange-oauth2-code-and-store", + { + long_lived_token, + platform, + authorization_code, + code_verifier, + } + ); + console.log("response:", response); + return response; + } catch (error) { + console.error("gRPC call error:", error); + throw error; + } + }, + listEntityStoredTokens: async (long_lived_token) => { + try { + console.log("long_lived_token:", long_lived_token); + const response = await ipcRenderer.invoke("list-entity-stored-tokens", { + long_lived_token, }); console.log("response:", response); return response; @@ -79,7 +123,7 @@ contextBridge.exposeInMainWorld("api", { throw error; } }, - + storeParams: (key, value) => safestorage.store(key, value), retrieveParams: (key) => safestorage.retrieve(key), @@ -130,7 +174,10 @@ contextBridge.exposeInMainWorld("api", { }, storeServerKeys: async (clientDeviceIdPrivKey, clientPublishPrivKey) => { try { - await ipcRenderer.invoke("store-server-keys", { clientDeviceIdPrivKey, clientPublishPrivKey }); + await ipcRenderer.invoke("store-server-keys", { + clientDeviceIdPrivKey, + clientPublishPrivKey, + }); } catch (error) { console.error("Storage error:", error); throw error; @@ -145,25 +192,21 @@ contextBridge.exposeInMainWorld("api", { throw error; } }, - listEntityStoredTokens: async (long_lived_token) => { - try { - const response = await ipcRenderer.invoke("list-entity-stored-tokens", { long_lived_token }); - return response; - } catch (error) { - console.error("gRPC call error:", error); - throw error; - } - }, - openExternalUrl: (url) => { + + openOauth: ({ oauthUrl, expectedRedirect, clientID, scope }) => { return new Promise((resolve, reject) => { - ipcRenderer.invoke("open-external-url", url) - .then((result) => { - resolve(result); // Return true or false based on success - }) - .catch((error) => { - console.error("Failed to invoke open-external-url:", error); - reject(error); - }); + ipcRenderer.invoke("open-oauth", { + oauthUrl, + expectedRedirect, + clientID, + scope, + }); + console.log("Got here 0000111"); + ipcRenderer.once("oauth-url", (event, newUrl) => { + console.log("Got here 111"); + console.log("new", newUrl); + resolve(newUrl); + }); }); }, }); diff --git a/public/publisher.js b/public/publisher.js index a274aa3..f353820 100644 --- a/public/publisher.js +++ b/public/publisher.js @@ -30,6 +30,21 @@ function getOAuth2AuthorizationUrl({ }, callback); } +function exchangeOAuth2CodeAndStore({ + long_lived_token, + platform, + authorization_code, + code_verifier, +}, callback) { + client.exchangeOAuth2CodeAndStore({ + long_lived_token, + platform, + authorization_code, + code_verifier, + }, callback); +} + module.exports = { getOAuth2AuthorizationUrl, + exchangeOAuth2CodeAndStore }; diff --git a/src/Components/AddAccounts.js b/src/Components/AddAccounts.js index a89a9dd..011dae4 100644 --- a/src/Components/AddAccounts.js +++ b/src/Components/AddAccounts.js @@ -1,36 +1,77 @@ -import React, { useState } from "react"; +import React, { useState, useEffect } from "react"; import { Drawer, Grid, Box, Typography } from "@mui/material"; import { useTranslation } from "react-i18next"; +import nacl from "tweetnacl"; +import { + encode as encodeBase64, + decode as decodeBase64, +} from "base64-arraybuffer"; +import { createHash } from "crypto-browserify"; +import { createDecipheriv } from "crypto-browserify"; export default function AddAccounts({ open, onClose }) { const { t } = useTranslation(); const [unstoredTokens, setUnstoredTokens] = useState([ { platform: "gmail" }, { platform: "twitter" }, - ]); // Mock data for icons + ]); + + const openOAuthScreen = async ( + oauthUrl, + expectedRedirect, + clientID, + scope + ) => { + try { + const newUrl = await window.api.openOauth({ + oauthUrl, + expectedRedirect, + clientID, + scope, + }); + console.log("Received OAuth2 redirection URL:", newUrl); + handleMessage(newUrl); + } catch (error) { + console.error("Error opening OAuth screen:", error); + // Handle error, e.g., show a message to the user + } + }; + + const handleMessage = (url) => { + // Your logic to handle the URL goes here + console.log("Handling URL:", url); + // Parse the URL to extract the authorization code or token + const parsedUrl = new URL(url); + const authCode = parsedUrl.searchParams.get("code"); + console.log("Authorization Code:", authCode); + }; const handleAddAccount = async (platform) => { - try { + try { const response = await window.api.getOAuth2AuthorizationUrl( platform, "", "", - true, + false ); - console.log("Authorization URL:", response); - - // Call the IPC handler to open external URL - const success = await window.api.openExternalUrl(response.authorization_url); - if (!success) { - console.error("Failed to open external URL."); + openOAuthScreen( + response.authorization_url, + response.redirect_url, + response.client_id, + response.scope.split(",") + ); + } catch (error) { + console.error("Failed to get OAuth2 authorization URL:", error); } - } catch (error) { - console.error("Failed to get OAuth2 authorization URL:", error); - } -}; + }; return ( - + Add Accounts Adding accounts blah blah blah @@ -52,3 +93,39 @@ export default function AddAccounts({ open, onClose }) { ); } + +// Helper function to extract the code from the URL +function extractCodeFromUrl(url) { + const urlObj = new URL(url); + const params = new URLSearchParams(urlObj.search); + return params.get("code"); +} + +// Function to derive the key +function deriveKey(sharedSecret) { + const hash = createHash("sha256"); + hash.update(sharedSecret); + return hash.digest().slice(0, 32); // Fernet uses 256-bit keys +} + +// Function to decrypt the token +function decryptFernet(key, token) { + const keyBuffer = Buffer.from(key, "base64"); + const tokenBuffer = Buffer.from(token, "base64"); + + const iv = tokenBuffer.slice(1, 17); // Initialization vector + const ciphertext = tokenBuffer.slice(17, -32); // Ciphertext + const hmac = tokenBuffer.slice(-32); // HMAC + + const decipher = createDecipheriv("aes-256-cbc", keyBuffer, iv); + let decrypted = decipher.update(ciphertext, "binary", "utf8"); + decrypted += decipher.final("utf8"); + + return decrypted; +} + +// Function to run the next process after token exchange +function runNextProcess(response) { + // Add your next process logic here + console.log("Running next process with response:", response); +} diff --git a/src/Components/Login.js b/src/Components/Login.js index 18c9693..fb027a7 100644 --- a/src/Components/Login.js +++ b/src/Components/Login.js @@ -10,7 +10,6 @@ import { InputAdornment, IconButton, } from "@mui/material"; -// import PhoneInput from "react-phone-number-input"; import "react-phone-number-input/style.css"; import flags from "react-phone-number-input/flags"; import { useTranslation } from "react-i18next"; @@ -21,6 +20,10 @@ import nacl from "tweetnacl"; import naclUtil from "tweetnacl-util"; import Visibility from '@mui/icons-material/Visibility'; import VisibilityOff from '@mui/icons-material/VisibilityOff'; +import { encode as encodeBase64, decode as decodeBase64 } from 'base64-arraybuffer'; +import { decode as utf8Decode, encode as utf8Encode } from 'utf8'; +import { createHash } from 'crypto-browserify'; +import { createDecipheriv, randomBytes } from 'crypto-browserify'; function generateKeyPair() { const keyPair = nacl.box.keyPair(); @@ -30,9 +33,11 @@ function generateKeyPair() { }; } + + function Login({ onClose, open }) { const { t } = useTranslation(); - const [showPassword, setShowPassword] = React.useState(false); + const [showPassword, setShowPassword] = useState(false); const [loading, setLoading] = useState(false); const [loginData, setLoginData] = useState({ phoneNumber: "", @@ -121,14 +126,20 @@ function Login({ onClose, open }) { }); setOtpOpen(true); } else { + await window.api.storeParams( + "serverDeviceId", + response.server_device_id_pub_key + ); await window.api.storeParams( "longLivedToken", response.long_lived_token - ); // Store the token here - await window.api.storeSession(response); + ); + + await window.api.storeParams('serverDeviceId', response.server_device_id_pub_key); + await window.api.storeParams('longLivedToken', response.long_lived_token); + setAlert({ - message: - "Login successful. OTP sent successfully. Check your phone for the code.", + message: "Login successful. OTP sent successfully. Check your phone for the code.", severity: "success", open: true, }); @@ -168,12 +179,16 @@ function Login({ onClose, open }) { otp ); console.log("OTP Verification Response:", response); - await window.api.storeParams("longLivedToken", response.long_lived_token); // Store the token here + + await window.api.storeParams('serverDeviceId', response.server_device_id_pub_key); + await window.api.storeParams('longLivedToken', response.long_lived_token); + setAlert({ message: "Login successful", severity: "success", open: true, }); + setTimeout(() => { navigate("/onboarding3"); // Navigate to /onboarding3 after showing the success message handleClose(); diff --git a/src/Pages/Compose.js b/src/Pages/Compose.js index c3485fe..fb86666 100644 --- a/src/Pages/Compose.js +++ b/src/Pages/Compose.js @@ -3,6 +3,23 @@ import { Drawer, Grid, Box, Typography } from "@mui/material"; import GmailCompose from "../Components/ComposeGmail"; import TwitterCompose from "../Components/ComposeTwitter"; import { useTranslation } from "react-i18next"; +import nacl from "tweetnacl"; +import naclUtil from "tweetnacl-util"; +import { decode } from "base64-arraybuffer"; +import { Buffer } from "buffer"; +import Fernet from "fernet"; + +function generateSecretKey(serverPublicKey, clientSecretKey) { + const serverPubKeyUint8 = new Uint8Array(decode(serverPublicKey)); + const clientSecKeyUint8 = new Uint8Array(decode(clientSecretKey)); + return nacl.box.before(serverPubKeyUint8, clientSecKeyUint8); +} + +function decryptToken(secretKey, encryptedToken) { + const secret = new Fernet.Secret(Buffer.from(secretKey, 'base64').toString('hex')); + const fernet = new Fernet({ key: secret }); + return fernet.decode(encryptedToken).toString(); +} export default function Compose({ open, onClose }) { const { t } = useTranslation(); @@ -13,17 +30,26 @@ export default function Compose({ open, onClose }) { useEffect(() => { const fetchStoredTokens = async () => { try { - const longLivedToken = await window.api.retrieveParams("longLivedToken"); - const response = await window.api.listEntityStoredTokens(longLivedToken); + const encryptedToken = await window.api.retrieveParams('longLivedToken'); + const serverDeviceIdPubKey = await window.api.retrieveParams('serverDeviceId'); + const clientDeviceIdSecretKey = await window.api.retrieveParams('clientDeviceIdSecretKey'); + + // Decrypt token using Fernet + const secret = new Fernet.Secret(Buffer.from(clientDeviceIdSecretKey, 'base64').toString('hex')); + const fernet = new Fernet({ key: secret }); + const decryptedToken = fernet.decode(encryptedToken).toString(); + + const response = await window.api.listEntityStoredTokens(decryptedToken); setTokens(response.stored_tokens); + console.log('response:', response); } catch (error) { - console.error("Failed to fetch stored tokens:", error); + console.error('Failed to fetch stored tokens:', error); } }; - + fetchStoredTokens(); }, []); - + const handleGmailClick = () => { setComposeOpen(true); setTwitterOpen(false); diff --git a/yarn.lock b/yarn.lock index bc4f136..792e70a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1927,6 +1927,13 @@ resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== +"@getstation/electron-google-oauth2@^14.0.0": + version "14.0.0" + resolved "https://registry.yarnpkg.com/@getstation/electron-google-oauth2/-/electron-google-oauth2-14.0.0.tgz#260461f895720ad4515716d91f97a194d5881f13" + integrity sha512-v4ELWTb24wZBO/X9ymmVhcYwjfJfKvREa1vkXU1VJfqBQfOcekZHYF0gyZCTnCB4C4Y3Uaun6z5Apykf669bEQ== + dependencies: + google-auth-library "^8.8.0" + "@grpc/grpc-js@^1.10.8": version "1.10.8" resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.10.8.tgz#99787785cd8335be861afd1cd485ae9f058e4484" @@ -4036,6 +4043,11 @@ arraybuffer.prototype.slice@^1.0.3: is-array-buffer "^3.0.4" is-shared-array-buffer "^1.0.2" +arrify@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" + integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== + asap@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" @@ -4348,7 +4360,12 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base64-js@^1.0.2, base64-js@^1.3.1, base64-js@^1.5.1: +base64-arraybuffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz#1c37589a7c4b0746e34bd1feb951da2df01c1bdc" + integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ== + +base64-js@^1.0.2, base64-js@^1.3.0, base64-js@^1.3.1, base64-js@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -4374,6 +4391,11 @@ big.js@^5.2.2: resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== +bignumber.js@^9.0.0: + version "9.1.2" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c" + integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== + binary-extensions@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" @@ -4578,6 +4600,11 @@ buffer-crc32@~0.2.3: resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== + buffer-equal@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.1.tgz#2f7651be5b1b3f057fcd6e7ee16cf34767077d90" @@ -5330,7 +5357,7 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -crypto-browserify@^3.11.0: +crypto-browserify@^3.11.0, crypto-browserify@^3.12.0: version "3.12.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== @@ -5347,11 +5374,21 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" +crypto-js@~4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631" + integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== + crypto-random-string@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== +crypto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/crypto/-/crypto-1.0.1.tgz#2af1b7cad8175d24c8a1b0778255794a21803037" + integrity sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig== + css-blank-pseudo@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz#36523b01c12a25d812df343a32c322d2a2324561" @@ -6006,6 +6043,13 @@ eastasianwidth@^0.2.0: resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== +ecdsa-sig-formatter@1.0.11, ecdsa-sig-formatter@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -6802,6 +6846,11 @@ express@^4.17.3: utils-merge "1.0.1" vary "~1.1.2" +extend@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + extract-zip@^2.0.0, extract-zip@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" @@ -6844,6 +6893,11 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-text-encoding@^1.0.0: + version "1.0.6" + resolved "https://registry.yarnpkg.com/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz#0aa25f7f638222e3396d72bf936afcf1d42d6867" + integrity sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w== + fastq@^1.6.0: version "1.17.1" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" @@ -6872,6 +6926,14 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" +fernet@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/fernet/-/fernet-0.3.2.tgz#4815e74b5438a930029b7ad13f5ba54b1f0d19e7" + integrity sha512-VPwO4hF9sp8YrCeiOjMb4HTg5WV5VC7Nk2EG3pfotqW9ZHa3aNnR+oGiOZu8k0Jp4VxJi0RTJwHmloyjWs+Mzg== + dependencies: + crypto-js "~4.2.0" + urlsafe-base64 "1.0.0" + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -7195,6 +7257,24 @@ gauge@^4.0.3: strip-ansi "^6.0.1" wide-align "^1.1.5" +gaxios@^5.0.0, gaxios@^5.0.1: + version "5.1.3" + resolved "https://registry.yarnpkg.com/gaxios/-/gaxios-5.1.3.tgz#f7fa92da0fe197c846441e5ead2573d4979e9013" + integrity sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA== + dependencies: + extend "^3.0.2" + https-proxy-agent "^5.0.0" + is-stream "^2.0.0" + node-fetch "^2.6.9" + +gcp-metadata@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-5.3.0.tgz#6f45eb473d0cb47d15001476b48b663744d25408" + integrity sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w== + dependencies: + gaxios "^5.0.0" + json-bigint "^1.0.0" + gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -7390,6 +7470,28 @@ globby@^11.0.4, globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" +google-auth-library@^8.8.0: + version "8.9.0" + resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-8.9.0.tgz#15a271eb2ec35d43b81deb72211bd61b1ef14dd0" + integrity sha512-f7aQCJODJFmYWN6PeNKzgvy9LI2tYmXnzpNDHEjG5sDNPgGb2FXQyTBnXeSH+PAtpKESFD+LmHw3Ox3mN7e1Fg== + dependencies: + arrify "^2.0.0" + base64-js "^1.3.0" + ecdsa-sig-formatter "^1.0.11" + fast-text-encoding "^1.0.0" + gaxios "^5.0.0" + gcp-metadata "^5.3.0" + gtoken "^6.1.0" + jws "^4.0.0" + lru-cache "^6.0.0" + +google-p12-pem@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-4.0.1.tgz#82841798253c65b7dc2a4e5fe9df141db670172a" + integrity sha512-WPkN4yGtz05WZ5EhtlxNDWPhC4JIic6G8ePitwUWy4l+XPVYec+a0j0Ts47PDtW59y3RwAhUd9/h9ZZ63px6RQ== + dependencies: + node-forge "^1.3.1" + google-protobuf@^3.21.2: version "3.21.2" resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.2.tgz#4580a2bea8bbb291ee579d1fefb14d6fa3070ea4" @@ -7429,6 +7531,15 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== +gtoken@^6.1.0: + version "6.1.2" + resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-6.1.2.tgz#aeb7bdb019ff4c3ba3ac100bbe7b6e74dce0e8bc" + integrity sha512-4ccGpzz7YAr7lxrT2neugmXQ3hP9ho2gcaityLVkiUecAiwiy60Ii8gRbZeOsXV19fYaRjgBSshs8kXw+NKCPQ== + dependencies: + gaxios "^5.0.1" + google-p12-pem "^4.0.0" + jws "^4.0.0" + gzip-size@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462" @@ -9235,6 +9346,13 @@ jsesc@~0.5.0: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== +json-bigint@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-bigint/-/json-bigint-1.0.0.tgz#ae547823ac0cad8398667f8cd9ef4730f5b01ff1" + integrity sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ== + dependencies: + bignumber.js "^9.0.0" + json-buffer@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" @@ -9332,6 +9450,23 @@ junk@^3.1.0: resolved "https://registry.yarnpkg.com/junk/-/junk-3.1.0.tgz#31499098d902b7e98c5d9b9c80f43457a88abfa1" integrity sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ== +jwa@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-2.0.0.tgz#a7e9c3f29dae94027ebcaf49975c9345593410fc" + integrity sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jws@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jws/-/jws-4.0.0.tgz#2d4e8cf6a318ffaa12615e9dec7e86e6c97310f4" + integrity sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg== + dependencies: + jwa "^2.0.0" + safe-buffer "^5.0.1" + keytar@^7.9.0: version "7.9.0" resolved "https://registry.yarnpkg.com/keytar/-/keytar-7.9.0.tgz#4c6225708f51b50cbf77c5aae81721964c2918cb" @@ -10123,7 +10258,14 @@ node-api-version@^0.2.0: dependencies: semver "^7.3.5" -node-forge@^1: +node-fetch@^2.6.9: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +node-forge@^1, node-forge@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== @@ -13364,6 +13506,11 @@ tr46@^2.1.0: dependencies: punycode "^2.1.1" +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + tree-kill@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" @@ -13702,11 +13849,21 @@ url@^0.11.0, url@^0.11.3: punycode "^1.4.1" qs "^6.11.2" +urlsafe-base64@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/urlsafe-base64/-/urlsafe-base64-1.0.0.tgz#23f89069a6c62f46cf3a1d3b00169cefb90be0c6" + integrity sha512-RtuPeMy7c1UrHwproMZN9gN6kiZ0SvJwRaEzwZY0j9MypEkFqyBaKv176jvlPtg58Zh36bOkS0NFABXMHvvGCA== + utf8-byte-length@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz#f45f150c4c66eee968186505ab93fcbb8ad6bf61" integrity sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA== +utf8@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" + integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== + util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -13881,6 +14038,11 @@ web-vitals@^2.1.0: resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-2.1.4.tgz#76563175a475a5e835264d373704f9dde718290c" integrity sha512-sVWcwhU5mX6crfI5Vd2dC4qchyTqxV8URinzt25XqVh+bHEPGH4C3NPrNionCP7Obx59wrYEbNlw4Z8sjALzZg== +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" @@ -14033,6 +14195,14 @@ whatwg-mimetype@^2.3.0: resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + whatwg-url@^7.0.0: version "7.1.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06"