From 280ad1d71d655a9b27c704103e82013d1a9c439b Mon Sep 17 00:00:00 2001 From: Andrei Date: Mon, 2 Sep 2024 13:46:40 +0300 Subject: [PATCH 01/12] passkey provider --- .../SignTransactionsModals.tsx | 4 + .../SignWithPasskeyModal.tsx | 23 ++ .../SignWithPasskeyModal/index.tsx | 1 + .../types/signTransactionsModals.types.ts | 1 + src/UI/index.ts | 1 + src/UI/pages/UnlockPage/index.tsx | 8 + .../PasskeyLoginButton/PasskeyLoginButton.tsx | 65 +++++ src/UI/passkey/PasskeyLoginButton/index.ts | 1 + .../passkeyLoginButton.styles.scss | 19 ++ .../ProviderInitializer.tsx | 15 + .../helpers/getPasskeyProvider.ts | 18 ++ .../ProviderInitializer/helpers/index.ts | 1 + src/hooks/login/index.ts | 1 + src/hooks/login/usePasskeyLogin.ts | 132 +++++++++ .../transactions/useSignTransactions.tsx | 7 +- .../useSignTransactionsCommonData.tsx | 7 + .../useSignTransactionsWithDevice.tsx | 1 - src/passkeyProvider/errors.ts | 29 ++ src/passkeyProvider/index.ts | 1 + .../lib/webauthn-prf/client.ts | 268 ++++++++++++++++++ src/passkeyProvider/lib/webauthn-prf/index.ts | 5 + src/passkeyProvider/lib/webauthn-prf/types.ts | 142 ++++++++++ src/passkeyProvider/lib/webauthn-prf/utils.ts | 46 +++ src/passkeyProvider/operation.ts | 7 + src/passkeyProvider/passkeyProvider.ts | 246 ++++++++++++++++ src/providers/accountProvider.ts | 2 + src/providers/utils.ts | 3 + src/reduxStore/slices/loginInfoSlice.ts | 2 + src/types/enums.types.ts | 1 + yarn.lock | 100 +++---- 30 files changed, 1105 insertions(+), 52 deletions(-) create mode 100644 src/UI/SignTransactionsModals/SignWithPasskeyModal/SignWithPasskeyModal.tsx create mode 100644 src/UI/SignTransactionsModals/SignWithPasskeyModal/index.tsx create mode 100644 src/UI/passkey/PasskeyLoginButton/PasskeyLoginButton.tsx create mode 100644 src/UI/passkey/PasskeyLoginButton/index.ts create mode 100644 src/UI/passkey/PasskeyLoginButton/passkeyLoginButton.styles.scss create mode 100644 src/components/ProviderInitializer/helpers/getPasskeyProvider.ts create mode 100644 src/hooks/login/usePasskeyLogin.ts create mode 100644 src/passkeyProvider/errors.ts create mode 100644 src/passkeyProvider/index.ts create mode 100644 src/passkeyProvider/lib/webauthn-prf/client.ts create mode 100644 src/passkeyProvider/lib/webauthn-prf/index.ts create mode 100644 src/passkeyProvider/lib/webauthn-prf/types.ts create mode 100644 src/passkeyProvider/lib/webauthn-prf/utils.ts create mode 100644 src/passkeyProvider/operation.ts create mode 100644 src/passkeyProvider/passkeyProvider.ts diff --git a/src/UI/SignTransactionsModals/SignTransactionsModals.tsx b/src/UI/SignTransactionsModals/SignTransactionsModals.tsx index 524f20c61..5c43c9d59 100644 --- a/src/UI/SignTransactionsModals/SignTransactionsModals.tsx +++ b/src/UI/SignTransactionsModals/SignTransactionsModals.tsx @@ -11,6 +11,7 @@ import { SignWithLedgerModal } from './SignWithLedgerModal'; import { SignWithMetamaskModal } from './SignWithMetamaskModal'; import { SignWithMetamaskProxyModal } from './SignWithMetamaskProxyModal'; import { SignWithOperaModal } from './SignWithOperaModal'; +import { SignWithPasskeyModal } from './SignWithPasskeyModal'; import { SignWithWalletConnectModal } from './SignWithWalletConnectModal'; import { CustomConfirmScreensType, @@ -38,6 +39,7 @@ export const SignTransactionsModals = ({ WalletConnect: CustomConfirmScreens?.WalletConnect ?? SignWithWalletConnectModal, Extension: CustomConfirmScreens?.Extension ?? SignWithExtensionModal, + Passkey: CustomConfirmScreens?.Passkey ?? SignWithPasskeyModal, Metamask: CustomConfirmScreens?.Metamask ?? SignWithMetamaskModal, MetamaskProxy: CustomConfirmScreens?.MetamaskProxy ?? SignWithMetamaskProxyModal, @@ -75,6 +77,8 @@ export const SignTransactionsModals = ({ return renderScreen({ Screen: ConfirmScreens.WalletConnect }); case LoginMethodsEnum.extension: return renderScreen({ Screen: ConfirmScreens.Extension }); + case LoginMethodsEnum.passkey: + return renderScreen({ Screen: ConfirmScreens.Passkey }); case LoginMethodsEnum.metamask: return renderScreen({ Screen: ConfirmScreens.Metamask, isDevice: true }); case LoginMethodsEnum.opera: diff --git a/src/UI/SignTransactionsModals/SignWithPasskeyModal/SignWithPasskeyModal.tsx b/src/UI/SignTransactionsModals/SignWithPasskeyModal/SignWithPasskeyModal.tsx new file mode 100644 index 000000000..d00ffd24f --- /dev/null +++ b/src/UI/SignTransactionsModals/SignWithPasskeyModal/SignWithPasskeyModal.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { SignModalPropsType } from 'types'; + +import { + SignWaitingScreenModal, + SignWaitingScreenModalPropsType +} from '../components'; + +export const SignWithPasskeyModal = (props: SignModalPropsType) => { + const description = props.error + ? props.error + : props.transactions?.length > 1 + ? 'Please signin with your passkey in order to sign the transactions' + : 'Please signin with your passkey in order to sign the transaction'; + + const waitingScreenProps: SignWaitingScreenModalPropsType = { + ...props, + description, + title: 'Confirm by signing in with passkey' + }; + + return ; +}; diff --git a/src/UI/SignTransactionsModals/SignWithPasskeyModal/index.tsx b/src/UI/SignTransactionsModals/SignWithPasskeyModal/index.tsx new file mode 100644 index 000000000..9c723676c --- /dev/null +++ b/src/UI/SignTransactionsModals/SignWithPasskeyModal/index.tsx @@ -0,0 +1 @@ +export * from './SignWithPasskeyModal'; diff --git a/src/UI/SignTransactionsModals/types/signTransactionsModals.types.ts b/src/UI/SignTransactionsModals/types/signTransactionsModals.types.ts index bddb55a90..52dcec1e4 100644 --- a/src/UI/SignTransactionsModals/types/signTransactionsModals.types.ts +++ b/src/UI/SignTransactionsModals/types/signTransactionsModals.types.ts @@ -20,6 +20,7 @@ export type ScreenType = (signProps: SignPropsType) => JSX.Element; export interface CustomConfirmScreensType { Ledger?: ScreenType; Extension?: ScreenType; + Passkey?: ScreenType; Metamask?: ScreenType; Opera?: ScreenType; CrossWindow?: ScreenType; diff --git a/src/UI/index.ts b/src/UI/index.ts index 7785bbf25..3ebc22ea9 100644 --- a/src/UI/index.ts +++ b/src/UI/index.ts @@ -4,6 +4,7 @@ export * from './Denominate'; export * from './FormatAmount'; export * from './ExplorerLink'; export * from './extension/ExtensionLoginButton'; +export * from './passkey/PasskeyLoginButton'; export * from './operaWallet/OperaWalletLoginButton'; export * from './ledger/LedgerLoginButton'; export * from './ledger/LedgerLoginContainer'; diff --git a/src/UI/pages/UnlockPage/index.tsx b/src/UI/pages/UnlockPage/index.tsx index 9d1f4ce03..9f0826ba6 100644 --- a/src/UI/pages/UnlockPage/index.tsx +++ b/src/UI/pages/UnlockPage/index.tsx @@ -6,6 +6,7 @@ import { ExtensionLoginButton } from 'UI/extension/ExtensionLoginButton'; import { LedgerLoginButton } from 'UI/ledger/LedgerLoginButton'; import { MetamaskProxyButton } from 'UI/metamaskProxy/MetamaskProxyLoginButton'; import { OperaWalletLoginButton } from 'UI/operaWallet/OperaWalletLoginButton'; +import { PasskeyLoginButton } from 'UI/passkey/PasskeyLoginButton'; import { WalletConnectLoginButton } from 'UI/walletConnect/WalletConnectLoginButton'; import { WebWalletLoginButton } from 'UI/webWallet/WebWalletLoginButton'; @@ -16,6 +17,7 @@ export interface Props { loginRoute: string; LedgerLoginButtonText?: string; ExtensionLoginButtonText?: string; + PasskeyLoginButtonText?: string; OperaWalletLoginButtonText?: string; CrossWindowLoginButtonText?: string; MetamaskProxyLoginButtonText?: string; @@ -33,6 +35,7 @@ const UnlockPageComponent = ({ description = 'Pick a login method', WalletConnectLoginButtonText = 'xPortal App', ExtensionLoginButtonText = 'Extension', + PasskeyLoginButtonText = 'Passkey', OperaWalletLoginButtonText = 'Opera Crypto Wallet', MetamaskProxyLoginButtonText = 'Metamask Proxy', WebWalletLoginButtonText = 'Web wallet', @@ -87,6 +90,11 @@ const UnlockPageComponent = ({ loginButtonText={ExtensionLoginButtonText} /> + + JSX.Element = ({ + token, + className = 'dapp-passkey-login', + children, + callbackRoute, + buttonClassName = 'dapp-default-login-button', + nativeAuth, + loginButtonText = 'Passkey', + onLoginRedirect, + disabled +}) => { + const [onInitiateLogin] = usePasskeyLogin({ + callbackRoute, + token, + onLoginRedirect, + nativeAuth + }); + const disabledConnectButton = getIsNativeAuthSingingForbidden(token); + + const handleLogin = () => { + onInitiateLogin(); + }; + + return ( + + {children} + + ); +}; + +export const PasskeyLoginButton = withStyles(PasskeyLoginButtonComponent, { + ssrStyles: () => + import( + 'UI/extension/ExtensionLoginButton/extensionLoginButton.styles.scss' + ), + clientStyles: () => + require('UI/extension/ExtensionLoginButton/extensionLoginButton.styles.scss') + .default +}); diff --git a/src/UI/passkey/PasskeyLoginButton/index.ts b/src/UI/passkey/PasskeyLoginButton/index.ts new file mode 100644 index 000000000..691827930 --- /dev/null +++ b/src/UI/passkey/PasskeyLoginButton/index.ts @@ -0,0 +1 @@ +export * from './PasskeyLoginButton'; diff --git a/src/UI/passkey/PasskeyLoginButton/passkeyLoginButton.styles.scss b/src/UI/passkey/PasskeyLoginButton/passkeyLoginButton.styles.scss new file mode 100644 index 000000000..f04c87541 --- /dev/null +++ b/src/UI/passkey/PasskeyLoginButton/passkeyLoginButton.styles.scss @@ -0,0 +1,19 @@ +.passkey-login { + box-sizing: border-box; +} + +.login-text { + box-sizing: border-box; +} + +.no-passkey-button-wrapper { + box-sizing: border-box; +} + +.nopasskeyButtonContent { + box-sizing: border-box; +} + +.no-passkey-button-title { + box-sizing: border-box; +} diff --git a/src/components/ProviderInitializer/ProviderInitializer.tsx b/src/components/ProviderInitializer/ProviderInitializer.tsx index f84e6a710..795f7a1d5 100644 --- a/src/components/ProviderInitializer/ProviderInitializer.tsx +++ b/src/components/ProviderInitializer/ProviderInitializer.tsx @@ -53,6 +53,7 @@ import { getOperaProvider, getCrossWindowProvider, getExtensionProvider, + getPasskeyProvider, processModifiedAccount, getMetamaskProvider, getMetamaskProxyProvider @@ -274,6 +275,14 @@ export function ProviderInitializer() { } } + async function setPasskeyProvider() { + const address = await getAddress(); + const provider = await getPasskeyProvider(address); + if (provider) { + setAccountProvider(provider); + } + } + async function setMetamaskProvider() { const address = await getAddress(); const provider = await getMetamaskProvider(address); @@ -350,6 +359,12 @@ export function ProviderInitializer() { setExtensionProvider(); break; } + + case LoginMethodsEnum.passkey: { + setPasskeyProvider(); + break; + } + case LoginMethodsEnum.metamask: { setMetamaskProvider(); break; diff --git a/src/components/ProviderInitializer/helpers/getPasskeyProvider.ts b/src/components/ProviderInitializer/helpers/getPasskeyProvider.ts new file mode 100644 index 000000000..e85c36315 --- /dev/null +++ b/src/components/ProviderInitializer/helpers/getPasskeyProvider.ts @@ -0,0 +1,18 @@ +import { PasskeyProvider } from 'passkeyProvider'; + +export async function getPasskeyProvider(address: string) { + try { + const provider = PasskeyProvider.getInstance().setAddress(address); + + const success = await provider.init(); + + if (success) { + return provider; + } else { + console.error('Could not initialise passkey provider'); + } + } catch (err) { + console.error('Unable to login to PasskeyProvider', err); + } + return null; +} diff --git a/src/components/ProviderInitializer/helpers/index.ts b/src/components/ProviderInitializer/helpers/index.ts index 32372861a..3411b36b9 100644 --- a/src/components/ProviderInitializer/helpers/index.ts +++ b/src/components/ProviderInitializer/helpers/index.ts @@ -5,3 +5,4 @@ export * from './getMetamaskProxyProvider'; export * from './processModifiedAccount'; export * from './getModifiedLoginToken'; export * from './getMetamaskProvider'; +export * from './getPasskeyProvider'; diff --git a/src/hooks/login/index.ts b/src/hooks/login/index.ts index 36b46beda..402dbbd26 100644 --- a/src/hooks/login/index.ts +++ b/src/hooks/login/index.ts @@ -7,3 +7,4 @@ export { useLedgerLogin } from './useLedgerLogin'; export { useXaliasLogin } from './useXaliasLogin'; export { useWalletConnectV2Login } from './useWalletConnectV2Login'; export { useMetamaskLogin } from './useMetamaskLogin'; +export { usePasskeyLogin } from './usePasskeyLogin'; diff --git a/src/hooks/login/usePasskeyLogin.ts b/src/hooks/login/usePasskeyLogin.ts new file mode 100644 index 000000000..9891ca05f --- /dev/null +++ b/src/hooks/login/usePasskeyLogin.ts @@ -0,0 +1,132 @@ +import { useState } from 'react'; + +import { SECOND_LOGIN_ATTEMPT_ERROR } from 'constants/errorsMessages'; +import { PasskeyProvider } from 'passkeyProvider'; +import { setAccountProvider } from 'providers/accountProvider'; +import { loginAction } from 'reduxStore/commonActions'; +import { useDispatch } from 'reduxStore/DappProviderContext'; +import { + InitiateLoginFunctionType, + LoginHookGenericStateType, + OnProviderLoginType +} from 'types'; +import { LoginMethodsEnum } from 'types/enums.types'; +import { getIsLoggedIn } from 'utils/getIsLoggedIn'; +import { optionalRedirect } from 'utils/internal'; +import { addOriginToLocationPath } from 'utils/window'; +import { getDefaultCallbackUrl } from 'utils/window'; +import { clearInitiatedLogins } from './helpers'; +import { useLoginService } from './useLoginService'; + +export type UsePasskeyLoginReturnType = [ + InitiateLoginFunctionType, + LoginHookGenericStateType +]; + +export const usePasskeyLogin = ({ + callbackRoute, + token: tokenToSign, + nativeAuth, + onLoginRedirect +}: OnProviderLoginType): UsePasskeyLoginReturnType => { + const [error, setError] = useState(''); + const [isLoading, setIsLoading] = useState(false); + const hasNativeAuth = nativeAuth != null; + const loginService = useLoginService(nativeAuth); + let token = tokenToSign; + + const dispatch = useDispatch(); + const isLoggedIn = getIsLoggedIn(); + + async function initiateLogin() { + if (isLoggedIn) { + throw new Error(SECOND_LOGIN_ATTEMPT_ERROR); + } + + clearInitiatedLogins(); + + setIsLoading(true); + const provider: PasskeyProvider = PasskeyProvider.getInstance(); + + try { + const isSuccessfullyInitialized: boolean = await provider.init(); + + if (!isSuccessfullyInitialized) { + console.warn( + 'Something went wrong trying to redirect to wallet login..' + ); + return; + } + + const defaultCallbackUrl = getDefaultCallbackUrl(); + const callbackUrl: string = encodeURIComponent( + addOriginToLocationPath(callbackRoute ?? defaultCallbackUrl) + ); + + if (hasNativeAuth && !token) { + token = await loginService.getNativeAuthLoginToken(); + + // Fetching block failed + if (!token) { + console.warn('Fetching block failed. Login cancelled.'); + return; + } + } + + if (token) { + loginService.setLoginToken(token); + } + + const providerLoginData = { + callbackUrl, + ...(token && { token }) + }; + + await provider.login(providerLoginData); + + setAccountProvider(provider); + + const { signature, address } = provider.account; + + if (!address) { + setIsLoading(false); + console.warn('Login cancelled.'); + setError('Login cancelled'); + return; + } + + if (signature && token) { + loginService.setTokenLoginInfo({ + signature, + address + }); + } + + dispatch(loginAction({ address, loginMethod: LoginMethodsEnum.passkey })); + + optionalRedirect({ + callbackRoute, + onLoginRedirect, + options: { signature, address } + }); + } catch (error) { + console.error('error logging in', error); + // TODO: can be any or typed error + setError('Error logging in: ' + (error as any).message); + } finally { + setIsLoading(false); + } + } + + const loginFailed = Boolean(error); + + return [ + initiateLogin, + { + loginFailed, + error, + isLoading: isLoading && !loginFailed, + isLoggedIn: isLoggedIn && !loginFailed + } + ]; +}; diff --git a/src/hooks/transactions/useSignTransactions.tsx b/src/hooks/transactions/useSignTransactions.tsx index 2a68871a7..bb9554c3e 100644 --- a/src/hooks/transactions/useSignTransactions.tsx +++ b/src/hooks/transactions/useSignTransactions.tsx @@ -26,6 +26,7 @@ import { CrossWindowProvider, MetamaskProxyProvider } from 'lib/sdkWebWalletCrossWindowProvider'; +import { PasskeyProvider } from 'passkeyProvider'; import { ExperimentalWebviewProvider } from 'providers/experimentalWebViewProvider'; import { getProviderType } from 'providers/utils'; @@ -98,6 +99,7 @@ export const useSignTransactions = () => { const clearSignInfo = (sessionId?: string) => { const isExtensionProvider = provider instanceof ExtensionProvider; + const isPasskeyProvider = provider instanceof PasskeyProvider; const isCrossWindowProvider = provider instanceof CrossWindowProvider; const isMetamaskProxyProvider = provider instanceof MetamaskProxyProvider; const isMetamaskProvider = provider instanceof MetamaskProvider; @@ -113,6 +115,7 @@ export const useSignTransactions = () => { !isExtensionProvider && !isCrossWindowProvider && !isMetamaskProxyProvider && + !isPasskeyProvider && !isMetamaskProvider ) { return; @@ -123,6 +126,9 @@ export const useSignTransactions = () => { if (isExtensionProvider) { ExtensionProvider.getInstance()?.cancelAction?.(); } + if (isPasskeyProvider) { + PasskeyProvider.getInstance()?.cancelAction?.(); + } if (isMetamaskProvider) { MetamaskProvider.getInstance()?.cancelAction?.(); } @@ -229,7 +235,6 @@ export const useSignTransactions = () => { if (isCrossWindowProvider && hasConsentPopup) { (provider as CrossWindowProvider).setShouldShowConsentPopup(true); } - const signedTransactions: Transaction[] = (await provider.signTransactions( isGuarded && allowGuardian diff --git a/src/hooks/transactions/useSignTransactionsCommonData.tsx b/src/hooks/transactions/useSignTransactionsCommonData.tsx index bdaa61d80..f119bf871 100644 --- a/src/hooks/transactions/useSignTransactionsCommonData.tsx +++ b/src/hooks/transactions/useSignTransactionsCommonData.tsx @@ -11,6 +11,7 @@ import { MetamaskProxyProvider } from 'lib/sdkWebWalletCrossWindowProvider'; +import { PasskeyProvider } from 'passkeyProvider'; import { ExperimentalWebviewProvider } from 'providers/experimentalWebViewProvider'; import { useDispatch, useSelector } from 'reduxStore/DappProviderContext'; import { @@ -71,6 +72,7 @@ export const useSignTransactionsCommonData = () => { function clearSignInfo(sessionId?: string) { const isExtensionProvider = provider instanceof ExtensionProvider; + const isPasskeyProvider = provider instanceof PasskeyProvider; const isCrossWindowProvider = provider instanceof CrossWindowProvider; const isMetamaskProxyProvider = provider instanceof MetamaskProxyProvider; const isMetamaskProvider = provider instanceof MetamaskProvider; @@ -84,6 +86,7 @@ export const useSignTransactionsCommonData = () => { !isExtensionProvider && !isCrossWindowProvider && !isMetamaskProxyProvider && + !isPasskeyProvider && !isMetamaskProvider ) { return; @@ -95,6 +98,10 @@ export const useSignTransactionsCommonData = () => { ExtensionProvider.getInstance()?.cancelAction?.(); } + if (isPasskeyProvider) { + PasskeyProvider.getInstance()?.cancelAction?.(); + } + if (isMetamaskProvider) { MetamaskProvider.getInstance()?.cancelAction?.(); } diff --git a/src/hooks/transactions/useSignTransactionsWithDevice.tsx b/src/hooks/transactions/useSignTransactionsWithDevice.tsx index a656704db..f79549f40 100644 --- a/src/hooks/transactions/useSignTransactionsWithDevice.tsx +++ b/src/hooks/transactions/useSignTransactionsWithDevice.tsx @@ -156,7 +156,6 @@ export function useSignTransactionsWithDevice( if (!transaction) { return null; } - return await connectedProvider.signTransaction(transaction); } diff --git a/src/passkeyProvider/errors.ts b/src/passkeyProvider/errors.ts new file mode 100644 index 000000000..9f474caf0 --- /dev/null +++ b/src/passkeyProvider/errors.ts @@ -0,0 +1,29 @@ +/** + * The base class for exceptions (errors). + */ +export class Err extends Error { + inner: Error | undefined = undefined; + + public constructor(message: string, inner?: Error) { + super(message); + this.inner = inner; + } +} + +export class ErrCannotSignSingleTransaction extends Err { + public constructor() { + super("Cannot sign single transaction."); + } +} + +export class ErrAccountNotConnected extends Err { + public constructor() { + super("Account is not connected."); + } +} + +export class AuthenticatorNotSupported extends Err { + public constructor() { + super("Passkey authenticator does not support PRF."); + } +} diff --git a/src/passkeyProvider/index.ts b/src/passkeyProvider/index.ts new file mode 100644 index 000000000..49c7204fb --- /dev/null +++ b/src/passkeyProvider/index.ts @@ -0,0 +1 @@ +export * from "./passkeyProvider"; diff --git a/src/passkeyProvider/lib/webauthn-prf/client.ts b/src/passkeyProvider/lib/webauthn-prf/client.ts new file mode 100644 index 000000000..4f993076a --- /dev/null +++ b/src/passkeyProvider/lib/webauthn-prf/client.ts @@ -0,0 +1,268 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +import { + AuthenticateOptions, + AuthenticationEncoded, + AuthenticationExtensionsClientOutputsWithPrf, + AuthenticatorAttestationResponseWithData, + AuthenticatorAttestationResponseWithPublicKey, + AuthenticatorResponseWithAlgorithm, + AuthType, + NamedAlgo, + NumAlgo, + PublicKeyCredentialCreationOptions, + PublicKeyCredentialRequestOptions, + RegisterOptions, + RegistrationEncoded +} from './types.js'; +import * as utils from './utils.js'; + +//generated with crypto.getRandomValues +const randomness = + '125,31,50,6,242,196,44,99,212,140,13,135,165,76,139,234,130,235,189,246,131,38,217,236,172,174,67,82,180,79,137,150'; +const salt = new Uint8Array(randomness.split(',').map((str) => parseInt(str))) + .buffer; + +/** + * Returns whether passwordless authentication is available on this browser/platform or not. + */ +export function isAvailable(): boolean { + return !!window.PublicKeyCredential; +} + +/** + * Returns whether the device itself can be used as authenticator. + */ +export async function isLocalAuthenticator(): Promise { + return await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable(); +} + +async function getAuthAttachment( + authType: AuthType +): Promise { + if (authType === 'local') return 'platform'; + if (authType === 'roaming' || authType === 'extern') return 'cross-platform'; + if (authType === 'both') return undefined; // The webauthn protocol considers `null` as invalid but `undefined` as "both"! + + // the default case: "auto", depending on device capabilities + try { + if (await isLocalAuthenticator()) return 'platform'; + else return 'cross-platform'; + } catch (e) { + // might happen due to some security policies + // see https://w3c.github.io/webauthn/#sctn-isUserVerifyingPlatformAuthenticatorAvailable + return undefined; // The webauthn protocol considers `null` as invalid but `undefined` as "both"! + } +} + +function getAlgoName(num: NumAlgo): NamedAlgo { + switch (num) { + case -7: + return 'ES256'; + // case -8 ignored to to its rarity + case -257: + return 'RS256'; + default: + throw new Error(`Unknown algorithm code: ${num}`); + } +} + +/** + * Creates a cryptographic key pair, in order to register the public key for later passwordless authentication. + * + * @param {string} username + * @param {string} challenge A server-side randomly generated string. + * @param {Object} [options] Optional parameters. + * @param {number} [options.timeout=60000] Number of milliseconds the user has to respond to the biometric/PIN check. + * @param {'required'|'preferred'|'discouraged'} [options.userVerification='required'] Whether to prompt for biometric/PIN check or not. + * @param {'auto'|'local'|'roaming'|'both'} [options.authenticatorType='auto'] Which device to use as authenticator. + * 'auto': if the local device can be used as authenticator it will be preferred. Otherwise it will prompt for a roaming device. + * 'local': use the local device (using TouchID, FaceID, Windows Hello or PIN) + * 'roaming': use a roaming device (security key or connected phone) + * 'both': prompt the user to choose between local or roaming device. The UI and user interaction in this case is platform specific. + * @param {boolean} [attestation=false] If enabled, the device attestation and clientData will be provided as Base64url encoded binary data. + * Note that this is not available on some platforms. + */ +export async function register( + username: string, + challenge: string, + options?: RegisterOptions +): Promise { + options = options ?? {}; + + if (!utils.isBase64url(challenge)) + throw new Error('Provided challenge is not properly encoded in Base64url'); + + const creationOptions: PublicKeyCredentialCreationOptions = { + challenge: utils.parseBase64url(challenge), + rp: { + id: window.location.hostname, + name: window.location.hostname + }, + user: { + id: await utils.sha256(new TextEncoder().encode(username)), // ID should not be directly "identifiable" for privacy concerns + name: username, + displayName: username + }, + pubKeyCredParams: [ + { alg: -7, type: 'public-key' }, // ES256 (Webauthn's default algorithm) + { alg: -257, type: 'public-key' } // RS256 (for Windows Hello and others) + ], + timeout: options.timeout ?? 60000, + authenticatorSelection: { + userVerification: options.userVerification ?? 'required', // Webauthn default is "preferred" + authenticatorAttachment: await getAuthAttachment( + options.authenticatorType ?? 'auto' + ) + }, + attestation: 'direct', // options.attestation ? "direct" : "none" + extensions: { + prf: { + eval: { + first: salt + } + } + } + }; + + if (options.debug) console.debug(creationOptions); + + const credential = (await navigator.credentials.create({ + publicKey: creationOptions + })) as PublicKeyCredential; + + if (options.debug) console.debug(credential); + + const response = credential.response as AuthenticatorAttestationResponse; + + const publicKey = ( + response as AuthenticatorAttestationResponseWithPublicKey + ).getPublicKey(); + const publicKeyAlgorithm = ( + credential.response as AuthenticatorResponseWithAlgorithm + ).getPublicKeyAlgorithm(); + if (!publicKey) { + throw new Error('Could not retrieve public key'); + } + + if (!publicKeyAlgorithm) { + throw new Error('Could not retrieve public key algorithm'); + } + + const registration: RegistrationEncoded = { + username: username, + credential: { + id: credential.id, + publicKey: utils.toBase64url(publicKey), + algorithm: getAlgoName(publicKeyAlgorithm) + }, + authenticatorData: utils.toBase64url( + ( + response as AuthenticatorAttestationResponseWithData + ).getAuthenticatorData() + ), + clientData: utils.toBase64url(response.clientDataJSON), + extensionResults: new Uint8Array( + ( + credential.getClientExtensionResults() as AuthenticationExtensionsClientOutputsWithPrf + ).prf.results.first + ) + }; + + if (options.attestation) { + registration.attestationData = utils.toBase64url( + response.attestationObject + ); + } + + return registration; +} + +async function getTransports( + authType: AuthType +): Promise { + const local: AuthenticatorTransport[] = ['internal']; + //@ts-ignore + const roaming: AuthenticatorTransport[] = ['hybrid', 'usb', 'ble', 'nfc']; + + if (authType === 'local') return local; + if (authType == 'roaming' || authType === 'extern') return roaming; + if (authType === 'both') return [...local, ...roaming]; + + // the default case: "auto", depending on device capabilities + try { + if (await isLocalAuthenticator()) return local; + else return roaming; + } catch (e) { + return [...local, ...roaming]; + } +} + +/** + * Signs a challenge using one of the provided credentials IDs in order to authenticate the user. + * + * @param {string[]} credentialIds The list of credential IDs that can be used for signing. + * @param {string} challenge A server-side randomly generated string, the base64 encoded version will be signed. + * @param {Object} [options] Optional parameters. + * @param {number} [options.timeout=60000] Number of milliseconds the user has to respond to the biometric/PIN check. + * @param {'required'|'preferred'|'discouraged'} [options.userVerification='required'] Whether to prompt for biometric/PIN check or not. + * @param {'optional'|'conditional'|'required'|'silent'} [options.mediation='optional'] https://developer.mozilla.org/en-US/docs/Web/API/CredentialsContainer/get#mediation + */ +export async function authenticate( + credentialIds: string[], + challenge: string, + options?: AuthenticateOptions +): Promise { + options = options ?? {}; + + if (!utils.isBase64url(challenge)) + throw new Error('Provided challenge is not properly encoded in Base64url'); + + const transports = await getTransports(options.authenticatorType ?? 'auto'); + + const authOptions: PublicKeyCredentialRequestOptions = { + challenge: utils.parseBase64url(challenge), + rpId: window.location.hostname, + allowCredentials: credentialIds.map((id) => { + return { + id: utils.parseBase64url(id), + type: 'public-key', + transports: transports + }; + }), + userVerification: options.userVerification ?? 'required', + timeout: options.timeout ?? 60000, + extensions: { + prf: { + eval: { + first: salt + } + } + } + }; + + if (options.debug) console.debug(authOptions); + + const auth = (await navigator.credentials.get({ + publicKey: authOptions, + mediation: options.mediation + })) as PublicKeyCredential; + + if (options.debug) console.debug(auth); + + const response = auth.response as AuthenticatorAssertionResponse; + + const authentication: AuthenticationEncoded = { + credentialId: auth.id, + //userHash: utils.toBase64url(response.userHandle), // unreliable, optional for authenticators + authenticatorData: utils.toBase64url(response.authenticatorData), + clientData: utils.toBase64url(response.clientDataJSON), + signature: utils.toBase64url(response.signature), + extensionResults: new Uint8Array( + ( + auth.getClientExtensionResults() as AuthenticationExtensionsClientOutputsWithPrf + ).prf.results.first + ) + }; + + return authentication; +} diff --git a/src/passkeyProvider/lib/webauthn-prf/index.ts b/src/passkeyProvider/lib/webauthn-prf/index.ts new file mode 100644 index 000000000..d7cd16146 --- /dev/null +++ b/src/passkeyProvider/lib/webauthn-prf/index.ts @@ -0,0 +1,5 @@ +import * as client from "./client.js"; +import * as utils from "./utils.js"; + +export { client, utils }; +export default { client, utils }; diff --git a/src/passkeyProvider/lib/webauthn-prf/types.ts b/src/passkeyProvider/lib/webauthn-prf/types.ts new file mode 100644 index 000000000..7d8763f6b --- /dev/null +++ b/src/passkeyProvider/lib/webauthn-prf/types.ts @@ -0,0 +1,142 @@ +// 'extern' is deprecated in favor of 'roaming' but kept for compatibility purposes +export type AuthType = 'auto' | 'local' | 'extern' | 'roaming' | 'both'; + +// TODO: although algo "-8" is currently only used optionally by a few security keys, +// it would not harm to support it for the sake of completeness +export type NumAlgo = -7 | -257; +export type NamedAlgo = 'RS256' | 'ES256'; + +export interface AuthenticateOptions { + userVerification?: UserVerificationRequirement; + authenticatorType?: AuthType; + timeout?: number; + debug?: boolean; + mediation?: CredentialMediationRequirement; +} + +export interface AuthenticatorResponseWithAlgorithm + extends AuthenticatorResponse { + getPublicKeyAlgorithm: () => NumAlgo; +} + +export interface AuthenticationExtensionsClientOutputsWithPrf + extends AuthenticationExtensionsClientOutputs { + prf: { + results: { + first: ArrayBuffer; + }; + }; +} + +export interface AuthenticatorAttestationResponseWithPublicKey + extends AuthenticatorAttestationResponse { + getPublicKey: () => ArrayBuffer | null; +} + +export interface AuthenticatorAttestationResponseWithData + extends AuthenticatorAttestationResponse { + getAuthenticatorData: () => ArrayBuffer; +} + +export interface AuthenticationEncoded { + credentialId: string; + //userHash: string, // unreliable, optional for authenticators + authenticatorData: string; + clientData: string; + signature: string; + extensionResults: Uint8Array; +} + +export interface AuthenticationParsed { + credentialId: string; + //userHash: string, // unreliable, optional for authenticators + authenticator: AuthenticatorInfo; + client: ClientInfo; + signature: string; + extensionResults: Uint8Array; +} + +export interface RegisterOptions extends AuthenticateOptions { + attestation?: boolean; +} + +export interface CredentialKey { + id: string; + publicKey: string; + algorithm: 'RS256' | 'ES256'; +} + +export interface RegistrationEncoded { + username: string; + credential: CredentialKey; + authenticatorData: string; + clientData: string; + attestationData?: string; + extensionResults: Uint8Array; +} + +export interface RegistrationParsed { + username: string; + credential: { + id: string; + publicKey: string; + algorithm: 'RS256' | 'ES256'; + }; + authenticator: AuthenticatorInfo; + client: ClientInfo; + extensionResults: Uint8Array; +} + +export interface ClientInfo { + type: 'webauthn.create' | 'webauthn.get'; + challenge: string; + origin: string; + crossOrigin: boolean; + tokenBindingId?: { + id: string; + status: string; + }; +} + +export interface AuthenticatorInfo { + rpIdHash: string; + flags: { + userPresent: boolean; + userVerified: boolean; + backupEligibility: boolean; + backupState: boolean; + attestedData: boolean; + extensionsIncluded: boolean; + }; + counter: number; + aaguid: string; + name: string; +} + +interface AuthenticationExtensionsClientInputs { + appid?: string; + credProps?: boolean; + hmacCreateSecret?: boolean; + prf: { eval: { first: object } }; +} + +export interface PublicKeyCredentialCreationOptions { + attestation?: AttestationConveyancePreference; + authenticatorSelection?: AuthenticatorSelectionCriteria; + challenge: BufferSource; + excludeCredentials?: PublicKeyCredentialDescriptor[]; + extensions?: AuthenticationExtensionsClientInputs; + pubKeyCredParams: PublicKeyCredentialParameters[]; + rp: PublicKeyCredentialRpEntity; + timeout?: number; + user: PublicKeyCredentialUserEntity; +} + +export interface PublicKeyCredentialRequestOptions { + allowCredentials?: PublicKeyCredentialDescriptor[]; + challenge: BufferSource; + extensions?: AuthenticationExtensionsClientInputs; + rpId?: string; + timeout?: number; + userVerification?: UserVerificationRequirement; +} diff --git a/src/passkeyProvider/lib/webauthn-prf/utils.ts b/src/passkeyProvider/lib/webauthn-prf/utils.ts new file mode 100644 index 000000000..f0cdd4087 --- /dev/null +++ b/src/passkeyProvider/lib/webauthn-prf/utils.ts @@ -0,0 +1,46 @@ +/******************************** + Encoding/Decoding Utils +********************************/ + +export function randomChallenge() { + return crypto.randomUUID(); +} + +export function toBuffer(txt: string): ArrayBuffer { + return Uint8Array.from(txt, (c) => c.charCodeAt(0)).buffer; +} + +export function parseBuffer(buffer: ArrayBuffer): string { + return String.fromCharCode(...new Uint8Array(buffer)); +} + +export function isBase64url(txt: string): boolean { + return txt.match(/^[a-zA-Z0-9\-_]+=*$/) !== null; +} + +export function toBase64url(buffer: ArrayBuffer): string { + const txt = btoa(parseBuffer(buffer)); // base64 + return txt.replaceAll('+', '-').replaceAll('/', '_'); +} + +export function parseBase64url(txt: string): ArrayBuffer { + txt = txt.replaceAll('-', '+').replaceAll('_', '/'); // base64url -> base64 + return toBuffer(atob(txt)); +} + +export async function sha256(buffer: ArrayBuffer): Promise { + return await crypto.subtle.digest('SHA-256', buffer); +} + +export function bufferToHex(buffer: ArrayBuffer): string { + return [...new Uint8Array(buffer)] + .map((b) => b.toString(16).padStart(2, '0')) + .join(''); +} + +export function concatenateBuffers(buffer1: ArrayBuffer, buffer2: ArrayBuffer) { + const tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength); + tmp.set(new Uint8Array(buffer1), 0); + tmp.set(new Uint8Array(buffer2), buffer1.byteLength); + return tmp; +} diff --git a/src/passkeyProvider/operation.ts b/src/passkeyProvider/operation.ts new file mode 100644 index 000000000..d5921a295 --- /dev/null +++ b/src/passkeyProvider/operation.ts @@ -0,0 +1,7 @@ +export enum Operation { + Connect = "connect", + Logout = "logout", + SignTransactions = "signTransactions", + SignMessage = "signMessage", + CancelAction = "cancelAction", +} diff --git a/src/passkeyProvider/passkeyProvider.ts b/src/passkeyProvider/passkeyProvider.ts new file mode 100644 index 000000000..a15cbe4b7 --- /dev/null +++ b/src/passkeyProvider/passkeyProvider.ts @@ -0,0 +1,246 @@ +import { Address } from '@multiversx/sdk-core/out'; +import { SignableMessage } from '@multiversx/sdk-core/out/signableMessage'; +import { Transaction } from '@multiversx/sdk-core/out/transaction'; +import { UserSecretKey, UserSigner } from '@multiversx/sdk-wallet/out'; +import { + AuthenticatorNotSupported, + ErrCannotSignSingleTransaction +} from './errors'; +import { client } from './lib/webauthn-prf'; + +interface IPasskeyAccount { + address: string; + name?: string; + signature?: string; +} + +interface SignMessageParams { + message: string; + address?: string; + privateKey: string; +} + +export class PasskeyProvider { + public account: IPasskeyAccount = { address: '' }; + private initialized = false; + private static _instance: PasskeyProvider = new PasskeyProvider(); + private keyPair: { privateKey: string; publicKey: string } | undefined = + undefined; + + private constructor() { + if (PasskeyProvider._instance) { + throw new Error( + 'Error: Instantiation failed: Use PasskeyProvider.getInstance() instead of new.' + ); + } + PasskeyProvider._instance = this; + } + + public static getInstance(): PasskeyProvider { + return PasskeyProvider._instance; + } + + public setAddress(address: string): PasskeyProvider { + this.account.address = address; + return PasskeyProvider._instance; + } + + async init(): Promise { + this.initialized = true; + return this.initialized; + } + + async login( + options: { + walletName?: string; + callbackUrl?: string; + token?: string; + } = {} + ): Promise<{ address: string; signature?: string }> { + if (!this.initialized) { + throw new Error('Passkey provider is not initialised, call init() first'); + } + const { token } = options; + await this.ensureConnected(); + if (!this.keyPair?.privateKey && !this.keyPair?.publicKey) { + throw new Error('Could not retrieve key pair.'); + } + this.account.address = this.keyPair.publicKey; + + if (token) { + const signedToken = await this.signMessageWithPrivateKey({ + address: this.account.address, + message: token, + privateKey: this.keyPair.privateKey + }); + + this.account.signature = signedToken.getSignature().toString('hex'); + } + + if (!this.keyPair.publicKey) { + throw new Error('Login cancelled'); + } + + this.destroyKeyPair(); + + return { address: this.account.address, signature: this.account.signature }; + } + + private destroyKeyPair() { + this.keyPair = undefined; + } + + private async signMessageWithPrivateKey({ + message, + address, + privateKey + }: SignMessageParams): Promise { + const signer = new UserSigner(UserSecretKey.fromString(privateKey)); + + const messageToSign = new SignableMessage({ + ...(address ? { address: new Address(address) } : {}), + message: Buffer.from(message) + }); + const serializedMessage = messageToSign.serializeForSigning(); + const signature = await signer.sign(serializedMessage); + messageToSign.applySignature(signature); + + return messageToSign; + } + + public setUserKeyPair(inputKeyMaterial: Uint8Array) { + const privateKey = new UserSecretKey(inputKeyMaterial); + const publicKey = privateKey.generatePublicKey().toAddress().bech32(); + if (this.account.address && publicKey !== this.account.address) { + throw new Error( + `Wrong address. Please use the passkey for ${this.account.address}` + ); + } + this.keyPair = { + privateKey: privateKey.hex(), + publicKey + }; + } + + public async createAccount(walletName: string, token: string) { + const challengeFromServer = window.crypto.randomUUID(); + const { extensionResults } = await client.register( + walletName, + challengeFromServer, + { + authenticatorType: 'extern' + } + ); + this.setUserKeyPair(extensionResults); + + return this.login({ walletName, token }); + } + + public async isExistingUser(email: string) { + return Boolean(window.localStorage.getItem(email)); + } + + async logout(): Promise { + if (!this.initialized) { + throw new Error('Passkey provider is not initialised, call init() first'); + } + try { + this.disconnect(); + } catch (error) { + console.warn('Passkey origin url is already cleared!', error); + } + + return true; + } + + private disconnect() { + this.account = { address: '' }; + } + + async getAddress(): Promise { + if (!this.initialized) { + throw new Error('Passkey provider is not initialised, call init() first'); + } + return this.account ? this.account.address : ''; + } + + isInitialized(): boolean { + return this.initialized; + } + + async isConnected(): Promise { + return Boolean(this.account.address); + } + + async signTransaction(transaction: Transaction): Promise { + await this.ensureConnected(); + + const signedTransactions = await this.signTransactions([transaction]); + + if (signedTransactions.length != 1) { + throw new ErrCannotSignSingleTransaction(); + } + this.destroyKeyPair(); + return signedTransactions[0]; + } + + private async ensureConnected() { + if (this.keyPair?.privateKey || this.keyPair?.publicKey) { + return; + } + + const challengeFromServer = window.crypto.randomUUID(); + let inputKeyMaterial: Uint8Array; + try { + const { extensionResults } = await client.authenticate( + [], + challengeFromServer, + { userVerification: 'required', authenticatorType: 'extern' } + ); + inputKeyMaterial = extensionResults; + } catch (error) { + throw new AuthenticatorNotSupported(); + } + this.setUserKeyPair(inputKeyMaterial); + } + + async signTransactions(transactions: Transaction[]): Promise { + await this.ensureConnected(); + + try { + const signer = new UserSigner( + UserSecretKey.fromString(this.keyPair!.privateKey) + ); + + for (const transaction of transactions) { + const signature = await signer.sign(transaction.serializeForSigning()); + transaction.applySignature(signature); + } + this.destroyKeyPair(); + return transactions; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } catch (error: any) { + this.destroyKeyPair(); + throw new Error(`Transaction canceled: ${error.message}.`); + } + } + + async signMessage(message: SignableMessage): Promise { + await this.ensureConnected(); + const signedMessage = await this.signMessageWithPrivateKey({ + message: message.message.toString(), + address: this.account.address, + privateKey: this.keyPair!.privateKey + }); + const signature = signedMessage.getSignature(); + + message.applySignature(signature); + + this.destroyKeyPair(); + return message; + } + + cancelAction() { + return true; + } +} diff --git a/src/providers/accountProvider.ts b/src/providers/accountProvider.ts index cf0b79243..460a52b18 100644 --- a/src/providers/accountProvider.ts +++ b/src/providers/accountProvider.ts @@ -7,6 +7,7 @@ import { CrossWindowProvider, MetamaskProxyProvider } from 'lib/sdkWebWalletCrossWindowProvider'; +import { PasskeyProvider } from 'passkeyProvider'; import { IDappProvider } from 'types'; import { WalletConnectV2Provider } from 'utils/walletconnect/__sdkWalletconnectProvider'; import { emptyProvider } from './utils'; @@ -14,6 +15,7 @@ import { emptyProvider } from './utils'; export type ProvidersType = | IDappProvider | ExtensionProvider + | PasskeyProvider | MetamaskProvider | WalletProvider | CrossWindowProvider diff --git a/src/providers/utils.ts b/src/providers/utils.ts index ef7e67fef..8bc99698a 100644 --- a/src/providers/utils.ts +++ b/src/providers/utils.ts @@ -10,6 +10,7 @@ import { CrossWindowProvider, MetamaskProxyProvider } from 'lib/sdkWebWalletCrossWindowProvider'; +import { PasskeyProvider } from 'passkeyProvider'; import { IDappProvider } from 'types'; import { LoginMethodsEnum } from 'types/enums.types'; import { @@ -31,6 +32,8 @@ export const getProviderType = ( return LoginMethodsEnum.ledger; case ExtensionProvider: return LoginMethodsEnum.extension; + case PasskeyProvider: + return LoginMethodsEnum.passkey; case MetamaskProvider: return LoginMethodsEnum.metamask; case OperaProvider: diff --git a/src/reduxStore/slices/loginInfoSlice.ts b/src/reduxStore/slices/loginInfoSlice.ts index 223293b78..bb0603697 100644 --- a/src/reduxStore/slices/loginInfoSlice.ts +++ b/src/reduxStore/slices/loginInfoSlice.ts @@ -31,6 +31,7 @@ export interface LoginInfoStateType { tokenLogin: TokenLoginType | null; walletLogin: LoginInfoType | null; extensionLogin: LoginInfoType | null; + passkeyLogin: LoginInfoType | null; operaLogin: LoginInfoType | null; crossWindowLogin: LoginInfoType | null; metamaskProxyWindowLogin: LoginInfoType | null; @@ -47,6 +48,7 @@ const initialState: LoginInfoStateType = { tokenLogin: null, walletLogin: null, extensionLogin: null, + passkeyLogin: null, operaLogin: null, crossWindowLogin: null, metamaskProxyWindowLogin: null, diff --git a/src/types/enums.types.ts b/src/types/enums.types.ts index c4f89c32e..1fd2a94c8 100644 --- a/src/types/enums.types.ts +++ b/src/types/enums.types.ts @@ -38,6 +38,7 @@ export enum LoginMethodsEnum { crossWindow = 'crossWindow', metamaskProxy = 'metamaskProxy', extension = 'extension', + passkey = 'passkey', metamask = 'metamask', opera = 'opera', extra = 'extra', diff --git a/yarn.lock b/yarn.lock index 4828d7546..59ae7c370 100644 --- a/yarn.lock +++ b/yarn.lock @@ -92,12 +92,12 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.12.11", "@babel/generator@^7.12.5", "@babel/generator@^7.18.13", "@babel/generator@^7.21.5", "@babel/generator@^7.25.0", "@babel/generator@^7.25.4", "@babel/generator@^7.7.2": - version "7.25.5" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.5.tgz#b31cf05b3fe8c32d206b6dad03bb0aacbde73450" - integrity sha512-abd43wyLfbWoxC6ahM8xTkqLpGB2iWBVyuKC9/srhFunCd1SDNrV1s72bBpK4hLj8KLzHBBcOblvLQZBNw9r3w== +"@babel/generator@^7.12.11", "@babel/generator@^7.12.5", "@babel/generator@^7.18.13", "@babel/generator@^7.21.5", "@babel/generator@^7.25.0", "@babel/generator@^7.25.6", "@babel/generator@^7.7.2": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.6.tgz#0df1ad8cb32fe4d2b01d8bf437f153d19342a87c" + integrity sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw== dependencies: - "@babel/types" "^7.25.4" + "@babel/types" "^7.25.6" "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" @@ -288,12 +288,12 @@ "@babel/types" "^7.25.0" "@babel/helpers@^7.12.5", "@babel/helpers@^7.21.5", "@babel/helpers@^7.25.0": - version "7.25.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.0.tgz#e69beb7841cb93a6505531ede34f34e6a073650a" - integrity sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw== + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.6.tgz#57ee60141829ba2e102f30711ffe3afab357cc60" + integrity sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q== dependencies: "@babel/template" "^7.25.0" - "@babel/types" "^7.25.0" + "@babel/types" "^7.25.6" "@babel/highlight@^7.24.7": version "7.24.7" @@ -305,12 +305,12 @@ js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.12.11", "@babel/parser@^7.12.7", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.21.8", "@babel/parser@^7.23.9", "@babel/parser@^7.25.0", "@babel/parser@^7.25.4": - version "7.25.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.4.tgz#af4f2df7d02440286b7de57b1c21acfb2a6f257a" - integrity sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA== +"@babel/parser@^7.1.0", "@babel/parser@^7.12.11", "@babel/parser@^7.12.7", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.21.8", "@babel/parser@^7.23.9", "@babel/parser@^7.25.0", "@babel/parser@^7.25.6": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.6.tgz#85660c5ef388cbbf6e3d2a694ee97a38f18afe2f" + integrity sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q== dependencies: - "@babel/types" "^7.25.4" + "@babel/types" "^7.25.6" "@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.3": version "7.25.3" @@ -500,18 +500,18 @@ "@babel/helper-plugin-utils" "^7.24.7" "@babel/plugin-syntax-import-assertions@^7.23.3", "@babel/plugin-syntax-import-assertions@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz#2a0b406b5871a20a841240586b1300ce2088a778" - integrity sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg== + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.6.tgz#bb918905c58711b86f9710d74a3744b6c56573b5" + integrity sha512-aABl0jHw9bZ2karQ/uUD6XP4u0SG22SJrOHFoL6XB1R7dTovOP4TzTlsxOYC5yQ1pdscVK2JTUnF6QL3ARoAiQ== dependencies: - "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.8" "@babel/plugin-syntax-import-attributes@^7.23.3", "@babel/plugin-syntax-import-attributes@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz#b4f9ea95a79e6912480c4b626739f86a076624ca" - integrity sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A== + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.6.tgz#6d4c78f042db0e82fd6436cd65fec5dc78ad2bde" + integrity sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ== dependencies: - "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.8" "@babel/plugin-syntax-import-meta@^7.10.4": version "7.10.4" @@ -1329,9 +1329,9 @@ regenerator-runtime "^0.13.2" "@babel/runtime@^7.0.0", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.17.8", "@babel/runtime@^7.5.0", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": - version "7.25.4" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.4.tgz#6ef37d678428306e7d75f054d5b1bdb8cf8aa8ee" - integrity sha512-DSgLeL/FNcpXuzav5wfYvHCGvynXkJbn3Zvc3823AEe9nPwW9IK4UoCSS5yGymmQzN0pCPvivtgS6/8U2kkm1w== + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.6.tgz#9afc3289f7184d8d7f98b099884c26317b9264d2" + integrity sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ== dependencies: regenerator-runtime "^0.14.0" @@ -1352,22 +1352,22 @@ "@babel/types" "^7.25.0" "@babel/traverse@^7.1.6", "@babel/traverse@^7.12.11", "@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.21.5", "@babel/traverse@^7.24.7", "@babel/traverse@^7.24.8", "@babel/traverse@^7.25.0", "@babel/traverse@^7.25.1", "@babel/traverse@^7.25.2", "@babel/traverse@^7.25.3", "@babel/traverse@^7.25.4", "@babel/traverse@^7.7.2": - version "7.25.4" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.4.tgz#648678046990f2957407e3086e97044f13c3e18e" - integrity sha512-VJ4XsrD+nOvlXyLzmLzUs/0qjFS4sK30te5yEFlvbbUNEgKaVb2BHZUpAL+ttLPQAHNrsI3zZisbfha5Cvr8vg== + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.6.tgz#04fad980e444f182ecf1520504941940a90fea41" + integrity sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ== dependencies: "@babel/code-frame" "^7.24.7" - "@babel/generator" "^7.25.4" - "@babel/parser" "^7.25.4" + "@babel/generator" "^7.25.6" + "@babel/parser" "^7.25.6" "@babel/template" "^7.25.0" - "@babel/types" "^7.25.4" + "@babel/types" "^7.25.6" debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.12.11", "@babel/types@^7.12.7", "@babel/types@^7.14.8", "@babel/types@^7.2.0", "@babel/types@^7.20.0", "@babel/types@^7.20.7", "@babel/types@^7.21.5", "@babel/types@^7.24.7", "@babel/types@^7.24.8", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.25.4", "@babel/types@^7.3.3", "@babel/types@^7.4.4": - version "7.25.4" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.4.tgz#6bcb46c72fdf1012a209d016c07f769e10adcb5f" - integrity sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ== +"@babel/types@^7.0.0", "@babel/types@^7.12.11", "@babel/types@^7.12.7", "@babel/types@^7.14.8", "@babel/types@^7.2.0", "@babel/types@^7.20.0", "@babel/types@^7.20.7", "@babel/types@^7.21.5", "@babel/types@^7.24.7", "@babel/types@^7.24.8", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.25.6", "@babel/types@^7.3.3", "@babel/types@^7.4.4": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.6.tgz#893942ddb858f32ae7a004ec9d3a76b3463ef8e6" + integrity sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw== dependencies: "@babel/helper-string-parser" "^7.24.8" "@babel/helper-validator-identifier" "^7.24.7" @@ -2293,9 +2293,9 @@ uuid "^9.0.1" "@metamask/utils@^9.0.0": - version "9.1.0" - resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-9.1.0.tgz#54e5afcec07e6032d4dd4171e862b36daa52d77e" - integrity sha512-g2REf+xSt0OZfMoNNdC4+/Yy8eP3KUqvIArel54XRFKPoXbHI6+YjFfrLtfykWBjffOp7DTfIc3Kvk5TLfuiyg== + version "9.2.1" + resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-9.2.1.tgz#d9f84706ff97e0c8d1bde5778549365b14269e81" + integrity sha512-/u663aUaB6+Xe75i3Mt/1cCljm41HDYIsna5oBrwGvgkY2zH7/9k9Zjd706cxoAbxN7QgLSVAReUiGnuxCuXrQ== dependencies: "@ethereumjs/tx" "^4.2.0" "@metamask/superstruct" "^3.1.0" @@ -6178,9 +6178,9 @@ axios@^0.21.1: follow-redirects "^1.14.0" axios@^1.6.5: - version "1.7.5" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.5.tgz#21eed340eb5daf47d29b6e002424b3e88c8c54b1" - integrity sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw== + version "1.7.6" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.6.tgz#34f338182f6802fd3824a6511d6ddf99dd5ae0b5" + integrity sha512-Ekur6XDwhnJ5RgOCaxFnXyqlPALI3rVeukZMwOdfghW7/wGz784BYKiQq+QD8NPcr91KRo30KfHOchyijwWw7g== dependencies: follow-redirects "^1.15.6" form-data "^4.0.0" @@ -6900,9 +6900,9 @@ can-bind-to-host@^1.1.1: integrity sha512-CqsgmaqiyFRNtP17Ihqa/uHbZxRirntNVNl/kJz31DLKuNRfzvzionkLoUSkElQ6Cz+cpXKA3mhHq4tjbieujA== caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001646: - version "1.0.30001653" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001653.tgz#b8af452f8f33b1c77f122780a4aecebea0caca56" - integrity sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw== + version "1.0.30001655" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001655.tgz#0ce881f5a19a2dcfda2ecd927df4d5c1684b982f" + integrity sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg== capture-exit@^2.0.0: version "2.0.0" @@ -8746,9 +8746,9 @@ esbuild@^0.14.13: esbuild-windows-arm64 "0.14.54" escalade@^3.1.1, escalade@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" - integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== escape-html@~1.0.3: version "1.0.3" @@ -16563,9 +16563,9 @@ ufo@^1.4.0, ufo@^1.5.3: integrity sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ== uglify-js@^3.1.4: - version "3.19.2" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.19.2.tgz#319ae26a5fbd18d03c7dc02496cfa1d6f1cd4307" - integrity sha512-S8KA6DDI47nQXJSi2ctQ629YzwOVs+bQML6DAtvy0wgNdpi+0ySpQK0g2pxBq2xfF2z3YCscu7NNA8nXT9PlIQ== + version "3.19.3" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.19.3.tgz#82315e9bbc6f2b25888858acd1fff8441035b77f" + integrity sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ== uint8arrays@3.1.0: version "3.1.0" From 609c0b89e5fc5d50c77ab9d5c443e718e83027f8 Mon Sep 17 00:00:00 2001 From: Andrei Date: Tue, 3 Sep 2024 10:26:36 +0300 Subject: [PATCH 02/12] changelog --- CHANGELOG.md | 1 + package.json | 3 +- .../SignTransactionsModals.tsx | 9 +- .../SignWithIframeModal.tsx} | 4 +- .../SignWithIframeModal/index.tsx | 1 + .../SignWithMetamaskProxyModal/index.tsx | 1 - .../types/signTransactionsModals.types.ts | 2 +- .../IframeLoginButton/IframeButton.tsx} | 28 +- .../iframeLoginButton.styles.scss} | 2 +- src/UI/iframe/IframeLoginButton/index.ts | 1 + src/UI/index.ts | 2 +- .../MetamaskProxyLoginButton/index.ts | 1 - src/UI/pages/UnlockPage/index.tsx | 10 +- .../ProviderInitializer.tsx | 10 +- ...kProxyProvider.ts => getIframeProvider.ts} | 10 +- .../helpers/getPasskeyProvider.ts | 2 +- .../ProviderInitializer/helpers/index.ts | 2 +- src/constants/dataTestIds.enum.ts | 2 +- .../login/helpers/clearInitiatedLogins.ts | 12 +- ...etamaskProxyLogin.ts => useIframeLogin.ts} | 16 +- src/hooks/login/usePasskeyLogin.ts | 2 +- .../transactions/useSignTransactions.tsx | 16 +- .../useSignTransactionsCommonData.tsx | 16 +- src/lib/sdkWebWalletCrossWindowProvider.ts | 1 - src/passkeyProvider/errors.ts | 29 -- src/passkeyProvider/index.ts | 1 - .../lib/webauthn-prf/client.ts | 268 ------------------ src/passkeyProvider/lib/webauthn-prf/index.ts | 5 - src/passkeyProvider/lib/webauthn-prf/types.ts | 142 ---------- src/passkeyProvider/lib/webauthn-prf/utils.ts | 46 --- src/passkeyProvider/operation.ts | 7 - src/passkeyProvider/passkeyProvider.ts | 246 ---------------- src/providers/accountProvider.ts | 10 +- src/providers/utils.ts | 12 +- src/reduxStore/slices/loginInfoSlice.ts | 4 +- src/types/enums.types.ts | 2 +- src/wrappers/AppInitializer.tsx | 1 + yarn.lock | 74 +++-- 38 files changed, 127 insertions(+), 874 deletions(-) rename src/UI/SignTransactionsModals/{SignWithMetamaskProxyModal/SignWithMetamaskProxyModal.tsx => SignWithIframeModal/SignWithIframeModal.tsx} (81%) create mode 100644 src/UI/SignTransactionsModals/SignWithIframeModal/index.tsx delete mode 100644 src/UI/SignTransactionsModals/SignWithMetamaskProxyModal/index.tsx rename src/UI/{metamaskProxy/MetamaskProxyLoginButton/MetamaskProxyButton.tsx => iframe/IframeLoginButton/IframeButton.tsx} (64%) rename src/UI/{metamaskProxy/MetamaskProxyLoginButton/metamaskProxyLoginButton.styles.scss => iframe/IframeLoginButton/iframeLoginButton.styles.scss} (88%) create mode 100644 src/UI/iframe/IframeLoginButton/index.ts delete mode 100644 src/UI/metamaskProxy/MetamaskProxyLoginButton/index.ts rename src/components/ProviderInitializer/helpers/{getMetamaskProxyProvider.ts => getIframeProvider.ts} (51%) rename src/hooks/login/{useMetamaskProxyLogin.ts => useIframeLogin.ts} (90%) delete mode 100644 src/passkeyProvider/errors.ts delete mode 100644 src/passkeyProvider/index.ts delete mode 100644 src/passkeyProvider/lib/webauthn-prf/client.ts delete mode 100644 src/passkeyProvider/lib/webauthn-prf/index.ts delete mode 100644 src/passkeyProvider/lib/webauthn-prf/types.ts delete mode 100644 src/passkeyProvider/lib/webauthn-prf/utils.ts delete mode 100644 src/passkeyProvider/operation.ts delete mode 100644 src/passkeyProvider/passkeyProvider.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bda5b368..a437c860c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] - [Upgrade sdk-dapp-utils, webview-provider, metamask-proxy-provider and cross-window-provider packages](https://github.com/multiversx/mx-sdk-dapp/pull/1247) +- [Add passkey provider and replace MetamaskProxyProvider with IframeProvider](https://github.com/multiversx/mx-sdk-dapp/pull/1249) ## [[v2.38.8]](https://github.com/multiversx/mx-sdk-dapp/pull/1246)] - 2024-08-29 - [Added sign screens cached tokens functionality](https://github.com/multiversx/mx-sdk-dapp/pull/1245) diff --git a/package.json b/package.json index e6a2943c0..5a72658c8 100644 --- a/package.json +++ b/package.json @@ -161,12 +161,13 @@ "@multiversx/sdk-extension-provider": "3.0.0", "@multiversx/sdk-hw-provider": "6.4.0", "@multiversx/sdk-metamask-provider": "0.0.5", - "@multiversx/sdk-metamask-proxy-provider": "1.0.0", "@multiversx/sdk-native-auth-client": "1.0.7", "@multiversx/sdk-opera-provider": "1.0.0-alpha.1", + "@multiversx/sdk-passkey-provider": "^1.0.0", "@multiversx/sdk-wallet": "4.2.0", "@multiversx/sdk-wallet-connect-provider": "4.1.3", "@multiversx/sdk-web-wallet-cross-window-provider": "1.0.0", + "@multiversx/sdk-web-wallet-iframe-provider": "^1.0.0", "@multiversx/sdk-web-wallet-provider": "3.2.1", "@multiversx/sdk-webview-provider": "1.0.0", "@reduxjs/toolkit": "1.8.2", diff --git a/src/UI/SignTransactionsModals/SignTransactionsModals.tsx b/src/UI/SignTransactionsModals/SignTransactionsModals.tsx index 5c43c9d59..f2417cc15 100644 --- a/src/UI/SignTransactionsModals/SignTransactionsModals.tsx +++ b/src/UI/SignTransactionsModals/SignTransactionsModals.tsx @@ -7,9 +7,9 @@ import { ConfirmationScreen, DeviceConfirmationScreen } from './components'; import { SignWithCrossWindowWalletModal } from './SignWithCrossWindowWalletModal'; import { SignWithExtensionModal } from './SignWithExtensionModal'; import { SignWithExtraModal } from './SignWithExtraModal'; +import { SignWithIframeModal } from './SignWithIframeModal'; import { SignWithLedgerModal } from './SignWithLedgerModal'; import { SignWithMetamaskModal } from './SignWithMetamaskModal'; -import { SignWithMetamaskProxyModal } from './SignWithMetamaskProxyModal'; import { SignWithOperaModal } from './SignWithOperaModal'; import { SignWithPasskeyModal } from './SignWithPasskeyModal'; import { SignWithWalletConnectModal } from './SignWithWalletConnectModal'; @@ -41,8 +41,7 @@ export const SignTransactionsModals = ({ Extension: CustomConfirmScreens?.Extension ?? SignWithExtensionModal, Passkey: CustomConfirmScreens?.Passkey ?? SignWithPasskeyModal, Metamask: CustomConfirmScreens?.Metamask ?? SignWithMetamaskModal, - MetamaskProxy: - CustomConfirmScreens?.MetamaskProxy ?? SignWithMetamaskProxyModal, + Iframe: CustomConfirmScreens?.Iframe ?? SignWithIframeModal, Opera: CustomConfirmScreens?.Opera ?? SignWithOperaModal, CrossWindow: CustomConfirmScreens?.CrossWindow ?? SignWithCrossWindowWalletModal, @@ -85,8 +84,8 @@ export const SignTransactionsModals = ({ return renderScreen({ Screen: ConfirmScreens.Opera }); case LoginMethodsEnum.crossWindow: return renderScreen({ Screen: ConfirmScreens.CrossWindow }); - case LoginMethodsEnum.metamaskProxy: - return renderScreen({ Screen: ConfirmScreens.MetamaskProxy }); + case LoginMethodsEnum.iframe: + return renderScreen({ Screen: ConfirmScreens.Iframe }); case LoginMethodsEnum.wallet: return renderScreen({ Screen: ConfirmScreens.Wallet }); case LoginMethodsEnum.extra: diff --git a/src/UI/SignTransactionsModals/SignWithMetamaskProxyModal/SignWithMetamaskProxyModal.tsx b/src/UI/SignTransactionsModals/SignWithIframeModal/SignWithIframeModal.tsx similarity index 81% rename from src/UI/SignTransactionsModals/SignWithMetamaskProxyModal/SignWithMetamaskProxyModal.tsx rename to src/UI/SignTransactionsModals/SignWithIframeModal/SignWithIframeModal.tsx index 09dd44c36..ef6700f32 100644 --- a/src/UI/SignTransactionsModals/SignWithMetamaskProxyModal/SignWithMetamaskProxyModal.tsx +++ b/src/UI/SignTransactionsModals/SignWithIframeModal/SignWithIframeModal.tsx @@ -6,7 +6,7 @@ import { SignWaitingScreenModalPropsType } from '../components'; -export const SignWithMetamaskProxyModal = (props: SignModalPropsType) => { +export const SignWithIframeModal = (props: SignModalPropsType) => { const description = props.error ? props.error : props.transactions?.length > 1 @@ -16,7 +16,7 @@ export const SignWithMetamaskProxyModal = (props: SignModalPropsType) => { const waitingScreenProps: SignWaitingScreenModalPropsType = { ...props, description, - title: 'Confirm on Metamask Extension' + title: 'Confirm on your authenticated provider' }; return ; diff --git a/src/UI/SignTransactionsModals/SignWithIframeModal/index.tsx b/src/UI/SignTransactionsModals/SignWithIframeModal/index.tsx new file mode 100644 index 000000000..911b79d07 --- /dev/null +++ b/src/UI/SignTransactionsModals/SignWithIframeModal/index.tsx @@ -0,0 +1 @@ +export * from './SignWithIframeModal'; diff --git a/src/UI/SignTransactionsModals/SignWithMetamaskProxyModal/index.tsx b/src/UI/SignTransactionsModals/SignWithMetamaskProxyModal/index.tsx deleted file mode 100644 index deaf98310..000000000 --- a/src/UI/SignTransactionsModals/SignWithMetamaskProxyModal/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from './SignWithMetamaskProxyModal'; diff --git a/src/UI/SignTransactionsModals/types/signTransactionsModals.types.ts b/src/UI/SignTransactionsModals/types/signTransactionsModals.types.ts index 52dcec1e4..3f6f193d3 100644 --- a/src/UI/SignTransactionsModals/types/signTransactionsModals.types.ts +++ b/src/UI/SignTransactionsModals/types/signTransactionsModals.types.ts @@ -27,5 +27,5 @@ export interface CustomConfirmScreensType { WalletConnect?: ScreenType; Wallet?: ScreenType; Extra?: ScreenType; - MetamaskProxy?: ScreenType; + Iframe?: ScreenType; } diff --git a/src/UI/metamaskProxy/MetamaskProxyLoginButton/MetamaskProxyButton.tsx b/src/UI/iframe/IframeLoginButton/IframeButton.tsx similarity index 64% rename from src/UI/metamaskProxy/MetamaskProxyLoginButton/MetamaskProxyButton.tsx rename to src/UI/iframe/IframeLoginButton/IframeButton.tsx index a8f4c909e..ccf2f6835 100644 --- a/src/UI/metamaskProxy/MetamaskProxyLoginButton/MetamaskProxyButton.tsx +++ b/src/UI/iframe/IframeLoginButton/IframeButton.tsx @@ -1,12 +1,12 @@ import React, { ReactNode } from 'react'; import { withStyles, WithStylesImportType } from 'hocs/withStyles'; -import { useMetamaskProxyLogin } from 'hooks/login/useMetamaskProxyLogin'; +import { useIframeLogin } from 'hooks/login/useIframeLogin'; import { getIsNativeAuthSingingForbidden } from 'services/nativeAuth/helpers'; import { LoginButton } from 'UI/LoginButton/LoginButton'; import { OnProviderLoginType } from '../../../types'; import { WithClassnameType } from '../../types'; -export interface MetamaskProxyLoginButtonPropsType +export interface IframeLoginButtonPropsType extends WithClassnameType, OnProviderLoginType { children?: ReactNode; @@ -15,8 +15,8 @@ export interface MetamaskProxyLoginButtonPropsType disabled?: boolean; } -const MetamaskProxyLoginButtonComponent: ( - props: MetamaskProxyLoginButtonPropsType & WithStylesImportType +const IframeLoginButtonComponent: ( + props: IframeLoginButtonPropsType & WithStylesImportType ) => JSX.Element = ({ token, className = 'dapp-metamask-proxy-login', @@ -28,7 +28,7 @@ const MetamaskProxyLoginButtonComponent: ( onLoginRedirect, disabled }) => { - const [onInitiateLogin] = useMetamaskProxyLogin({ + const [onInitiateLogin] = useIframeLogin({ callbackRoute, token, onLoginRedirect, @@ -53,15 +53,9 @@ const MetamaskProxyLoginButtonComponent: ( ); }; -export const MetamaskProxyButton = withStyles( - MetamaskProxyLoginButtonComponent, - { - ssrStyles: () => - import( - 'UI/metamaskProxy/MetamaskProxyLoginButton/metamaskProxyLoginButton.styles.scss' - ), - clientStyles: () => - require('UI/metamaskProxy/MetamaskProxyLoginButton/metamaskProxyLoginButton.styles.scss') - .default - } -); +export const IframeButton = withStyles(IframeLoginButtonComponent, { + ssrStyles: () => + import('UI/iframe/IframeLoginButton/iframeLoginButton.styles.scss'), + clientStyles: () => + require('UI/iframe/IframeLoginButton/iframeLoginButton.styles.scss').default +}); diff --git a/src/UI/metamaskProxy/MetamaskProxyLoginButton/metamaskProxyLoginButton.styles.scss b/src/UI/iframe/IframeLoginButton/iframeLoginButton.styles.scss similarity index 88% rename from src/UI/metamaskProxy/MetamaskProxyLoginButton/metamaskProxyLoginButton.styles.scss rename to src/UI/iframe/IframeLoginButton/iframeLoginButton.styles.scss index d60e781d7..2b8626d66 100644 --- a/src/UI/metamaskProxy/MetamaskProxyLoginButton/metamaskProxyLoginButton.styles.scss +++ b/src/UI/iframe/IframeLoginButton/iframeLoginButton.styles.scss @@ -10,7 +10,7 @@ box-sizing: border-box; } -.noMetamaskProxyButtonContent { +.noIframeButtonContent { box-sizing: border-box; } diff --git a/src/UI/iframe/IframeLoginButton/index.ts b/src/UI/iframe/IframeLoginButton/index.ts new file mode 100644 index 000000000..6a65c504a --- /dev/null +++ b/src/UI/iframe/IframeLoginButton/index.ts @@ -0,0 +1 @@ +export * from './IframeButton'; diff --git a/src/UI/index.ts b/src/UI/index.ts index 3ebc22ea9..0ffc3d91e 100644 --- a/src/UI/index.ts +++ b/src/UI/index.ts @@ -31,4 +31,4 @@ export * from './TransactionsTable'; export * from './ScamPhishingAlert'; export * from './TimeAgo'; export * from './metamask/MetamaskLoginButton'; -export * from './metamaskProxy/MetamaskProxyLoginButton'; +export * from './iframe/IframeLoginButton'; diff --git a/src/UI/metamaskProxy/MetamaskProxyLoginButton/index.ts b/src/UI/metamaskProxy/MetamaskProxyLoginButton/index.ts deleted file mode 100644 index 7cd1b0dde..000000000 --- a/src/UI/metamaskProxy/MetamaskProxyLoginButton/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './MetamaskProxyButton'; diff --git a/src/UI/pages/UnlockPage/index.tsx b/src/UI/pages/UnlockPage/index.tsx index 9f0826ba6..50ceb829d 100644 --- a/src/UI/pages/UnlockPage/index.tsx +++ b/src/UI/pages/UnlockPage/index.tsx @@ -3,8 +3,8 @@ import classNames from 'classnames'; import { withStyles, WithStylesImportType } from 'hocs/withStyles'; import { useGetLoginInfo } from 'hooks'; import { ExtensionLoginButton } from 'UI/extension/ExtensionLoginButton'; +import { IframeButton } from 'UI/iframe/IframeLoginButton'; import { LedgerLoginButton } from 'UI/ledger/LedgerLoginButton'; -import { MetamaskProxyButton } from 'UI/metamaskProxy/MetamaskProxyLoginButton'; import { OperaWalletLoginButton } from 'UI/operaWallet/OperaWalletLoginButton'; import { PasskeyLoginButton } from 'UI/passkey/PasskeyLoginButton'; import { WalletConnectLoginButton } from 'UI/walletConnect/WalletConnectLoginButton'; @@ -20,7 +20,7 @@ export interface Props { PasskeyLoginButtonText?: string; OperaWalletLoginButtonText?: string; CrossWindowLoginButtonText?: string; - MetamaskProxyLoginButtonText?: string; + IframeLoginButtonText?: string; WebWalletLoginButtonText?: string; WalletConnectLoginButtonText?: string; WalletConnectV2LoginButtonText?: string; @@ -37,7 +37,7 @@ const UnlockPageComponent = ({ ExtensionLoginButtonText = 'Extension', PasskeyLoginButtonText = 'Passkey', OperaWalletLoginButtonText = 'Opera Crypto Wallet', - MetamaskProxyLoginButtonText = 'Metamask Proxy', + IframeLoginButtonText = 'Embeded web wallet', WebWalletLoginButtonText = 'Web wallet', globalStyles, styles @@ -95,9 +95,9 @@ const UnlockPageComponent = ({ loginButtonText={PasskeyLoginButtonText} /> - { @@ -13,9 +11,9 @@ export const clearInitiatedLogins = (props?: { skip: LoginMethodsEnum }) => { if (crossWindowProvider.isInitialized()) { crossWindowProvider.dispose(); } - const metamaskProvider = MetamaskProxyProvider.getInstance(); - if (metamaskProvider.isInitialized()) { - metamaskProvider.dispose(); + const iframeProvider = IframeProvider.getInstance(); + if (iframeProvider.isInitialized()) { + iframeProvider.dispose(); } }); diff --git a/src/hooks/login/useMetamaskProxyLogin.ts b/src/hooks/login/useIframeLogin.ts similarity index 90% rename from src/hooks/login/useMetamaskProxyLogin.ts rename to src/hooks/login/useIframeLogin.ts index b9697ab40..4467ea55b 100644 --- a/src/hooks/login/useMetamaskProxyLogin.ts +++ b/src/hooks/login/useIframeLogin.ts @@ -1,7 +1,7 @@ import { useState } from 'react'; +import { IframeProvider } from '@multiversx/sdk-web-wallet-iframe-provider/out'; import { processModifiedAccount } from 'components/ProviderInitializer/helpers/processModifiedAccount'; import { SECOND_LOGIN_ATTEMPT_ERROR } from 'constants/errorsMessages'; -import { MetamaskProxyProvider } from 'lib/sdkWebWalletCrossWindowProvider'; import { setAccountProvider } from 'providers/accountProvider'; import { loginAction } from 'reduxStore/commonActions'; import { useDispatch, useSelector } from 'reduxStore/DappProviderContext'; @@ -19,19 +19,19 @@ import { getWindowLocation } from 'utils/window/getWindowLocation'; import { clearInitiatedLogins } from './helpers'; import { useLoginService } from './useLoginService'; -export type UseMetamaskProxyLoginReturnType = [ +export type UseIframeLoginReturnType = [ InitiateLoginFunctionType, LoginHookGenericStateType ]; -export const useMetamaskProxyLogin = ({ +export const useIframeLogin = ({ callbackRoute, token: tokenToSign, nativeAuth, walletAddress }: OnProviderLoginType & { walletAddress?: string; -}): UseMetamaskProxyLoginReturnType => { +}): UseIframeLoginReturnType => { const [error, setError] = useState(''); const [isLoading, setIsLoading] = useState(false); const hasNativeAuth = nativeAuth != null; @@ -48,16 +48,16 @@ export const useMetamaskProxyLogin = ({ } clearInitiatedLogins({ - skip: LoginMethodsEnum.metamaskProxy + skip: LoginMethodsEnum.iframe }); setIsLoading(true); - const provider = MetamaskProxyProvider.getInstance(); + const provider = IframeProvider.getInstance(); const walletUrl = walletAddress ?? network.metamaskSnapWalletAddress; if (!walletUrl) { - setError('Metamask snap wallet URL is not set'); + setError('Iframe snap wallet URL is not set'); return; } provider.setWalletUrl(walletUrl); @@ -122,7 +122,7 @@ export const useMetamaskProxyLogin = ({ dispatch( loginAction({ address: account.address, - loginMethod: LoginMethodsEnum.metamaskProxy + loginMethod: LoginMethodsEnum.iframe }) ); diff --git a/src/hooks/login/usePasskeyLogin.ts b/src/hooks/login/usePasskeyLogin.ts index 9891ca05f..b6c3f0003 100644 --- a/src/hooks/login/usePasskeyLogin.ts +++ b/src/hooks/login/usePasskeyLogin.ts @@ -1,7 +1,7 @@ import { useState } from 'react'; +import { PasskeyProvider } from '@multiversx/sdk-passkey-provider/out'; import { SECOND_LOGIN_ATTEMPT_ERROR } from 'constants/errorsMessages'; -import { PasskeyProvider } from 'passkeyProvider'; import { setAccountProvider } from 'providers/accountProvider'; import { loginAction } from 'reduxStore/commonActions'; import { useDispatch } from 'reduxStore/DappProviderContext'; diff --git a/src/hooks/transactions/useSignTransactions.tsx b/src/hooks/transactions/useSignTransactions.tsx index bb9554c3e..0f3657bde 100644 --- a/src/hooks/transactions/useSignTransactions.tsx +++ b/src/hooks/transactions/useSignTransactions.tsx @@ -8,6 +8,8 @@ import { import { ExtensionProvider } from '@multiversx/sdk-extension-provider'; import { MetamaskProvider } from '@multiversx/sdk-metamask-provider/out/metamaskProvider'; +import { PasskeyProvider } from '@multiversx/sdk-passkey-provider/out'; +import { IframeProvider } from '@multiversx/sdk-web-wallet-iframe-provider/out'; import uniq from 'lodash/uniq'; import { useGetAccountFromApi } from 'apiCalls/accounts/useGetAccountFromApi'; import { @@ -22,11 +24,7 @@ import { import { useGetAccount } from 'hooks/account'; import { useGetAccountProvider } from 'hooks/account/useGetAccountProvider'; import { useParseSignedTransactions } from 'hooks/transactions/useParseSignedTransactions'; -import { - CrossWindowProvider, - MetamaskProxyProvider -} from 'lib/sdkWebWalletCrossWindowProvider'; -import { PasskeyProvider } from 'passkeyProvider'; +import { CrossWindowProvider } from 'lib/sdkWebWalletCrossWindowProvider'; import { ExperimentalWebviewProvider } from 'providers/experimentalWebViewProvider'; import { getProviderType } from 'providers/utils'; @@ -101,7 +99,7 @@ export const useSignTransactions = () => { const isExtensionProvider = provider instanceof ExtensionProvider; const isPasskeyProvider = provider instanceof PasskeyProvider; const isCrossWindowProvider = provider instanceof CrossWindowProvider; - const isMetamaskProxyProvider = provider instanceof MetamaskProxyProvider; + const isIframeProvider = provider instanceof IframeProvider; const isMetamaskProvider = provider instanceof MetamaskProvider; const isExperiementalWebviewProvider = provider instanceof ExperimentalWebviewProvider; @@ -114,7 +112,7 @@ export const useSignTransactions = () => { if ( !isExtensionProvider && !isCrossWindowProvider && - !isMetamaskProxyProvider && + !isIframeProvider && !isPasskeyProvider && !isMetamaskProvider ) { @@ -135,8 +133,8 @@ export const useSignTransactions = () => { if (isCrossWindowProvider) { CrossWindowProvider.getInstance()?.cancelAction?.(); } - if (isMetamaskProxyProvider) { - MetamaskProxyProvider.getInstance()?.cancelAction?.(); + if (isIframeProvider) { + IframeProvider.getInstance()?.cancelAction?.(); } if (isExperiementalWebviewProvider) { ExperimentalWebviewProvider.getInstance()?.cancelAction?.(); diff --git a/src/hooks/transactions/useSignTransactionsCommonData.tsx b/src/hooks/transactions/useSignTransactionsCommonData.tsx index f119bf871..2c35cf229 100644 --- a/src/hooks/transactions/useSignTransactionsCommonData.tsx +++ b/src/hooks/transactions/useSignTransactionsCommonData.tsx @@ -3,15 +3,13 @@ import { useEffect, useState } from 'react'; import { Transaction } from '@multiversx/sdk-core/out'; import { ExtensionProvider } from '@multiversx/sdk-extension-provider'; import { MetamaskProvider } from '@multiversx/sdk-metamask-provider/out/metamaskProvider'; +import { PasskeyProvider } from '@multiversx/sdk-passkey-provider/out'; +import { IframeProvider } from '@multiversx/sdk-web-wallet-iframe-provider/out'; import { useGetAccount } from 'hooks/account'; import { useGetAccountProvider } from 'hooks/account/useGetAccountProvider'; import { useParseSignedTransactions } from 'hooks/transactions/useParseSignedTransactions'; -import { - CrossWindowProvider, - MetamaskProxyProvider -} from 'lib/sdkWebWalletCrossWindowProvider'; +import { CrossWindowProvider } from 'lib/sdkWebWalletCrossWindowProvider'; -import { PasskeyProvider } from 'passkeyProvider'; import { ExperimentalWebviewProvider } from 'providers/experimentalWebViewProvider'; import { useDispatch, useSelector } from 'reduxStore/DappProviderContext'; import { @@ -74,7 +72,7 @@ export const useSignTransactionsCommonData = () => { const isExtensionProvider = provider instanceof ExtensionProvider; const isPasskeyProvider = provider instanceof PasskeyProvider; const isCrossWindowProvider = provider instanceof CrossWindowProvider; - const isMetamaskProxyProvider = provider instanceof MetamaskProxyProvider; + const isIframeProvider = provider instanceof IframeProvider; const isMetamaskProvider = provider instanceof MetamaskProvider; const isExperimentalWebviewProvider = provider instanceof ExperimentalWebviewProvider; @@ -85,7 +83,7 @@ export const useSignTransactionsCommonData = () => { if ( !isExtensionProvider && !isCrossWindowProvider && - !isMetamaskProxyProvider && + !isIframeProvider && !isPasskeyProvider && !isMetamaskProvider ) { @@ -110,8 +108,8 @@ export const useSignTransactionsCommonData = () => { CrossWindowProvider.getInstance()?.cancelAction?.(); } - if (isMetamaskProxyProvider) { - MetamaskProxyProvider.getInstance()?.cancelAction?.(); + if (isIframeProvider) { + IframeProvider.getInstance()?.cancelAction?.(); } if (isExperimentalWebviewProvider) { diff --git a/src/lib/sdkWebWalletCrossWindowProvider.ts b/src/lib/sdkWebWalletCrossWindowProvider.ts index bf0e541c5..7bf070682 100644 --- a/src/lib/sdkWebWalletCrossWindowProvider.ts +++ b/src/lib/sdkWebWalletCrossWindowProvider.ts @@ -1,2 +1 @@ export { CrossWindowProvider } from '@multiversx/sdk-web-wallet-cross-window-provider/out/CrossWindowProvider/CrossWindowProvider'; -export { MetamaskProxyProvider } from '@multiversx/sdk-metamask-proxy-provider/out/MetamaskProxyProvider/MetamaskProxyProvider'; diff --git a/src/passkeyProvider/errors.ts b/src/passkeyProvider/errors.ts deleted file mode 100644 index 9f474caf0..000000000 --- a/src/passkeyProvider/errors.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * The base class for exceptions (errors). - */ -export class Err extends Error { - inner: Error | undefined = undefined; - - public constructor(message: string, inner?: Error) { - super(message); - this.inner = inner; - } -} - -export class ErrCannotSignSingleTransaction extends Err { - public constructor() { - super("Cannot sign single transaction."); - } -} - -export class ErrAccountNotConnected extends Err { - public constructor() { - super("Account is not connected."); - } -} - -export class AuthenticatorNotSupported extends Err { - public constructor() { - super("Passkey authenticator does not support PRF."); - } -} diff --git a/src/passkeyProvider/index.ts b/src/passkeyProvider/index.ts deleted file mode 100644 index 49c7204fb..000000000 --- a/src/passkeyProvider/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./passkeyProvider"; diff --git a/src/passkeyProvider/lib/webauthn-prf/client.ts b/src/passkeyProvider/lib/webauthn-prf/client.ts deleted file mode 100644 index 4f993076a..000000000 --- a/src/passkeyProvider/lib/webauthn-prf/client.ts +++ /dev/null @@ -1,268 +0,0 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ -import { - AuthenticateOptions, - AuthenticationEncoded, - AuthenticationExtensionsClientOutputsWithPrf, - AuthenticatorAttestationResponseWithData, - AuthenticatorAttestationResponseWithPublicKey, - AuthenticatorResponseWithAlgorithm, - AuthType, - NamedAlgo, - NumAlgo, - PublicKeyCredentialCreationOptions, - PublicKeyCredentialRequestOptions, - RegisterOptions, - RegistrationEncoded -} from './types.js'; -import * as utils from './utils.js'; - -//generated with crypto.getRandomValues -const randomness = - '125,31,50,6,242,196,44,99,212,140,13,135,165,76,139,234,130,235,189,246,131,38,217,236,172,174,67,82,180,79,137,150'; -const salt = new Uint8Array(randomness.split(',').map((str) => parseInt(str))) - .buffer; - -/** - * Returns whether passwordless authentication is available on this browser/platform or not. - */ -export function isAvailable(): boolean { - return !!window.PublicKeyCredential; -} - -/** - * Returns whether the device itself can be used as authenticator. - */ -export async function isLocalAuthenticator(): Promise { - return await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable(); -} - -async function getAuthAttachment( - authType: AuthType -): Promise { - if (authType === 'local') return 'platform'; - if (authType === 'roaming' || authType === 'extern') return 'cross-platform'; - if (authType === 'both') return undefined; // The webauthn protocol considers `null` as invalid but `undefined` as "both"! - - // the default case: "auto", depending on device capabilities - try { - if (await isLocalAuthenticator()) return 'platform'; - else return 'cross-platform'; - } catch (e) { - // might happen due to some security policies - // see https://w3c.github.io/webauthn/#sctn-isUserVerifyingPlatformAuthenticatorAvailable - return undefined; // The webauthn protocol considers `null` as invalid but `undefined` as "both"! - } -} - -function getAlgoName(num: NumAlgo): NamedAlgo { - switch (num) { - case -7: - return 'ES256'; - // case -8 ignored to to its rarity - case -257: - return 'RS256'; - default: - throw new Error(`Unknown algorithm code: ${num}`); - } -} - -/** - * Creates a cryptographic key pair, in order to register the public key for later passwordless authentication. - * - * @param {string} username - * @param {string} challenge A server-side randomly generated string. - * @param {Object} [options] Optional parameters. - * @param {number} [options.timeout=60000] Number of milliseconds the user has to respond to the biometric/PIN check. - * @param {'required'|'preferred'|'discouraged'} [options.userVerification='required'] Whether to prompt for biometric/PIN check or not. - * @param {'auto'|'local'|'roaming'|'both'} [options.authenticatorType='auto'] Which device to use as authenticator. - * 'auto': if the local device can be used as authenticator it will be preferred. Otherwise it will prompt for a roaming device. - * 'local': use the local device (using TouchID, FaceID, Windows Hello or PIN) - * 'roaming': use a roaming device (security key or connected phone) - * 'both': prompt the user to choose between local or roaming device. The UI and user interaction in this case is platform specific. - * @param {boolean} [attestation=false] If enabled, the device attestation and clientData will be provided as Base64url encoded binary data. - * Note that this is not available on some platforms. - */ -export async function register( - username: string, - challenge: string, - options?: RegisterOptions -): Promise { - options = options ?? {}; - - if (!utils.isBase64url(challenge)) - throw new Error('Provided challenge is not properly encoded in Base64url'); - - const creationOptions: PublicKeyCredentialCreationOptions = { - challenge: utils.parseBase64url(challenge), - rp: { - id: window.location.hostname, - name: window.location.hostname - }, - user: { - id: await utils.sha256(new TextEncoder().encode(username)), // ID should not be directly "identifiable" for privacy concerns - name: username, - displayName: username - }, - pubKeyCredParams: [ - { alg: -7, type: 'public-key' }, // ES256 (Webauthn's default algorithm) - { alg: -257, type: 'public-key' } // RS256 (for Windows Hello and others) - ], - timeout: options.timeout ?? 60000, - authenticatorSelection: { - userVerification: options.userVerification ?? 'required', // Webauthn default is "preferred" - authenticatorAttachment: await getAuthAttachment( - options.authenticatorType ?? 'auto' - ) - }, - attestation: 'direct', // options.attestation ? "direct" : "none" - extensions: { - prf: { - eval: { - first: salt - } - } - } - }; - - if (options.debug) console.debug(creationOptions); - - const credential = (await navigator.credentials.create({ - publicKey: creationOptions - })) as PublicKeyCredential; - - if (options.debug) console.debug(credential); - - const response = credential.response as AuthenticatorAttestationResponse; - - const publicKey = ( - response as AuthenticatorAttestationResponseWithPublicKey - ).getPublicKey(); - const publicKeyAlgorithm = ( - credential.response as AuthenticatorResponseWithAlgorithm - ).getPublicKeyAlgorithm(); - if (!publicKey) { - throw new Error('Could not retrieve public key'); - } - - if (!publicKeyAlgorithm) { - throw new Error('Could not retrieve public key algorithm'); - } - - const registration: RegistrationEncoded = { - username: username, - credential: { - id: credential.id, - publicKey: utils.toBase64url(publicKey), - algorithm: getAlgoName(publicKeyAlgorithm) - }, - authenticatorData: utils.toBase64url( - ( - response as AuthenticatorAttestationResponseWithData - ).getAuthenticatorData() - ), - clientData: utils.toBase64url(response.clientDataJSON), - extensionResults: new Uint8Array( - ( - credential.getClientExtensionResults() as AuthenticationExtensionsClientOutputsWithPrf - ).prf.results.first - ) - }; - - if (options.attestation) { - registration.attestationData = utils.toBase64url( - response.attestationObject - ); - } - - return registration; -} - -async function getTransports( - authType: AuthType -): Promise { - const local: AuthenticatorTransport[] = ['internal']; - //@ts-ignore - const roaming: AuthenticatorTransport[] = ['hybrid', 'usb', 'ble', 'nfc']; - - if (authType === 'local') return local; - if (authType == 'roaming' || authType === 'extern') return roaming; - if (authType === 'both') return [...local, ...roaming]; - - // the default case: "auto", depending on device capabilities - try { - if (await isLocalAuthenticator()) return local; - else return roaming; - } catch (e) { - return [...local, ...roaming]; - } -} - -/** - * Signs a challenge using one of the provided credentials IDs in order to authenticate the user. - * - * @param {string[]} credentialIds The list of credential IDs that can be used for signing. - * @param {string} challenge A server-side randomly generated string, the base64 encoded version will be signed. - * @param {Object} [options] Optional parameters. - * @param {number} [options.timeout=60000] Number of milliseconds the user has to respond to the biometric/PIN check. - * @param {'required'|'preferred'|'discouraged'} [options.userVerification='required'] Whether to prompt for biometric/PIN check or not. - * @param {'optional'|'conditional'|'required'|'silent'} [options.mediation='optional'] https://developer.mozilla.org/en-US/docs/Web/API/CredentialsContainer/get#mediation - */ -export async function authenticate( - credentialIds: string[], - challenge: string, - options?: AuthenticateOptions -): Promise { - options = options ?? {}; - - if (!utils.isBase64url(challenge)) - throw new Error('Provided challenge is not properly encoded in Base64url'); - - const transports = await getTransports(options.authenticatorType ?? 'auto'); - - const authOptions: PublicKeyCredentialRequestOptions = { - challenge: utils.parseBase64url(challenge), - rpId: window.location.hostname, - allowCredentials: credentialIds.map((id) => { - return { - id: utils.parseBase64url(id), - type: 'public-key', - transports: transports - }; - }), - userVerification: options.userVerification ?? 'required', - timeout: options.timeout ?? 60000, - extensions: { - prf: { - eval: { - first: salt - } - } - } - }; - - if (options.debug) console.debug(authOptions); - - const auth = (await navigator.credentials.get({ - publicKey: authOptions, - mediation: options.mediation - })) as PublicKeyCredential; - - if (options.debug) console.debug(auth); - - const response = auth.response as AuthenticatorAssertionResponse; - - const authentication: AuthenticationEncoded = { - credentialId: auth.id, - //userHash: utils.toBase64url(response.userHandle), // unreliable, optional for authenticators - authenticatorData: utils.toBase64url(response.authenticatorData), - clientData: utils.toBase64url(response.clientDataJSON), - signature: utils.toBase64url(response.signature), - extensionResults: new Uint8Array( - ( - auth.getClientExtensionResults() as AuthenticationExtensionsClientOutputsWithPrf - ).prf.results.first - ) - }; - - return authentication; -} diff --git a/src/passkeyProvider/lib/webauthn-prf/index.ts b/src/passkeyProvider/lib/webauthn-prf/index.ts deleted file mode 100644 index d7cd16146..000000000 --- a/src/passkeyProvider/lib/webauthn-prf/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import * as client from "./client.js"; -import * as utils from "./utils.js"; - -export { client, utils }; -export default { client, utils }; diff --git a/src/passkeyProvider/lib/webauthn-prf/types.ts b/src/passkeyProvider/lib/webauthn-prf/types.ts deleted file mode 100644 index 7d8763f6b..000000000 --- a/src/passkeyProvider/lib/webauthn-prf/types.ts +++ /dev/null @@ -1,142 +0,0 @@ -// 'extern' is deprecated in favor of 'roaming' but kept for compatibility purposes -export type AuthType = 'auto' | 'local' | 'extern' | 'roaming' | 'both'; - -// TODO: although algo "-8" is currently only used optionally by a few security keys, -// it would not harm to support it for the sake of completeness -export type NumAlgo = -7 | -257; -export type NamedAlgo = 'RS256' | 'ES256'; - -export interface AuthenticateOptions { - userVerification?: UserVerificationRequirement; - authenticatorType?: AuthType; - timeout?: number; - debug?: boolean; - mediation?: CredentialMediationRequirement; -} - -export interface AuthenticatorResponseWithAlgorithm - extends AuthenticatorResponse { - getPublicKeyAlgorithm: () => NumAlgo; -} - -export interface AuthenticationExtensionsClientOutputsWithPrf - extends AuthenticationExtensionsClientOutputs { - prf: { - results: { - first: ArrayBuffer; - }; - }; -} - -export interface AuthenticatorAttestationResponseWithPublicKey - extends AuthenticatorAttestationResponse { - getPublicKey: () => ArrayBuffer | null; -} - -export interface AuthenticatorAttestationResponseWithData - extends AuthenticatorAttestationResponse { - getAuthenticatorData: () => ArrayBuffer; -} - -export interface AuthenticationEncoded { - credentialId: string; - //userHash: string, // unreliable, optional for authenticators - authenticatorData: string; - clientData: string; - signature: string; - extensionResults: Uint8Array; -} - -export interface AuthenticationParsed { - credentialId: string; - //userHash: string, // unreliable, optional for authenticators - authenticator: AuthenticatorInfo; - client: ClientInfo; - signature: string; - extensionResults: Uint8Array; -} - -export interface RegisterOptions extends AuthenticateOptions { - attestation?: boolean; -} - -export interface CredentialKey { - id: string; - publicKey: string; - algorithm: 'RS256' | 'ES256'; -} - -export interface RegistrationEncoded { - username: string; - credential: CredentialKey; - authenticatorData: string; - clientData: string; - attestationData?: string; - extensionResults: Uint8Array; -} - -export interface RegistrationParsed { - username: string; - credential: { - id: string; - publicKey: string; - algorithm: 'RS256' | 'ES256'; - }; - authenticator: AuthenticatorInfo; - client: ClientInfo; - extensionResults: Uint8Array; -} - -export interface ClientInfo { - type: 'webauthn.create' | 'webauthn.get'; - challenge: string; - origin: string; - crossOrigin: boolean; - tokenBindingId?: { - id: string; - status: string; - }; -} - -export interface AuthenticatorInfo { - rpIdHash: string; - flags: { - userPresent: boolean; - userVerified: boolean; - backupEligibility: boolean; - backupState: boolean; - attestedData: boolean; - extensionsIncluded: boolean; - }; - counter: number; - aaguid: string; - name: string; -} - -interface AuthenticationExtensionsClientInputs { - appid?: string; - credProps?: boolean; - hmacCreateSecret?: boolean; - prf: { eval: { first: object } }; -} - -export interface PublicKeyCredentialCreationOptions { - attestation?: AttestationConveyancePreference; - authenticatorSelection?: AuthenticatorSelectionCriteria; - challenge: BufferSource; - excludeCredentials?: PublicKeyCredentialDescriptor[]; - extensions?: AuthenticationExtensionsClientInputs; - pubKeyCredParams: PublicKeyCredentialParameters[]; - rp: PublicKeyCredentialRpEntity; - timeout?: number; - user: PublicKeyCredentialUserEntity; -} - -export interface PublicKeyCredentialRequestOptions { - allowCredentials?: PublicKeyCredentialDescriptor[]; - challenge: BufferSource; - extensions?: AuthenticationExtensionsClientInputs; - rpId?: string; - timeout?: number; - userVerification?: UserVerificationRequirement; -} diff --git a/src/passkeyProvider/lib/webauthn-prf/utils.ts b/src/passkeyProvider/lib/webauthn-prf/utils.ts deleted file mode 100644 index f0cdd4087..000000000 --- a/src/passkeyProvider/lib/webauthn-prf/utils.ts +++ /dev/null @@ -1,46 +0,0 @@ -/******************************** - Encoding/Decoding Utils -********************************/ - -export function randomChallenge() { - return crypto.randomUUID(); -} - -export function toBuffer(txt: string): ArrayBuffer { - return Uint8Array.from(txt, (c) => c.charCodeAt(0)).buffer; -} - -export function parseBuffer(buffer: ArrayBuffer): string { - return String.fromCharCode(...new Uint8Array(buffer)); -} - -export function isBase64url(txt: string): boolean { - return txt.match(/^[a-zA-Z0-9\-_]+=*$/) !== null; -} - -export function toBase64url(buffer: ArrayBuffer): string { - const txt = btoa(parseBuffer(buffer)); // base64 - return txt.replaceAll('+', '-').replaceAll('/', '_'); -} - -export function parseBase64url(txt: string): ArrayBuffer { - txt = txt.replaceAll('-', '+').replaceAll('_', '/'); // base64url -> base64 - return toBuffer(atob(txt)); -} - -export async function sha256(buffer: ArrayBuffer): Promise { - return await crypto.subtle.digest('SHA-256', buffer); -} - -export function bufferToHex(buffer: ArrayBuffer): string { - return [...new Uint8Array(buffer)] - .map((b) => b.toString(16).padStart(2, '0')) - .join(''); -} - -export function concatenateBuffers(buffer1: ArrayBuffer, buffer2: ArrayBuffer) { - const tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength); - tmp.set(new Uint8Array(buffer1), 0); - tmp.set(new Uint8Array(buffer2), buffer1.byteLength); - return tmp; -} diff --git a/src/passkeyProvider/operation.ts b/src/passkeyProvider/operation.ts deleted file mode 100644 index d5921a295..000000000 --- a/src/passkeyProvider/operation.ts +++ /dev/null @@ -1,7 +0,0 @@ -export enum Operation { - Connect = "connect", - Logout = "logout", - SignTransactions = "signTransactions", - SignMessage = "signMessage", - CancelAction = "cancelAction", -} diff --git a/src/passkeyProvider/passkeyProvider.ts b/src/passkeyProvider/passkeyProvider.ts deleted file mode 100644 index a15cbe4b7..000000000 --- a/src/passkeyProvider/passkeyProvider.ts +++ /dev/null @@ -1,246 +0,0 @@ -import { Address } from '@multiversx/sdk-core/out'; -import { SignableMessage } from '@multiversx/sdk-core/out/signableMessage'; -import { Transaction } from '@multiversx/sdk-core/out/transaction'; -import { UserSecretKey, UserSigner } from '@multiversx/sdk-wallet/out'; -import { - AuthenticatorNotSupported, - ErrCannotSignSingleTransaction -} from './errors'; -import { client } from './lib/webauthn-prf'; - -interface IPasskeyAccount { - address: string; - name?: string; - signature?: string; -} - -interface SignMessageParams { - message: string; - address?: string; - privateKey: string; -} - -export class PasskeyProvider { - public account: IPasskeyAccount = { address: '' }; - private initialized = false; - private static _instance: PasskeyProvider = new PasskeyProvider(); - private keyPair: { privateKey: string; publicKey: string } | undefined = - undefined; - - private constructor() { - if (PasskeyProvider._instance) { - throw new Error( - 'Error: Instantiation failed: Use PasskeyProvider.getInstance() instead of new.' - ); - } - PasskeyProvider._instance = this; - } - - public static getInstance(): PasskeyProvider { - return PasskeyProvider._instance; - } - - public setAddress(address: string): PasskeyProvider { - this.account.address = address; - return PasskeyProvider._instance; - } - - async init(): Promise { - this.initialized = true; - return this.initialized; - } - - async login( - options: { - walletName?: string; - callbackUrl?: string; - token?: string; - } = {} - ): Promise<{ address: string; signature?: string }> { - if (!this.initialized) { - throw new Error('Passkey provider is not initialised, call init() first'); - } - const { token } = options; - await this.ensureConnected(); - if (!this.keyPair?.privateKey && !this.keyPair?.publicKey) { - throw new Error('Could not retrieve key pair.'); - } - this.account.address = this.keyPair.publicKey; - - if (token) { - const signedToken = await this.signMessageWithPrivateKey({ - address: this.account.address, - message: token, - privateKey: this.keyPair.privateKey - }); - - this.account.signature = signedToken.getSignature().toString('hex'); - } - - if (!this.keyPair.publicKey) { - throw new Error('Login cancelled'); - } - - this.destroyKeyPair(); - - return { address: this.account.address, signature: this.account.signature }; - } - - private destroyKeyPair() { - this.keyPair = undefined; - } - - private async signMessageWithPrivateKey({ - message, - address, - privateKey - }: SignMessageParams): Promise { - const signer = new UserSigner(UserSecretKey.fromString(privateKey)); - - const messageToSign = new SignableMessage({ - ...(address ? { address: new Address(address) } : {}), - message: Buffer.from(message) - }); - const serializedMessage = messageToSign.serializeForSigning(); - const signature = await signer.sign(serializedMessage); - messageToSign.applySignature(signature); - - return messageToSign; - } - - public setUserKeyPair(inputKeyMaterial: Uint8Array) { - const privateKey = new UserSecretKey(inputKeyMaterial); - const publicKey = privateKey.generatePublicKey().toAddress().bech32(); - if (this.account.address && publicKey !== this.account.address) { - throw new Error( - `Wrong address. Please use the passkey for ${this.account.address}` - ); - } - this.keyPair = { - privateKey: privateKey.hex(), - publicKey - }; - } - - public async createAccount(walletName: string, token: string) { - const challengeFromServer = window.crypto.randomUUID(); - const { extensionResults } = await client.register( - walletName, - challengeFromServer, - { - authenticatorType: 'extern' - } - ); - this.setUserKeyPair(extensionResults); - - return this.login({ walletName, token }); - } - - public async isExistingUser(email: string) { - return Boolean(window.localStorage.getItem(email)); - } - - async logout(): Promise { - if (!this.initialized) { - throw new Error('Passkey provider is not initialised, call init() first'); - } - try { - this.disconnect(); - } catch (error) { - console.warn('Passkey origin url is already cleared!', error); - } - - return true; - } - - private disconnect() { - this.account = { address: '' }; - } - - async getAddress(): Promise { - if (!this.initialized) { - throw new Error('Passkey provider is not initialised, call init() first'); - } - return this.account ? this.account.address : ''; - } - - isInitialized(): boolean { - return this.initialized; - } - - async isConnected(): Promise { - return Boolean(this.account.address); - } - - async signTransaction(transaction: Transaction): Promise { - await this.ensureConnected(); - - const signedTransactions = await this.signTransactions([transaction]); - - if (signedTransactions.length != 1) { - throw new ErrCannotSignSingleTransaction(); - } - this.destroyKeyPair(); - return signedTransactions[0]; - } - - private async ensureConnected() { - if (this.keyPair?.privateKey || this.keyPair?.publicKey) { - return; - } - - const challengeFromServer = window.crypto.randomUUID(); - let inputKeyMaterial: Uint8Array; - try { - const { extensionResults } = await client.authenticate( - [], - challengeFromServer, - { userVerification: 'required', authenticatorType: 'extern' } - ); - inputKeyMaterial = extensionResults; - } catch (error) { - throw new AuthenticatorNotSupported(); - } - this.setUserKeyPair(inputKeyMaterial); - } - - async signTransactions(transactions: Transaction[]): Promise { - await this.ensureConnected(); - - try { - const signer = new UserSigner( - UserSecretKey.fromString(this.keyPair!.privateKey) - ); - - for (const transaction of transactions) { - const signature = await signer.sign(transaction.serializeForSigning()); - transaction.applySignature(signature); - } - this.destroyKeyPair(); - return transactions; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } catch (error: any) { - this.destroyKeyPair(); - throw new Error(`Transaction canceled: ${error.message}.`); - } - } - - async signMessage(message: SignableMessage): Promise { - await this.ensureConnected(); - const signedMessage = await this.signMessageWithPrivateKey({ - message: message.message.toString(), - address: this.account.address, - privateKey: this.keyPair!.privateKey - }); - const signature = signedMessage.getSignature(); - - message.applySignature(signature); - - this.destroyKeyPair(); - return message; - } - - cancelAction() { - return true; - } -} diff --git a/src/providers/accountProvider.ts b/src/providers/accountProvider.ts index 460a52b18..983ff8c13 100644 --- a/src/providers/accountProvider.ts +++ b/src/providers/accountProvider.ts @@ -2,12 +2,10 @@ import { ExtensionProvider } from '@multiversx/sdk-extension-provider'; import { HWProvider } from '@multiversx/sdk-hw-provider'; import { MetamaskProvider } from '@multiversx/sdk-metamask-provider/out/metamaskProvider'; import { OperaProvider } from '@multiversx/sdk-opera-provider'; +import { PasskeyProvider } from '@multiversx/sdk-passkey-provider/out'; +import { IframeProvider } from '@multiversx/sdk-web-wallet-iframe-provider/out'; import { WalletProvider } from '@multiversx/sdk-web-wallet-provider'; -import { - CrossWindowProvider, - MetamaskProxyProvider -} from 'lib/sdkWebWalletCrossWindowProvider'; -import { PasskeyProvider } from 'passkeyProvider'; +import { CrossWindowProvider } from 'lib/sdkWebWalletCrossWindowProvider'; import { IDappProvider } from 'types'; import { WalletConnectV2Provider } from 'utils/walletconnect/__sdkWalletconnectProvider'; import { emptyProvider } from './utils'; @@ -19,7 +17,7 @@ export type ProvidersType = | MetamaskProvider | WalletProvider | CrossWindowProvider - | MetamaskProxyProvider + | IframeProvider | HWProvider | OperaProvider | WalletConnectV2Provider; diff --git a/src/providers/utils.ts b/src/providers/utils.ts index 8bc99698a..e89fca72e 100644 --- a/src/providers/utils.ts +++ b/src/providers/utils.ts @@ -4,13 +4,11 @@ import { HWProvider } from '@multiversx/sdk-hw-provider'; import { IHWWalletApp } from '@multiversx/sdk-hw-provider/out/interface'; import { MetamaskProvider } from '@multiversx/sdk-metamask-provider/out/metamaskProvider'; import { OperaProvider } from '@multiversx/sdk-opera-provider'; +import { PasskeyProvider } from '@multiversx/sdk-passkey-provider/out'; +import { IframeProvider } from '@multiversx/sdk-web-wallet-iframe-provider/out'; import { WalletProvider } from '@multiversx/sdk-web-wallet-provider'; import { LEDGER_CONTRACT_DATA_ENABLED_VALUE } from 'constants/index'; -import { - CrossWindowProvider, - MetamaskProxyProvider -} from 'lib/sdkWebWalletCrossWindowProvider'; -import { PasskeyProvider } from 'passkeyProvider'; +import { CrossWindowProvider } from 'lib/sdkWebWalletCrossWindowProvider'; import { IDappProvider } from 'types'; import { LoginMethodsEnum } from 'types/enums.types'; import { @@ -40,8 +38,8 @@ export const getProviderType = ( return LoginMethodsEnum.opera; case CrossWindowProvider: return LoginMethodsEnum.crossWindow; - case MetamaskProxyProvider: - return LoginMethodsEnum.metamaskProxy; + case IframeProvider: + return LoginMethodsEnum.iframe; case EmptyProvider: return LoginMethodsEnum.none; default: diff --git a/src/reduxStore/slices/loginInfoSlice.ts b/src/reduxStore/slices/loginInfoSlice.ts index bb0603697..ff41aa8c7 100644 --- a/src/reduxStore/slices/loginInfoSlice.ts +++ b/src/reduxStore/slices/loginInfoSlice.ts @@ -34,7 +34,7 @@ export interface LoginInfoStateType { passkeyLogin: LoginInfoType | null; operaLogin: LoginInfoType | null; crossWindowLogin: LoginInfoType | null; - metamaskProxyWindowLogin: LoginInfoType | null; + iframeWindowLogin: LoginInfoType | null; webviewLogin: LoginInfoType | null; isLoginSessionInvalid: boolean; logoutRoute?: string; @@ -51,7 +51,7 @@ const initialState: LoginInfoStateType = { passkeyLogin: null, operaLogin: null, crossWindowLogin: null, - metamaskProxyWindowLogin: null, + iframeWindowLogin: null, isLoginSessionInvalid: false, webviewLogin: null }; diff --git a/src/types/enums.types.ts b/src/types/enums.types.ts index 1fd2a94c8..cbdd1ed28 100644 --- a/src/types/enums.types.ts +++ b/src/types/enums.types.ts @@ -36,7 +36,7 @@ export enum LoginMethodsEnum { walletconnectv2 = 'walletconnectv2', wallet = 'wallet', crossWindow = 'crossWindow', - metamaskProxy = 'metamaskProxy', + iframe = 'iframe', extension = 'extension', passkey = 'passkey', metamask = 'metamask', diff --git a/src/wrappers/AppInitializer.tsx b/src/wrappers/AppInitializer.tsx index d77aabb80..ec68e0f9a 100644 --- a/src/wrappers/AppInitializer.tsx +++ b/src/wrappers/AppInitializer.tsx @@ -36,6 +36,7 @@ export const useAppInitializer = ({ environment, dappConfig }: UseAppInitializerPropsType) => { + console.log('------1'); const [initialized, setInitialized] = useState(false); const account = useGetAccountInfo(); const isLoginSessionInvalid = useSelector(isLoginSessionInvalidSelector); diff --git a/yarn.lock b/yarn.lock index 59ae7c370..bd91c23f3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2357,9 +2357,9 @@ protobufjs "7.2.4" "@multiversx/sdk-core@>= 12.18.0": - version "13.4.2" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-core/-/sdk-core-13.4.2.tgz#bfe524b9b18b631bef96acead7713d2d1ccab15c" - integrity sha512-+XdBSaX+iUMm9BRv86Tmzy16H3XS7TQ2/+HN12hCgP9TF003K8KABTCJnlyIrQ1oM5iI3ffbY+fEQpAwo+wQEQ== + version "13.5.0" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-core/-/sdk-core-13.5.0.tgz#e3d97fd92e3da534095ead2164a263e8d8a48482" + integrity sha512-J20WHxN7muUDrnGRbDhfgGJJEP1f27gdnSNx/7pa5urY/5z5Zh+a9XedUtJ/OXBcSuTp88ZelUpYFNEdenrJXA== dependencies: "@multiversx/sdk-transaction-decoder" "1.0.2" bech32 "1.1.4" @@ -2400,15 +2400,6 @@ "@metamask/providers" "16.0.0" "@multiversx/sdk-core" "12.18.0" -"@multiversx/sdk-metamask-proxy-provider@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-metamask-proxy-provider/-/sdk-metamask-proxy-provider-1.0.0.tgz#ea7d32ee43e756f73f2d661d7ce854b23c3b9e68" - integrity sha512-fdfUKfWLSHvdEPdvT/CZE56VbpreOgOYzn/QneuT/n1xMGuB++o3TFB4eGF06wEyDLmbtMMG4FEOvi9HFuFVbA== - dependencies: - "@types/jest" "^29.5.11" - "@types/qs" "6.9.10" - qs "6.11.2" - "@multiversx/sdk-native-auth-client@1.0.7": version "1.0.7" resolved "https://registry.yarnpkg.com/@multiversx/sdk-native-auth-client/-/sdk-native-auth-client-1.0.7.tgz#ae3c4afbd88349059c606e47c9515825ed4047ac" @@ -2421,6 +2412,13 @@ resolved "https://registry.yarnpkg.com/@multiversx/sdk-opera-provider/-/sdk-opera-provider-1.0.0-alpha.1.tgz#2beebd5423fdc2e667b33660f17cbff325449097" integrity sha512-5hrqn+kNpuy/S6eV5wh5mE4lvQo0PduZ7fLsh/2Srcaz3K5kM5lE1VyQmWk4DTxToZSldrGbgWz/olezoC6fPg== +"@multiversx/sdk-passkey-provider@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-passkey-provider/-/sdk-passkey-provider-1.0.0.tgz#f96d9956f3e9376eea86e8556219d4e88ff00bb9" + integrity sha512-lUY2ZSWNPN6X3RIMtSXjQFL5Owh+zxPZoiIQkkbBG+IUepk3MzPpASvgPfcEMSEM755Ud9hJb13Jr1HtCtmazg== + dependencies: + "@types/jest" "^29.5.11" + "@multiversx/sdk-transaction-decoder@1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@multiversx/sdk-transaction-decoder/-/sdk-transaction-decoder-1.0.2.tgz#83ded4f6d4b877b4421234856eb19709be2af31b" @@ -2464,6 +2462,15 @@ "@types/qs" "6.9.10" qs "6.11.2" +"@multiversx/sdk-web-wallet-iframe-provider@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-web-wallet-iframe-provider/-/sdk-web-wallet-iframe-provider-1.0.0.tgz#4ec085637ead9e5f2e9c74bb990ee525084b3d37" + integrity sha512-03yyNkgPjzxYIT9PpfEeaJdGlnGO+B/ZC0S9d1rqbxR2Z6qw8LfeP/qAMqdMgg5Z0bxxD2UE94uMyq+8Es55kA== + dependencies: + "@types/jest" "^29.5.11" + "@types/qs" "6.9.10" + qs "6.11.2" + "@multiversx/sdk-web-wallet-provider@3.2.1": version "3.2.1" resolved "https://registry.yarnpkg.com/@multiversx/sdk-web-wallet-provider/-/sdk-web-wallet-provider-3.2.1.tgz#94ba12140f4f9f35f30b8e13186baa78db4ddaae" @@ -2502,11 +2509,16 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.0.tgz#085fd70f6d7d9d109671090ccae1d3bec62554a1" integrity sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg== -"@noble/hashes@1.4.0", "@noble/hashes@^1.3.1", "@noble/hashes@~1.4.0": +"@noble/hashes@1.4.0", "@noble/hashes@~1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== +"@noble/hashes@^1.3.1": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.5.0.tgz#abadc5ca20332db2b1b2aa3e496e9af1213570b0" + integrity sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA== + "@node-rs/xxhash-android-arm-eabi@1.7.3": version "1.7.3" resolved "https://registry.yarnpkg.com/@node-rs/xxhash-android-arm-eabi/-/xxhash-android-arm-eabi-1.7.3.tgz#271a935e7f373a07927fd02311e81d0ffd7a95d5" @@ -4839,9 +4851,9 @@ form-data "^4.0.0" "@types/node@*", "@types/node@>=13.7.0": - version "22.5.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.1.tgz#de01dce265f6b99ed32b295962045d10b5b99560" - integrity sha512-KkHsxej0j9IW1KKOOAA/XBA0z08UFSrRQHErzEfA3Vgq57eXIMYboIlHJuYIfd+lwCQjtKqUu3UnmKbtUc9yRw== + version "22.5.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.2.tgz#e42344429702e69e28c839a7e16a8262a8086793" + integrity sha512-acJsPTEqYqulZS/Yp/S3GgeE6GZ0qYODUR8aVr/DkhHQ8l9nd4j5x1/ZJy9/gHrRlFMqkO6i0I3E27Alu4jjPg== dependencies: undici-types "~6.19.2" @@ -6178,9 +6190,9 @@ axios@^0.21.1: follow-redirects "^1.14.0" axios@^1.6.5: - version "1.7.6" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.6.tgz#34f338182f6802fd3824a6511d6ddf99dd5ae0b5" - integrity sha512-Ekur6XDwhnJ5RgOCaxFnXyqlPALI3rVeukZMwOdfghW7/wGz784BYKiQq+QD8NPcr91KRo30KfHOchyijwWw7g== + version "1.7.7" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" + integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== dependencies: follow-redirects "^1.15.6" form-data "^4.0.0" @@ -8834,9 +8846,9 @@ eslint-import-resolver-typescript@2.4.0: tsconfig-paths "^3.9.0" eslint-module-utils@^2.7.3: - version "2.8.2" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.2.tgz#2ecad69d71e1fa81f17f7f24d5d3e46b168de663" - integrity sha512-3XnC5fDyc8M4J2E8pt8pmSVRX2M+5yWMCfI/kDZwauQeFgzQOuhcRBFKjTeJagqgk4sFKxe1mvNVnaWwImx/Tg== + version "2.9.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.9.0.tgz#95d4ac038a68cd3f63482659dffe0883900eb342" + integrity sha512-McVbYmwA3NEKwRQY5g4aWMdcZE5xZxV8i8l7CqJSrameuGSQJtSWaL/LxTEzSKKaCcOhlpDR8XEfYXWPrdo/ZQ== dependencies: debug "^3.2.7" @@ -13050,9 +13062,9 @@ nanomatch@^1.2.9: to-regex "^3.0.1" napi-wasm@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/napi-wasm/-/napi-wasm-1.1.0.tgz#bbe617823765ae9c1bc12ff5942370eae7b2ba4e" - integrity sha512-lHwIAJbmLSjF9VDRm9GoVOy9AGp3aIvkjv+Kvz9h16QR3uSVYH78PNQUnT2U4X53mhlnV2M7wrhibQ3GHicDmg== + version "1.1.3" + resolved "https://registry.yarnpkg.com/napi-wasm/-/napi-wasm-1.1.3.tgz#7bb95c88e6561f84880bb67195437b1cfbe99224" + integrity sha512-h/4nMGsHjZDCYmQVNODIrYACVJ+I9KItbG+0si6W/jSjdA9JbWDoU4LLeMXVcEQGHjttI2tuXqDrbGF7qkUHHg== natural-compare@^1.4.0: version "1.4.0" @@ -13867,9 +13879,9 @@ picocolors@^0.2.1: integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== picocolors@^1.0.0, picocolors@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" - integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== + version "1.1.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" + integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.0, picomatch@^2.3.1: version "2.3.1" @@ -14145,9 +14157,9 @@ postcss@^7.0.14, postcss@^7.0.26, postcss@^7.0.32, postcss@^7.0.36, postcss@^7.0 source-map "^0.6.1" postcss@^8.2.15: - version "8.4.41" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.41.tgz#d6104d3ba272d882fe18fc07d15dc2da62fa2681" - integrity sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ== + version "8.4.44" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.44.tgz#d56834ef6508610ba224bb22b2457b2169ed0480" + integrity sha512-Aweb9unOEpQ3ezu4Q00DPvvM2ZTUitJdNKeP/+uQgr1IBIqu574IaZoURId7BKtWMREwzKa9OgzPzezWGPWFQw== dependencies: nanoid "^3.3.7" picocolors "^1.0.1" From b1fe385de2409db9d65adbe1de8024766ddda373 Mon Sep 17 00:00:00 2001 From: Andrei Date: Tue, 3 Sep 2024 10:27:50 +0300 Subject: [PATCH 03/12] fixed version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5a72658c8..e42b14437 100644 --- a/package.json +++ b/package.json @@ -167,7 +167,7 @@ "@multiversx/sdk-wallet": "4.2.0", "@multiversx/sdk-wallet-connect-provider": "4.1.3", "@multiversx/sdk-web-wallet-cross-window-provider": "1.0.0", - "@multiversx/sdk-web-wallet-iframe-provider": "^1.0.0", + "@multiversx/sdk-web-wallet-iframe-provider": "1.0.0", "@multiversx/sdk-web-wallet-provider": "3.2.1", "@multiversx/sdk-webview-provider": "1.0.0", "@reduxjs/toolkit": "1.8.2", From ad6d0ba7741e24532ae5f6afe6721ffdb9736894 Mon Sep 17 00:00:00 2001 From: Andrei Date: Tue, 3 Sep 2024 10:28:12 +0300 Subject: [PATCH 04/12] remove console.log --- src/wrappers/AppInitializer.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/wrappers/AppInitializer.tsx b/src/wrappers/AppInitializer.tsx index ec68e0f9a..d77aabb80 100644 --- a/src/wrappers/AppInitializer.tsx +++ b/src/wrappers/AppInitializer.tsx @@ -36,7 +36,6 @@ export const useAppInitializer = ({ environment, dappConfig }: UseAppInitializerPropsType) => { - console.log('------1'); const [initialized, setInitialized] = useState(false); const account = useGetAccountInfo(); const isLoginSessionInvalid = useSelector(isLoginSessionInvalidSelector); From 4a093a00bc9fb0a0cd96399ee48f6594870627e5 Mon Sep 17 00:00:00 2001 From: Andrei Date: Tue, 3 Sep 2024 14:28:31 +0300 Subject: [PATCH 05/12] fixes --- package.json | 2 +- src/UI/iframe/IframeLoginButton/IframeButton.tsx | 7 +++++-- src/hooks/login/useIframeLogin.ts | 8 +++++--- yarn.lock | 8 ++++---- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index e42b14437..6f36a9b10 100644 --- a/package.json +++ b/package.json @@ -167,7 +167,7 @@ "@multiversx/sdk-wallet": "4.2.0", "@multiversx/sdk-wallet-connect-provider": "4.1.3", "@multiversx/sdk-web-wallet-cross-window-provider": "1.0.0", - "@multiversx/sdk-web-wallet-iframe-provider": "1.0.0", + "@multiversx/sdk-web-wallet-iframe-provider": "^1.0.2", "@multiversx/sdk-web-wallet-provider": "3.2.1", "@multiversx/sdk-webview-provider": "1.0.0", "@reduxjs/toolkit": "1.8.2", diff --git a/src/UI/iframe/IframeLoginButton/IframeButton.tsx b/src/UI/iframe/IframeLoginButton/IframeButton.tsx index ccf2f6835..f4e809b73 100644 --- a/src/UI/iframe/IframeLoginButton/IframeButton.tsx +++ b/src/UI/iframe/IframeLoginButton/IframeButton.tsx @@ -1,4 +1,5 @@ import React, { ReactNode } from 'react'; +import { IframeLoginTypes } from '@multiversx/sdk-web-wallet-iframe-provider/out/constants'; import { withStyles, WithStylesImportType } from 'hocs/withStyles'; import { useIframeLogin } from 'hooks/login/useIframeLogin'; import { getIsNativeAuthSingingForbidden } from 'services/nativeAuth/helpers'; @@ -13,6 +14,7 @@ export interface IframeLoginButtonPropsType buttonClassName?: string; loginButtonText?: string; disabled?: boolean; + loginType?: IframeLoginTypes; } const IframeLoginButtonComponent: ( @@ -26,7 +28,8 @@ const IframeLoginButtonComponent: ( nativeAuth, loginButtonText = 'Metamask Proxy', onLoginRedirect, - disabled + disabled, + loginType = IframeLoginTypes.metamask }) => { const [onInitiateLogin] = useIframeLogin({ callbackRoute, @@ -37,7 +40,7 @@ const IframeLoginButtonComponent: ( const disabledConnectButton = getIsNativeAuthSingingForbidden(token); const handleLogin = () => { - onInitiateLogin(); + onInitiateLogin(loginType); }; return ( diff --git a/src/hooks/login/useIframeLogin.ts b/src/hooks/login/useIframeLogin.ts index 4467ea55b..ca806f20c 100644 --- a/src/hooks/login/useIframeLogin.ts +++ b/src/hooks/login/useIframeLogin.ts @@ -1,5 +1,6 @@ import { useState } from 'react'; import { IframeProvider } from '@multiversx/sdk-web-wallet-iframe-provider/out'; +import { IframeLoginTypes } from '@multiversx/sdk-web-wallet-iframe-provider/out/constants'; import { processModifiedAccount } from 'components/ProviderInitializer/helpers/processModifiedAccount'; import { SECOND_LOGIN_ATTEMPT_ERROR } from 'constants/errorsMessages'; import { setAccountProvider } from 'providers/accountProvider'; @@ -8,7 +9,6 @@ import { useDispatch, useSelector } from 'reduxStore/DappProviderContext'; import { networkSelector } from 'reduxStore/selectors/networkConfigSelectors'; import { setAccount } from 'reduxStore/slices'; import { - InitiateLoginFunctionType, LoginHookGenericStateType, LoginMethodsEnum, OnProviderLoginType @@ -20,7 +20,7 @@ import { clearInitiatedLogins } from './helpers'; import { useLoginService } from './useLoginService'; export type UseIframeLoginReturnType = [ - InitiateLoginFunctionType, + (loginType: IframeLoginTypes) => void, LoginHookGenericStateType ]; @@ -42,7 +42,7 @@ export const useIframeLogin = ({ const dispatch = useDispatch(); const isLoggedIn = getIsLoggedIn(); - async function initiateLogin() { + async function initiateLogin(loginType = IframeLoginTypes.metamask) { if (isLoggedIn) { throw new Error(SECOND_LOGIN_ATTEMPT_ERROR); } @@ -60,6 +60,8 @@ export const useIframeLogin = ({ setError('Iframe snap wallet URL is not set'); return; } + + provider.setLoginType(loginType); provider.setWalletUrl(walletUrl); const isSuccessfullyInitialized: boolean = await provider.init(); diff --git a/yarn.lock b/yarn.lock index bd91c23f3..38b8271b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2462,10 +2462,10 @@ "@types/qs" "6.9.10" qs "6.11.2" -"@multiversx/sdk-web-wallet-iframe-provider@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-web-wallet-iframe-provider/-/sdk-web-wallet-iframe-provider-1.0.0.tgz#4ec085637ead9e5f2e9c74bb990ee525084b3d37" - integrity sha512-03yyNkgPjzxYIT9PpfEeaJdGlnGO+B/ZC0S9d1rqbxR2Z6qw8LfeP/qAMqdMgg5Z0bxxD2UE94uMyq+8Es55kA== +"@multiversx/sdk-web-wallet-iframe-provider@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-web-wallet-iframe-provider/-/sdk-web-wallet-iframe-provider-1.0.2.tgz#968a3038b778d85e86724e2759cb1646672c3915" + integrity sha512-2WpmhjfOaZySf1NOFV2L5yjfRiukaOLU3+zkmwg106oMNJq7+mP7ZM7rMe7y95xYPFgMW+1Ivtdc1DTKycIn+g== dependencies: "@types/jest" "^29.5.11" "@types/qs" "6.9.10" From 53847948c5d65b8b56749f108b403498b0e22c6b Mon Sep 17 00:00:00 2001 From: Andrei Date: Tue, 3 Sep 2024 14:30:18 +0300 Subject: [PATCH 06/12] fixed version --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 6f36a9b10..4311578d3 100644 --- a/package.json +++ b/package.json @@ -163,11 +163,11 @@ "@multiversx/sdk-metamask-provider": "0.0.5", "@multiversx/sdk-native-auth-client": "1.0.7", "@multiversx/sdk-opera-provider": "1.0.0-alpha.1", - "@multiversx/sdk-passkey-provider": "^1.0.0", + "@multiversx/sdk-passkey-provider": "1.0.0", "@multiversx/sdk-wallet": "4.2.0", "@multiversx/sdk-wallet-connect-provider": "4.1.3", "@multiversx/sdk-web-wallet-cross-window-provider": "1.0.0", - "@multiversx/sdk-web-wallet-iframe-provider": "^1.0.2", + "@multiversx/sdk-web-wallet-iframe-provider": "1.0.2", "@multiversx/sdk-web-wallet-provider": "3.2.1", "@multiversx/sdk-webview-provider": "1.0.0", "@reduxjs/toolkit": "1.8.2", From 5ebccb85a09c9634c12b70818e4a0cc96539bc3f Mon Sep 17 00:00:00 2001 From: Andrei Date: Tue, 3 Sep 2024 14:34:15 +0300 Subject: [PATCH 07/12] regenerate yarn lock --- yarn.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yarn.lock b/yarn.lock index 38b8271b4..8b0ff99c3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2412,7 +2412,7 @@ resolved "https://registry.yarnpkg.com/@multiversx/sdk-opera-provider/-/sdk-opera-provider-1.0.0-alpha.1.tgz#2beebd5423fdc2e667b33660f17cbff325449097" integrity sha512-5hrqn+kNpuy/S6eV5wh5mE4lvQo0PduZ7fLsh/2Srcaz3K5kM5lE1VyQmWk4DTxToZSldrGbgWz/olezoC6fPg== -"@multiversx/sdk-passkey-provider@^1.0.0": +"@multiversx/sdk-passkey-provider@1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@multiversx/sdk-passkey-provider/-/sdk-passkey-provider-1.0.0.tgz#f96d9956f3e9376eea86e8556219d4e88ff00bb9" integrity sha512-lUY2ZSWNPN6X3RIMtSXjQFL5Owh+zxPZoiIQkkbBG+IUepk3MzPpASvgPfcEMSEM755Ud9hJb13Jr1HtCtmazg== @@ -2462,7 +2462,7 @@ "@types/qs" "6.9.10" qs "6.11.2" -"@multiversx/sdk-web-wallet-iframe-provider@^1.0.2": +"@multiversx/sdk-web-wallet-iframe-provider@1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@multiversx/sdk-web-wallet-iframe-provider/-/sdk-web-wallet-iframe-provider-1.0.2.tgz#968a3038b778d85e86724e2759cb1646672c3915" integrity sha512-2WpmhjfOaZySf1NOFV2L5yjfRiukaOLU3+zkmwg106oMNJq7+mP7ZM7rMe7y95xYPFgMW+1Ivtdc1DTKycIn+g== From b38f5f525bde8b9f9c8bb9d47c80a298aa2a1b2f Mon Sep 17 00:00:00 2001 From: Andrei Date: Thu, 5 Sep 2024 10:40:30 +0300 Subject: [PATCH 08/12] add create wallet to passkey provider --- package.json | 4 +- src/hooks/login/usePasskeyLogin.ts | 8 ++- yarn.lock | 78 +++++++++++++++--------------- 3 files changed, 47 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index 175b1b2d3..0551c2198 100644 --- a/package.json +++ b/package.json @@ -163,11 +163,11 @@ "@multiversx/sdk-metamask-provider": "0.0.5", "@multiversx/sdk-native-auth-client": "1.0.7", "@multiversx/sdk-opera-provider": "1.0.0-alpha.1", - "@multiversx/sdk-passkey-provider": "1.0.0", + "@multiversx/sdk-passkey-provider": "1.0.1", "@multiversx/sdk-wallet": "4.2.0", "@multiversx/sdk-wallet-connect-provider": "4.1.3", "@multiversx/sdk-web-wallet-cross-window-provider": "1.0.0", - "@multiversx/sdk-web-wallet-iframe-provider": "1.0.2", + "@multiversx/sdk-web-wallet-iframe-provider": "1.0.3", "@multiversx/sdk-web-wallet-provider": "3.2.1", "@multiversx/sdk-webview-provider": "1.0.0", "@reduxjs/toolkit": "1.8.2", diff --git a/src/hooks/login/usePasskeyLogin.ts b/src/hooks/login/usePasskeyLogin.ts index b6c3f0003..3ce23509b 100644 --- a/src/hooks/login/usePasskeyLogin.ts +++ b/src/hooks/login/usePasskeyLogin.ts @@ -38,7 +38,7 @@ export const usePasskeyLogin = ({ const dispatch = useDispatch(); const isLoggedIn = getIsLoggedIn(); - async function initiateLogin() { + async function initiateLogin(newWalletName?: string) { if (isLoggedIn) { throw new Error(SECOND_LOGIN_ATTEMPT_ERROR); } @@ -82,7 +82,11 @@ export const usePasskeyLogin = ({ ...(token && { token }) }; - await provider.login(providerLoginData); + if (newWalletName) { + await provider.createAccount({ walletName: newWalletName, token }); + } else { + await provider.login(providerLoginData); + } setAccountProvider(provider); diff --git a/yarn.lock b/yarn.lock index 8b0ff99c3..2c9fdd19a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2412,10 +2412,10 @@ resolved "https://registry.yarnpkg.com/@multiversx/sdk-opera-provider/-/sdk-opera-provider-1.0.0-alpha.1.tgz#2beebd5423fdc2e667b33660f17cbff325449097" integrity sha512-5hrqn+kNpuy/S6eV5wh5mE4lvQo0PduZ7fLsh/2Srcaz3K5kM5lE1VyQmWk4DTxToZSldrGbgWz/olezoC6fPg== -"@multiversx/sdk-passkey-provider@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-passkey-provider/-/sdk-passkey-provider-1.0.0.tgz#f96d9956f3e9376eea86e8556219d4e88ff00bb9" - integrity sha512-lUY2ZSWNPN6X3RIMtSXjQFL5Owh+zxPZoiIQkkbBG+IUepk3MzPpASvgPfcEMSEM755Ud9hJb13Jr1HtCtmazg== +"@multiversx/sdk-passkey-provider@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-passkey-provider/-/sdk-passkey-provider-1.0.1.tgz#311e4cd4871ac7b8cb5ec1aa4fdac33eec806a61" + integrity sha512-FSGM8tVq+git6WFHJm6AHeBqBLaEeV6Gb9u0Nrz0HyBSKZcHSuXLaXjpptpckMuQRZp9sKDHxKrQ0qjbacJZPA== dependencies: "@types/jest" "^29.5.11" @@ -2462,10 +2462,10 @@ "@types/qs" "6.9.10" qs "6.11.2" -"@multiversx/sdk-web-wallet-iframe-provider@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-web-wallet-iframe-provider/-/sdk-web-wallet-iframe-provider-1.0.2.tgz#968a3038b778d85e86724e2759cb1646672c3915" - integrity sha512-2WpmhjfOaZySf1NOFV2L5yjfRiukaOLU3+zkmwg106oMNJq7+mP7ZM7rMe7y95xYPFgMW+1Ivtdc1DTKycIn+g== +"@multiversx/sdk-web-wallet-iframe-provider@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-web-wallet-iframe-provider/-/sdk-web-wallet-iframe-provider-1.0.3.tgz#fb34a3deef6ee28fd9d7d6da866a0e635b934506" + integrity sha512-viKc7nmy66W+kjX6JIPm/adiwieX5K82Cuy9JtFS1xTx/Q7uZJOxktqC2+MIUPKudiYKWY1N07WaM5mzTIu5gQ== dependencies: "@types/jest" "^29.5.11" "@types/qs" "6.9.10" @@ -3000,9 +3000,9 @@ integrity sha512-gTL8H5USTAKOyVA4xczzDJnC3HMssdFa3tRlwBicXynx9XfiXwneHnYQogwSKpdCkjXISrEKSTtX62rLpNEVQg== "@scure/base@^1.1.3", "@scure/base@~1.1.6": - version "1.1.7" - resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.7.tgz#fe973311a5c6267846aa131bc72e96c5d40d2b30" - integrity sha512-PPNYBslrLNNUQ/Yad37MHYsNQtK67EhWb6WtSvNLLPo7SdVZgkUjD6Dg+5On7zNwmskf8OX7I7Nx5oN+MIWE0g== + version "1.1.8" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.8.tgz#8f23646c352f020c83bca750a82789e246d42b50" + integrity sha512-6CyAclxj3Nb0XT7GHK6K4zK6k2xJm6E4Ft0Ohjt4WgegiFUHEtFb2CGzmPmGBwoIhrLsqNLYfLr04Y1GePrzZg== "@scure/bip32@1.4.0": version "1.4.0" @@ -4851,9 +4851,9 @@ form-data "^4.0.0" "@types/node@*", "@types/node@>=13.7.0": - version "22.5.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.2.tgz#e42344429702e69e28c839a7e16a8262a8086793" - integrity sha512-acJsPTEqYqulZS/Yp/S3GgeE6GZ0qYODUR8aVr/DkhHQ8l9nd4j5x1/ZJy9/gHrRlFMqkO6i0I3E27Alu4jjPg== + version "22.5.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.3.tgz#91a374e42c6e7ccb5893a87f1775f36ce1671d65" + integrity sha512-njripolh85IA9SQGTAqbmnNZTdxv7X/4OYGPz8tgy5JDr8MP+uDBa921GpYEoDDnwm0Hmn5ZPeJgiiSTPoOzkQ== dependencies: undici-types "~6.19.2" @@ -4863,9 +4863,9 @@ integrity sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ== "@types/node@^14.0.10 || ^16.0.0", "@types/node@^14.14.20 || ^16.0.0": - version "16.18.106" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.106.tgz#62228200da6d98365d2de5601f7230cdf041f0e2" - integrity sha512-YTgQUcpdXRc7iiEMutkkXl9WUx5lGUCVYvnfRg9CV+IA4l9epctEhCTbaw4KgzXaKYv8emvFJkEM65+MkNUhsQ== + version "16.18.107" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.107.tgz#9185eaebaf7d002a67976d61ae8a9a808fc84829" + integrity sha512-VSha8UIBpCpETub8FZ1nXkODXm+k+YRwpuVQsF3zOuD6QyPQeuIdPRm6IBVa2E5en58CUFJfaw6GmYHP2q/vkQ== "@types/normalize-package-data@^2.4.0": version "2.4.4" @@ -9559,9 +9559,9 @@ focus-lock@^0.8.0: tslib "^1.9.3" follow-redirects@^1.14.0, follow-redirects@^1.15.4, follow-redirects@^1.15.6: - version "1.15.6" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" - integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== + version "1.15.8" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.8.tgz#ae67b97ae32e0a7b36066a5448938374ec18d13d" + integrity sha512-xgrmBhBToVKay1q2Tao5LI26B83UhrB/vM1avwVSDzt8rx3rO6AizBAaF46EgksTVr+rFTQaqZZ9MVBfUe4nig== for-each@^0.3.3: version "0.3.3" @@ -9998,7 +9998,7 @@ grapheme-splitter@^1.0.4: resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.9.0.tgz#1c310e63f16a49ce1fbb230bd0a000e99f6f115f" integrity sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw== -h3@^1.10.2, h3@^1.11.1: +h3@^1.10.2, h3@^1.12.0: version "1.12.0" resolved "https://registry.yarnpkg.com/h3/-/h3-1.12.0.tgz#9d7f05f08a997d263e484b02436cb027df3026d8" integrity sha512-Zi/CcNeWBXDrFNlV0hUBJQR9F7a96RjMeAZweW/ZWkR9fuXrMcvKnSA63f/zZ9l0GgQOZDVHGvXivNN9PWOwhA== @@ -12530,7 +12530,7 @@ lower-case@^2.0.2: dependencies: tslib "^2.0.3" -lru-cache@^10.2.0: +lru-cache@^10.4.3: version "10.4.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== @@ -13116,7 +13116,7 @@ node-dir@^0.1.10: dependencies: minimatch "^3.0.2" -node-fetch-native@^1.6.2, node-fetch-native@^1.6.3, node-fetch-native@^1.6.4: +node-fetch-native@^1.6.3, node-fetch-native@^1.6.4: version "1.6.4" resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.4.tgz#679fc8fd8111266d47d7e72c379f1bed9acff06e" integrity sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ== @@ -13436,7 +13436,7 @@ objectorarray@^1.0.5: resolved "https://registry.yarnpkg.com/objectorarray/-/objectorarray-1.0.5.tgz#2c05248bbefabd8f43ad13b41085951aac5e68a5" integrity sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg== -ofetch@^1.3.3: +ofetch@^1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/ofetch/-/ofetch-1.3.4.tgz#7ea65ced3c592ec2b9906975ae3fe1d26a56f635" integrity sha512-KLIET85ik3vhEfS+3fDlc/BAZiAp+43QEC/yCo5zkNoY2YaKvNkOaFr/6wCFgFH1kuYQM5pMNi0Tg8koiIemtw== @@ -14157,9 +14157,9 @@ postcss@^7.0.14, postcss@^7.0.26, postcss@^7.0.32, postcss@^7.0.36, postcss@^7.0 source-map "^0.6.1" postcss@^8.2.15: - version "8.4.44" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.44.tgz#d56834ef6508610ba224bb22b2457b2169ed0480" - integrity sha512-Aweb9unOEpQ3ezu4Q00DPvvM2ZTUitJdNKeP/+uQgr1IBIqu574IaZoURId7BKtWMREwzKa9OgzPzezWGPWFQw== + version "8.4.45" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.45.tgz#538d13d89a16ef71edbf75d895284ae06b79e603" + integrity sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q== dependencies: nanoid "^3.3.7" picocolors "^1.0.1" @@ -15212,9 +15212,9 @@ sass@1.56.1: source-map-js ">=0.6.2 <2.0.0" sass@^1.49.0: - version "1.77.8" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.77.8.tgz#9f18b449ea401759ef7ec1752a16373e296b52bd" - integrity sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ== + version "1.78.0" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.78.0.tgz#cef369b2f9dc21ea1d2cf22c979f52365da60841" + integrity sha512-AaIqGSrjo5lA2Yg7RvFZrlXDBCp3nV4XP73GrLGvdRWWwk+8H3l0SDvq/5bA4eF+0RFPLuWUk3E+P1U/YqnpsQ== dependencies: chokidar ">=3.0.0 <4.0.0" immutable "^4.0.0" @@ -16569,7 +16569,7 @@ typescript@4.7.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.3.tgz#8364b502d5257b540f9de4c40be84c98e23a129d" integrity sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA== -ufo@^1.4.0, ufo@^1.5.3: +ufo@^1.4.0, ufo@^1.5.3, ufo@^1.5.4: version "1.5.4" resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.5.4.tgz#16d6949674ca0c9e0fbbae1fa20a71d7b1ded754" integrity sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ== @@ -16790,20 +16790,20 @@ unset-value@^1.0.0: isobject "^3.0.0" unstorage@^1.9.0: - version "1.10.2" - resolved "https://registry.yarnpkg.com/unstorage/-/unstorage-1.10.2.tgz#fb7590ada8b30e83be9318f85100158b02a76dae" - integrity sha512-cULBcwDqrS8UhlIysUJs2Dk0Mmt8h7B0E6mtR+relW9nZvsf/u4SkAYyNliPiPW7XtFNb5u3IUMkxGxFTTRTgQ== + version "1.11.0" + resolved "https://registry.yarnpkg.com/unstorage/-/unstorage-1.11.0.tgz#4d5b48aef4180131669ac8cf95a26a33fd7051d0" + integrity sha512-d7ggFP/5h0AUIMbeQit8M3VuyIBFVMk2Ew5NOaCrKEsNzJRHym+0EhGD074ItIPuAEq8Q1EX3+NrizlJH700+g== dependencies: anymatch "^3.1.3" chokidar "^3.6.0" destr "^2.0.3" - h3 "^1.11.1" + h3 "^1.12.0" listhen "^1.7.2" - lru-cache "^10.2.0" + lru-cache "^10.4.3" mri "^1.2.0" - node-fetch-native "^1.6.2" - ofetch "^1.3.3" - ufo "^1.4.0" + node-fetch-native "^1.6.4" + ofetch "^1.3.4" + ufo "^1.5.4" untildify@^2.0.0: version "2.1.0" From d5401aa04f5ec86cea638ef0ebf8ffc9cc9b131d Mon Sep 17 00:00:00 2001 From: Andrei Date: Thu, 5 Sep 2024 10:42:17 +0300 Subject: [PATCH 09/12] changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f2f0022d..6750234f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- [Added create wallet feature for passkey provider](https://github.com/multiversx/mx-sdk-dapp/pull/1254) + ## [[v2.40.0]](https://github.com/multiversx/mx-sdk-dapp/pull/1253)] - 2024-09-03 - [Fixed websocket connection is not closed on logout](https://github.com/multiversx/mx-sdk-dapp/pull/1250) - [Upgrade sdk-dapp-utils, webview-provider, metamask-proxy-provider and cross-window-provider packages](https://github.com/multiversx/mx-sdk-dapp/pull/1247) From bcfeafbad5df64fdfcf9ecf8dd16759e57fead8d Mon Sep 17 00:00:00 2001 From: Andrei Date: Thu, 5 Sep 2024 10:43:04 +0300 Subject: [PATCH 10/12] 2.40.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0551c2198..311356594 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@multiversx/sdk-dapp", - "version": "2.40.0", + "version": "2.40.1", "description": "A library to hold the main logic for a dapp on the MultiversX blockchain", "author": "MultiversX", "license": "GPL-3.0-or-later", From e0f1d8bb49db94710d422dafecaf85aa0c46717e Mon Sep 17 00:00:00 2001 From: Andrei Date: Thu, 5 Sep 2024 10:51:00 +0300 Subject: [PATCH 11/12] changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6750234f6..18085418d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] + +## [[v2.40.1]](https://github.com/multiversx/mx-sdk-dapp/pull/1255)] - 2024-09-05 - [Added create wallet feature for passkey provider](https://github.com/multiversx/mx-sdk-dapp/pull/1254) ## [[v2.40.0]](https://github.com/multiversx/mx-sdk-dapp/pull/1253)] - 2024-09-03 From 380f31325b63c6c5df3b2bdf5e5a6281bbf7381c Mon Sep 17 00:00:00 2001 From: Andrei Date: Thu, 5 Sep 2024 11:23:17 +0300 Subject: [PATCH 12/12] upgrade passkey provider --- package.json | 2 +- yarn.lock | 38 +++++++++++++++++++------------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index 311356594..ad73bd659 100644 --- a/package.json +++ b/package.json @@ -163,7 +163,7 @@ "@multiversx/sdk-metamask-provider": "0.0.5", "@multiversx/sdk-native-auth-client": "1.0.7", "@multiversx/sdk-opera-provider": "1.0.0-alpha.1", - "@multiversx/sdk-passkey-provider": "1.0.1", + "@multiversx/sdk-passkey-provider": "1.0.2", "@multiversx/sdk-wallet": "4.2.0", "@multiversx/sdk-wallet-connect-provider": "4.1.3", "@multiversx/sdk-web-wallet-cross-window-provider": "1.0.0", diff --git a/yarn.lock b/yarn.lock index 2c9fdd19a..0a5bbea64 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2412,10 +2412,10 @@ resolved "https://registry.yarnpkg.com/@multiversx/sdk-opera-provider/-/sdk-opera-provider-1.0.0-alpha.1.tgz#2beebd5423fdc2e667b33660f17cbff325449097" integrity sha512-5hrqn+kNpuy/S6eV5wh5mE4lvQo0PduZ7fLsh/2Srcaz3K5kM5lE1VyQmWk4DTxToZSldrGbgWz/olezoC6fPg== -"@multiversx/sdk-passkey-provider@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-passkey-provider/-/sdk-passkey-provider-1.0.1.tgz#311e4cd4871ac7b8cb5ec1aa4fdac33eec806a61" - integrity sha512-FSGM8tVq+git6WFHJm6AHeBqBLaEeV6Gb9u0Nrz0HyBSKZcHSuXLaXjpptpckMuQRZp9sKDHxKrQ0qjbacJZPA== +"@multiversx/sdk-passkey-provider@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-passkey-provider/-/sdk-passkey-provider-1.0.2.tgz#aa67e8c29654f9e4dd6a705935f8d201f1dc9ad1" + integrity sha512-+gngXlSsBwK/i7YJPjWtL0PfPW9PcgxV2EcBMydcVnvSji0dsGb9QvcZr/PfVLS8w/ezriH1uoPlmj85SXrI8A== dependencies: "@types/jest" "^29.5.11" @@ -4851,9 +4851,9 @@ form-data "^4.0.0" "@types/node@*", "@types/node@>=13.7.0": - version "22.5.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.3.tgz#91a374e42c6e7ccb5893a87f1775f36ce1671d65" - integrity sha512-njripolh85IA9SQGTAqbmnNZTdxv7X/4OYGPz8tgy5JDr8MP+uDBa921GpYEoDDnwm0Hmn5ZPeJgiiSTPoOzkQ== + version "22.5.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.4.tgz#83f7d1f65bc2ed223bdbf57c7884f1d5a4fa84e8" + integrity sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg== dependencies: undici-types "~6.19.2" @@ -4863,9 +4863,9 @@ integrity sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ== "@types/node@^14.0.10 || ^16.0.0", "@types/node@^14.14.20 || ^16.0.0": - version "16.18.107" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.107.tgz#9185eaebaf7d002a67976d61ae8a9a808fc84829" - integrity sha512-VSha8UIBpCpETub8FZ1nXkODXm+k+YRwpuVQsF3zOuD6QyPQeuIdPRm6IBVa2E5en58CUFJfaw6GmYHP2q/vkQ== + version "16.18.108" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.108.tgz#b794e2b2a85b4c12935ea7d0f18641be68b352f9" + integrity sha512-fj42LD82fSv6yN9C6Q4dzS+hujHj+pTv0IpRR3kI20fnYeS0ytBpjFO9OjmDowSPPt4lNKN46JLaKbCyP+BW2A== "@types/normalize-package-data@^2.4.0": version "2.4.4" @@ -6912,9 +6912,9 @@ can-bind-to-host@^1.1.1: integrity sha512-CqsgmaqiyFRNtP17Ihqa/uHbZxRirntNVNl/kJz31DLKuNRfzvzionkLoUSkElQ6Cz+cpXKA3mhHq4tjbieujA== caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001646: - version "1.0.30001655" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001655.tgz#0ce881f5a19a2dcfda2ecd927df4d5c1684b982f" - integrity sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg== + version "1.0.30001657" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001657.tgz#29fd504bffca719d1c6b63a1f6f840be1973a660" + integrity sha512-DPbJAlP8/BAXy3IgiWmZKItubb3TYGP0WscQQlVGIfT4s/YlFYVuJgyOsQNP7rJRChx/qdMeLJQJP0Sgg2yjNA== capture-exit@^2.0.0: version "2.0.0" @@ -8199,9 +8199,9 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.5.4: - version "1.5.13" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz#1abf0410c5344b2b829b7247e031f02810d442e6" - integrity sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q== + version "1.5.14" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.14.tgz#8de5fd941f4deede999f90503c4b5923fbe1962b" + integrity sha512-bEfPECb3fJ15eaDnu9LEJ2vPGD6W1vt7vZleSVyFhYuMIKm3vz/g9lt7IvEzgdwj58RjbPKUF2rXTCN/UW47tQ== element-resize-detector@^1.2.2: version "1.2.4" @@ -16790,9 +16790,9 @@ unset-value@^1.0.0: isobject "^3.0.0" unstorage@^1.9.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/unstorage/-/unstorage-1.11.0.tgz#4d5b48aef4180131669ac8cf95a26a33fd7051d0" - integrity sha512-d7ggFP/5h0AUIMbeQit8M3VuyIBFVMk2Ew5NOaCrKEsNzJRHym+0EhGD074ItIPuAEq8Q1EX3+NrizlJH700+g== + version "1.11.1" + resolved "https://registry.yarnpkg.com/unstorage/-/unstorage-1.11.1.tgz#6635ddb07ade7a34d42f9193a2d314cae2137841" + integrity sha512-3NVszU4MGlO21WWnkSq0xnPVMHnMyB5DdJQyGRAg/DUZVeQjWRinLOia89iw5KGpllRtoA5+N+xnq75MAsPAOA== dependencies: anymatch "^3.1.3" chokidar "^3.6.0"