UNPKG

@web3auth/no-modal

Version:
204 lines (200 loc) 9.22 kB
'use strict'; var _defineProperty = require('@babel/runtime/helpers/defineProperty'); var baseControllers = require('@toruslabs/base-controllers'); var sessionManager = require('@toruslabs/session-manager'); var auth = require('@web3auth/auth'); var IChainInterface = require('../chain/IChainInterface.js'); var index$1 = require('../errors/index.js'); var loglevel = require('../loglevel.js'); var utils = require('../utils.js'); var index = require('../wallet/index.js'); var connectorStatus = require('./connectorStatus.js'); var constants = require('./constants.js'); var utils$1 = require('./utils.js'); class BaseConnector extends auth.SafeEventEmitter { constructor(options) { super(); _defineProperty(this, "connectorData", {}); _defineProperty(this, "isInjected", void 0); _defineProperty(this, "icon", void 0); _defineProperty(this, "coreOptions", void 0); _defineProperty(this, "rehydrated", false); _defineProperty(this, "authSessionManager", null); this.coreOptions = options.coreOptions; } get connected() { return connectorStatus.CONNECTED_STATUSES.includes(this.status); } get canAuthorize() { return connectorStatus.CAN_AUTHORIZE_STATUSES.includes(this.status); } get solanaWallet() { return null; } get provider() { return null; } checkConnectionRequirements() { // we reconnect without killing existing Wallet Connect or Metamask Connect session on calling connect again. if (this.name === index.WALLET_CONNECTORS.WALLET_CONNECT_V2 && this.status === constants.CONNECTOR_STATUS.CONNECTING) return; if (this.name === index.WALLET_CONNECTORS.METAMASK && !this.isInjected && this.status === constants.CONNECTOR_STATUS.CONNECTING) return; if (this.status === constants.CONNECTOR_STATUS.CONNECTING) throw index$1.WalletInitializationError.notReady("Already connecting"); if (this.connected) throw index$1.WalletLoginError.connectionError("Already connected"); if (this.status !== constants.CONNECTOR_STATUS.READY) throw index$1.WalletLoginError.connectionError("Wallet connector is not ready yet, Please wait for init function to resolve before calling connect/connectTo function"); } checkInitializationRequirements({ chainConfig }) { if (!this.coreOptions.clientId) throw index$1.WalletInitializationError.invalidParams("Please initialize Web3Auth with a valid clientId in constructor"); if (!chainConfig) throw index$1.WalletInitializationError.invalidParams("chainConfig is required before initialization"); if (!chainConfig.rpcTarget && chainConfig.chainNamespace !== baseControllers.CHAIN_NAMESPACES.OTHER) { throw index$1.WalletInitializationError.invalidParams("rpcTarget is required in chainConfig"); } if (!chainConfig.chainId && chainConfig.chainNamespace !== baseControllers.CHAIN_NAMESPACES.OTHER) { throw index$1.WalletInitializationError.invalidParams("chainID is required in chainConfig"); } if (this.connectorNamespace !== IChainInterface.CONNECTOR_NAMESPACES.MULTICHAIN && this.connectorNamespace !== chainConfig.chainNamespace) throw index$1.WalletInitializationError.invalidParams("Connector doesn't support this chain namespace"); if (this.status === constants.CONNECTOR_STATUS.NOT_READY) return; if (this.connected) throw index$1.WalletInitializationError.notReady("Already connected"); if (this.status === constants.CONNECTOR_STATUS.READY) throw index$1.WalletInitializationError.notReady("Connector is already initialized"); } checkDisconnectionRequirements() { if (!this.connected) throw index$1.WalletLoginError.disconnectionError("Not connected with wallet"); } checkSwitchChainRequirements(params, init = false) { if (!init && !this.provider && !this.solanaWallet) throw index$1.WalletLoginError.notConnectedError("Not connected with wallet."); if (!this.coreOptions.chains) throw index$1.WalletInitializationError.invalidParams("chainConfigs is required"); const doesChainExist = this.coreOptions.chains.some(x => x.chainId === params.chainId && (x.chainNamespace === this.connectorNamespace || this.connectorNamespace === IChainInterface.CONNECTOR_NAMESPACES.MULTICHAIN)); if (!doesChainExist) throw index$1.WalletInitializationError.invalidParams("Invalid chainId"); } updateConnectorData(data) { this.connectorData = data; this.emit(constants.CONNECTOR_EVENTS.CONNECTOR_DATA_UPDATED, { connectorName: this.name, data }); } initSessionManager(address) { this.authSessionManager = new sessionManager.AuthSessionManager({ storageKeyPrefix: `w3a:siww:${this.name}:${address.toLowerCase()}`, apiClientConfig: { baseURL: utils.citadelServerUrl(this.coreOptions.authBuildEnv) }, storage: this.coreOptions.storage, cookieOptions: this.coreOptions.cookieOptions }); } async getCachedAuthTokenInfo() { if (!this.authSessionManager) return null; const idToken = await this.authSessionManager.getIdToken(); if (!idToken || utils$1.checkIfTokenIsExpired(idToken)) return null; let [accessToken, refreshToken] = await Promise.all([this.authSessionManager.getAccessToken(), this.authSessionManager.getRefreshToken()]); if ((!accessToken || utils$1.checkIfTokenIsExpired(accessToken)) && refreshToken) { try { const response = await this.authSessionManager.ensureRefresh(); accessToken = response.access_token || (await this.authSessionManager.getAccessToken()); refreshToken = response.refresh_token || refreshToken; } catch { // access token refresh failed; still return the valid idToken loglevel.log.error("Access token refresh failed"); } } return { idToken, accessToken: accessToken !== null && accessToken !== void 0 ? accessToken : undefined, refreshToken: refreshToken !== null && refreshToken !== void 0 ? refreshToken : undefined }; } async saveAuthTokenInfo(tokens) { if (!this.authSessionManager) return; await this.authSessionManager.setTokens({ idToken: tokens.idToken, accessToken: tokens.accessToken, refreshToken: tokens.refreshToken }); } async getCachedOrNullAuthTokenInfo(account) { this.initSessionManager(account); const cached = await this.getCachedAuthTokenInfo(); if (cached) { this.status = constants.CONNECTOR_STATUS.AUTHORIZED; this.emit(constants.CONNECTOR_EVENTS.AUTHORIZED, { connector: this.name, authTokenInfo: cached }); } return cached; } async verifyAndAuthorize(params) { let tokens; try { tokens = await baseControllers.verifySignedChallenge({ chainNamespace: params.chainNamespace, signedMessage: params.signedMessage, challenge: params.challenge, connector: this.name, authServer: params.authServer, web3AuthClientId: this.coreOptions.clientId, web3AuthNetwork: this.coreOptions.web3AuthNetwork, sessionTimeout: this.coreOptions.sessionTime, deviceInfo: baseControllers.getDeviceInfo() }); } catch (error) { if (error instanceof Response && error.status === 401) { const body = await error.clone().json().catch(() => ({})); if (body.message === "ACCESS_CONTROL_DENIED") { throw index$1.WalletLoginError.userBlocked("User is blocked by the application", error); } } throw error; } await this.saveAuthTokenInfo(tokens); const tokenInfo = { idToken: tokens.idToken, accessToken: tokens.accessToken, refreshToken: tokens.refreshToken }; this.status = constants.CONNECTOR_STATUS.AUTHORIZED; this.emit(constants.CONNECTOR_EVENTS.AUTHORIZED, { connector: this.name, authTokenInfo: tokenInfo }); return tokenInfo; } async authorizeOrDisconnect(getAuthTokenInfo, chainId) { if (!getAuthTokenInfo) return; try { await this.getAuthTokenInfo(chainId); } catch (error) { loglevel.log.error("Authorization failed after connect; disconnecting wallet to keep state consistent", error); const wasRehydrated = this.rehydrated; try { // getAuthTokenInfo moved status to AUTHORIZING; restore CONNECTED so disconnect requirements pass. if (!this.connected) this.status = constants.CONNECTOR_STATUS.CONNECTED; await this.disconnect(); } catch (disconnectError) { loglevel.log.error("Failed to disconnect wallet after authorization error", disconnectError); } finally { // disconnect() resets rehydrated=false; restore so caller catch emits the right event. this.rehydrated = wasRehydrated; } throw error; } } async clearWalletSession() { if (!this.authSessionManager) return; try { await this.authSessionManager.logout(); } catch { try { await this.authSessionManager.clearSessionData(); } catch { // best-effort cleanup; don't block disconnect loglevel.log.error("Failed to clear wallet session"); } } finally { this.authSessionManager = null; } } } exports.BaseConnector = BaseConnector;