@web3auth/no-modal
Version:
Multi chain wallet aggregator for web3Auth
204 lines (200 loc) • 9.22 kB
JavaScript
'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;