UNPKG

@simbachain/web3-suites

Version:

common code for web3 suite plugins. Code in this repo can be used for truffle or hardhat, but is designed to be applicable to future web3 suite plugins as well.

990 lines 46.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.KeycloakHandler = exports.authErrors = exports.AuthProviders = exports.AUTHKEY = void 0; const lib_1 = require("../lib"); const chalk_1 = __importDefault(require("chalk")); const axios_1 = __importDefault(require("axios")); const url_1 = require("url"); const config_1 = require("./config"); const utf8_1 = __importDefault(require("utf8")); exports.AUTHKEY = 'SIMBAAUTH'; var AuthProviders; (function (AuthProviders) { AuthProviders["KEYCLOAK"] = "keycloak"; AuthProviders["KEYCLOAKOAUTH2"] = "KeycloakOAuth2"; })(AuthProviders || (exports.AuthProviders = AuthProviders = {})); ; const SIMBAERROR = "SIMBAERROR"; exports.authErrors = { headersError: `${chalk_1.default.red('simba: Error acquiring auth headers. Please make sure your OAuth provider certs are not expired.')}`, keycloakCertsError: `${chalk_1.default.red('simba: Error obtaining auth creds. Please make sure your OAuth provider certs are not expired.')}`, verificationInfoError: `${chalk_1.default.red('simba: Error acquiring verification info. Please make sure OAuth provider certs are not expired.')}`, authTokenError: `${chalk_1.default.red('simba: Error acquiring auth token. Please make sure OAuth provider certs are not expired')}`, noClientIDError: `${chalk_1.default.red('simba: Error acquiring clientID. Please make sure "clientID" is configured correctly for your OAuth provider')}`, noBaseURLError: `${chalk_1.default.red('simba: Error acquiring SIMBA_API_BASE_URL/baseURL. Please make sure SIMBA_API_BASE_URL is configured')}`, noAuthURLError: `${chalk_1.default.red('simba: Error acquiring authURL. Please make sure "authURLID" is configured in simba.json')}`, noRealmError: `${chalk_1.default.red('simba: Error acquiring realm. Please make sure "realm" is configured in simba.json')}`, badAuthProviderInfo: `${chalk_1.default.red('simba: Error acquiring auth provider info. This may be due to a bad SIMBA_API_BASE_URL/baseURL value. Please make sure SIMBA_API_BASE_URL is configured')}`, }; /** * This class handles our login for keycloak device login */ class KeycloakHandler { constructor(config, projectConfig, tokenExpirationPad = 60) { this.authErrors = exports.authErrors; this.config = lib_1.SimbaConfig.ConfigStore; this.projectConfig = lib_1.SimbaConfig.ProjectConfigStore; this.baseURL = lib_1.SimbaConfig.retrieveBaseAPIURL(); if (!this.baseURL) { lib_1.SimbaConfig.log.error(`:: ${this.authErrors.noBaseURLError}`); } this.configBase = this.baseURL.split(".").join("_"); } /** * handles login */ async performLogin(interactive = true) { lib_1.SimbaConfig.log.debug(`:: ENTER : interactive : ${interactive}`); const authToken = await this.loginAndGetAuthToken(false, interactive); lib_1.SimbaConfig.log.debug(`:: EXIT :`); return authToken; } /** * used as field for our auth token * @returns */ getConfigBase() { lib_1.SimbaConfig.log.debug(`:: ENTER :`); if (!this.configBase) { this.configBase = this.baseURL.split(".").join("_"); } lib_1.SimbaConfig.log.debug(`:: EXIT : ${JSON.stringify(this.configBase)}`); return this.configBase; } /** * self explanatory * this method does not necessarily serve a big purpose right now, * may want to remove in future * @param status */ setLoggedInStatus(status) { lib_1.SimbaConfig.log.debug(`:: ENTER : ${status}`); this._loggedIn = status; lib_1.SimbaConfig.log.debug(`:: EXIT :`); } /** * used to avoid trying to login in when the process has already begun * @returns */ isLoggedIn() { lib_1.SimbaConfig.log.debug(`:: ENTER :`); if (this.verificationInfo) { lib_1.SimbaConfig.log.debug(`:: EXIT : ${true}`); return true; } else { lib_1.SimbaConfig.log.debug(`:: EXIT : ${false}`); return false; } } /** * deletes our auth info / auth token in authconfig.json */ async logout() { lib_1.SimbaConfig.log.debug(`:: ENTER :`); this.setLoggedInStatus(false); this.deleteAuthInfo(); lib_1.SimbaConfig.deleteAuthProviderInfo(); lib_1.SimbaConfig.log.debug(`:: EXIT :`); } /** * deletes auth info in authconfig.json */ deleteAuthInfo() { lib_1.SimbaConfig.log.debug(`:: ENTER :`); if (this.config.get(this.configBase)) { this.config.set(this.configBase, {}); lib_1.SimbaConfig.log.debug(`:: EXIT :`); } } /** * tells us whether a certain key exists in our configstore (authconfig.json) * @param key * @returns */ hasConfig(key) { lib_1.SimbaConfig.log.debug(`:: ENTER : ${key}`); if (!this.config.has(this.configBase)) { lib_1.SimbaConfig.log.debug(`:: EXIT : ${false}`); return false; } const _hasConfig = key in this.config.get(this.getConfigBase()); lib_1.SimbaConfig.log.debug(`:: EXIT : ${_hasConfig}`); return _hasConfig; } /** * return value for key from configstore (authconfig.json) * @param key * @returns */ getConfig(key) { lib_1.SimbaConfig.log.debug(`:: ENTER :`); if (!this.config.has(this.configBase)) { lib_1.SimbaConfig.log.debug(`:: EXIT :`); return; } const dict = this.config.get(this.getConfigBase()); if (!(key in dict)) { lib_1.SimbaConfig.log.debug(`:: EXIT :`); return; } const _config = dict[key]; lib_1.SimbaConfig.log.debug(`:: EXIT : ${JSON.stringify(_config)}`); return _config; } /** * pertains to configstore (authconfig.json) * @param key * @param value * @returns */ getOrSetConfig(key, value) { const entryParams = { key, value, }; lib_1.SimbaConfig.log.debug(`:: ENTER : ${JSON.stringify(entryParams)}`); if (!this.hasConfig(key)) { this.setConfig(key, value); lib_1.SimbaConfig.log.debug(`:: EXIT :`); return value; } lib_1.SimbaConfig.log.debug(`:: EXIT :`); return this.getConfig(key); } /** * sets key/value in configstore (authconfig.json) * @param key * @param value * @returns */ setConfig(key, value) { lib_1.SimbaConfig.log.debug(`:: ENTER : KEY: ${key}, VALUE: ${JSON.stringify(value)}`); if (!this.config.has(this.configBase)) { this.config.set(this.configBase, {}); } const dict = this.config.get(this.configBase); dict[key] = value; this.config.set(this.configBase, dict); lib_1.SimbaConfig.log.debug(`:: EXIT : this.config: ${JSON.stringify(this.config)}`); lib_1.SimbaConfig.log.debug(`:: EXIT :`); return value; } /** * deletes keyu, value in configstore (authconfig.json) * @param key * @returns */ deleteConfig(key) { lib_1.SimbaConfig.log.debug(`:: ENTER :`); if (!this.config.has(this.configBase)) { lib_1.SimbaConfig.log.debug(`:: EXIT :`); return; } const dict = this.config.get(this.configBase); if (!(key in dict)) { lib_1.SimbaConfig.log.debug(`:: EXIT :`); return; } delete dict[key]; this.config.set(this.configBase, dict); lib_1.SimbaConfig.log.debug(`:: EXIT :`); } /** * uses expires_in from authtoken to create more human readable version, * as well as expires_at * @param auth * @returns */ parseExpiry(auth) { if ('expires_in' in auth) { const retrievedAt = new Date(); const expiresIn = parseInt(auth.expires_in, 10) * 1000; const expiresAt = new Date(Date.parse(retrievedAt.toISOString()) + expiresIn); auth.retrieved_at = retrievedAt.toISOString(); auth.expires_at = expiresAt.toISOString(); if (auth.refresh_expires_in) { const refreshExpiresIn = parseInt(auth.refresh_expires_in, 10) * 1000; const refreshExpiresAt = new Date(Date.parse(retrievedAt.toISOString()) + refreshExpiresIn); auth.refresh_expires_at = refreshExpiresAt.toISOString(); } } return auth; } /** * retrieves auth token using client creds, sets authtoken in authconfig.json * @returns */ async getAndSetAuthTokenFromClientCreds() { lib_1.SimbaConfig.log.debug(`:: ENTER :`); const clientID = lib_1.SimbaConfig.retrieveEnvVar(config_1.EnvVariableKeys.ID); const clientSecret = lib_1.SimbaConfig.retrieveEnvVar(config_1.EnvVariableKeys.SECRET); const authEndpoint = lib_1.SimbaConfig.retrieveEnvVar(config_1.EnvVariableKeys.AUTHENDPOINT); const credential = `${clientID}:${clientSecret}`; const utf8EncodedCred = utf8_1.default.encode(credential); const base64EncodedCred = Buffer.from(utf8EncodedCred).toString('base64'); const params = new url_1.URLSearchParams(); params.append('grant_type', "client_credentials"); const headers = { "content-type": "application/x-www-form-urlencoded", "Cache-Control": "no-cache", "Authorization": `Basic ${base64EncodedCred}` }; const config = { headers, }; try { const baseURL = lib_1.SimbaConfig.retrieveBaseAPIURL(); const url = (0, lib_1.buildURL)(baseURL, `${authEndpoint}token/`); lib_1.SimbaConfig.log.debug(`:: url : ${url}`); const res = await axios_1.default.post(url, params, config); let authToken = res.data; authToken = this.parseExpiry(authToken); this.setConfig(exports.AUTHKEY, authToken); lib_1.SimbaConfig.log.debug(`:: EXIT : authToken: ${JSON.stringify(authToken)}`); return authToken; } catch (error) { if (axios_1.default.isAxiosError(error) && error.response) { if (error.response.data.error === "invalid_client") { const message = "'invalid_client' error. This may mean you are using an invalid client ID and secret. Please make sure that your values for SIMBA_AUTH_CLIENT_ID and SIMBA_AUTH_CLIENT_SECRET are correct, were generated for the correct environment, and are properly set in .simbachain.env, simbachain.env, or .env. You create one of these files and set in either your project root or SIMBA_HOME location."; lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : ${message}`)}`); throw new Error(message); } const message = JSON.stringify(error.response.data); lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : ${message}`)}`); throw new Error(message); } else { const message = JSON.stringify(error); lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : ${message}`)}`); throw new Error(message); } } } /** * first step in logging in. returns verification info, including a URI, * to allow user to login. * @returns */ async getVerificationInfo() { lib_1.SimbaConfig.log.debug(`:: ENTER :`); const authProviderInfo = await lib_1.SimbaConfig.setAndGetAuthProviderInfo(); const realm = authProviderInfo.realm; const authURL = authProviderInfo.baseurl; const clientID = authProviderInfo.client_id; const url = `${authURL}/realms/${realm}/protocol/openid-connect/auth/device`; const params = new url_1.URLSearchParams(); params.append('client_id', clientID); const headers = { 'content-type': 'application/x-www-form-urlencoded;charset=utf-8' }; const config = { headers: headers, }; try { const res = await axios_1.default.post(url, params, config); const verificationInfo = res.data; this.verificationInfo = verificationInfo; lib_1.SimbaConfig.log.debug(`:: EXIT : ${JSON.stringify(this.verificationInfo)}`); return verificationInfo; } catch (error) { if (axios_1.default.isAxiosError(error) && error.response) { const message = JSON.stringify(error.response.data); lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : ${message}`)}`); throw new Error(message); } else { const message = JSON.stringify(error); lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : ${message}`)}`); throw new Error(message); } } } /** * reads out URI user should navigate to for login * @returns */ async loginUser() { lib_1.SimbaConfig.log.debug(`:: ENTER :`); if (!this.isLoggedIn()) { this.verificationInfo = await this.getVerificationInfo(); } const verificationCompleteURI = this.verificationInfo.verification_uri_complete; // the following line is where we begin the flow of handling not acquiring verification info if (!verificationCompleteURI) { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : ${this.authErrors.keycloakCertsError}`)}`); return SIMBAERROR; } lib_1.SimbaConfig.log.info(`\n${chalk_1.default.cyanBright('\nsimba: Please navigate to the following URI to log in: ')} ${chalk_1.default.greenBright(verificationCompleteURI)}`); lib_1.SimbaConfig.log.debug(`:: EXIT :`); return verificationCompleteURI; } /** * allows user to login after they have navigated to the URI from loginUser() * @param pollingConfig * @param refreshing * @returns */ async getAuthToken(pollingConfig = { maxAttempts: 60, interval: 3000, }, refreshing = false) { lib_1.SimbaConfig.log.debug(`:: ENTER :`); const maxAttempts = pollingConfig.maxAttempts; const interval = pollingConfig.interval; if (!this.isLoggedIn()) { this.verificationInfo = await this.getVerificationInfo(); } if (!this.verificationInfo) { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : ${this.authErrors.verificationInfoError}`)}`); return; } const deviceCode = this.verificationInfo.device_code; const params = new url_1.URLSearchParams(); const authProviderInfo = await lib_1.SimbaConfig.setAndGetAuthProviderInfo(); const realm = authProviderInfo.realm; const authURL = authProviderInfo.baseurl; const clientID = authProviderInfo.client_id; const url = `${authURL}/realms/${realm}/protocol/openid-connect/token`; const headers = { 'content-type': 'application/x-www-form-urlencoded;charset=utf-8' }; const config = { headers: headers, }; if (!refreshing) { params.append("grant_type", "urn:ietf:params:oauth:grant-type:device_code"); params.append("client_id", clientID); params.append("device_code", deviceCode); let attempts = 0; while (attempts < maxAttempts) { await new Promise(resolve => setTimeout(resolve, interval)); try { let response = await axios_1.default.post(url, params, config); let authToken = response.data; authToken = this.parseExpiry(authToken); this.setConfig(exports.AUTHKEY, authToken); lib_1.SimbaConfig.log.debug(`:: EXIT : ${JSON.stringify(authToken)}`); return authToken; } catch (error) { if (axios_1.default.isAxiosError(error) && error.response) { lib_1.SimbaConfig.log.debug(`${chalk_1.default.redBright(`\nsimba: ${JSON.stringify(error.response.data)}`)}`); } else { lib_1.SimbaConfig.log.debug(`${chalk_1.default.redBright(`\nsimba: ${JSON.stringify(error)}`)}`); } if (attempts % 5 == 0) { lib_1.SimbaConfig.log.info(`${chalk_1.default.cyanBright(`\nsimba: still waiting for user to login...`)}`); } attempts += 1; } } lib_1.SimbaConfig.log.debug(`:: EXIT : attempts exceeded, timedout`); return; } else { lib_1.SimbaConfig.log.debug(`:: entering refresh logic`); const authToken = this.getConfig(exports.AUTHKEY); lib_1.SimbaConfig.log.debug(`:: auth : ${JSON.stringify(authToken)}`); const _refreshToken = authToken.refresh_token; params.append("client_id", clientID); params.append("grant_type", "refresh_token"); params.append("refresh_token", _refreshToken); await new Promise(resolve => setTimeout(resolve, interval)); try { let response = await axios_1.default.post(url, params, config); let newAuthToken = response.data; newAuthToken = this.parseExpiry(newAuthToken); this.setConfig(exports.AUTHKEY, newAuthToken); lib_1.SimbaConfig.log.debug(`:: EXIT : ${JSON.stringify(newAuthToken)}`); return newAuthToken; } catch (error) { if (axios_1.default.isAxiosError(error) && error.response) { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : ${JSON.stringify(error.response.data)}`)}`); } else { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : ${JSON.stringify(error)}`)}`); } return; } } } /** * checks if auth token is expired. used as a check before we make http call * idea is to check for bad token before http call, if possible * @returns */ tokenExpired() { lib_1.SimbaConfig.log.debug(`:: ENTER :`); if (!this.hasConfig(exports.AUTHKEY)) { lib_1.SimbaConfig.log.debug(`:: EXIT : no authToken exists, exiting with true`); return true; } const authToken = this.getConfig(exports.AUTHKEY); if (!authToken.expires_at) { lib_1.SimbaConfig.log.debug(`:: EXIT : true`); return true; } if (new Date(authToken.expires_at) <= new Date()) { lib_1.SimbaConfig.log.debug(`:: EXIT : access_token expired, returning true`); return true; } lib_1.SimbaConfig.log.debug(`:: EXIT : false`); return false; } /** * checks if refresh token is expired. used as a check before we make http call * idea is to check for bad token before http call, if possible * @returns */ refreshTokenExpired() { lib_1.SimbaConfig.log.debug(`:: ENTER :`); if (!this.hasConfig(exports.AUTHKEY)) { lib_1.SimbaConfig.log.debug(`:: EXIT : true`); return true; } const authToken = this.getConfig(exports.AUTHKEY); if (!authToken.refresh_expires_at) { lib_1.SimbaConfig.log.debug(`:: EXIT : true`); return true; } if (new Date(authToken.refresh_expires_at) <= new Date()) { lib_1.SimbaConfig.log.debug(`:: EXIT : refresh_token expired, returning true`); return true; } lib_1.SimbaConfig.log.debug(`:: EXIT : false`); return false; } /** * refresh auth token using refresh token * @returns {Promise<KeycloakAccessToken | ClientCredsToken | void>} */ async refreshToken() { lib_1.SimbaConfig.log.debug(`:: ENTER :`); let interactive = true; const currentAuthToken = this.getConfig(exports.AUTHKEY); // if there isn't a refresh_token, then it's a client credentials token // so we grab a new auth token from client creds if (currentAuthToken && !currentAuthToken.refresh_token) { interactive = false; } if (this.refreshTokenExpired()) { this.deleteAuthInfo(); const authToken = await this.loginAndGetAuthToken(false, interactive); if (authToken) { lib_1.SimbaConfig.log.debug(`:: EXIT : ${JSON.stringify(authToken)}`); return authToken; } else { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : ${this.authErrors.authTokenError}`)}`); return; } } lib_1.SimbaConfig.log.debug(`:: entering logic to refresh token`); const pollingConfig = { maxAttempts: 60, interval: 3000, }; const refreshing = true; const newAuthToken = await this.getAuthToken(pollingConfig, refreshing); if (newAuthToken) { lib_1.SimbaConfig.log.debug(`:: EXIT : ${JSON.stringify(newAuthToken)}`); return newAuthToken; } else { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : ${this.authErrors.authTokenError}`)}`); return; } } /** * used for both client creds and device login * @param refreshing specifies whether just refreshing * @param interactive device login if true, client creds if false * @returns */ async loginAndGetAuthToken(refreshing = false, interactive = true) { lib_1.SimbaConfig.log.debug(`:: ENTER :`); let verificationCompleteURI; if (!interactive) { const authToken = await this.getAndSetAuthTokenFromClientCreds(); lib_1.SimbaConfig.log.debug(`:: EXIT :`); return authToken; } if (!refreshing) { this.logout(); verificationCompleteURI = await this.loginUser(); } // below we are checking to make sure that SIMBERROR was not returned from loginuser if (verificationCompleteURI !== SIMBAERROR) { const pollingConfig = { maxAttempts: 60, interval: 3000, }; const authToken = await this.getAuthToken(pollingConfig, refreshing); lib_1.SimbaConfig.log.debug(`:: EXIT : authToken : ${JSON.stringify(authToken)}`); this.setLoggedInStatus(true); return authToken; } else { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: :: EXIT : ${this.authErrors.verificationInfoError}`)}`); return; } } /** * returns headers with access token * @returns {Promise<Record<any, any> | void>} */ async accessTokenHeader() { lib_1.SimbaConfig.log.debug(`:: ENTER :`); let authToken = this.getConfig(exports.AUTHKEY); if (!authToken) { authToken = await this.loginAndGetAuthToken(false); } if (authToken) { const accessToken = authToken.access_token; const headers = { Authorization: `Bearer ${accessToken}`, }; lib_1.SimbaConfig.log.debug(`:: EXIT : headers: ${JSON.stringify(headers)}`); return headers; } else { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : ${this.authErrors.authTokenError}`)}`); return; } } /** * creates full url given our baseURL and an endpoint, while handling redundant "/" * @param urlExtension * @returns {string} */ buildURL(endpoint) { lib_1.SimbaConfig.log.debug(`:: ENTER : ${endpoint}`); if (endpoint.startsWith("http")) { lib_1.SimbaConfig.log.debug(`:: EXIT : ${endpoint}`); return endpoint; } let baseURL = this.baseURL.endsWith("/") ? this.baseURL : this.baseURL + "/"; let modifiedExtension = endpoint.startsWith("/") ? endpoint.slice(1) : endpoint; const fullURL = baseURL + modifiedExtension; lib_1.SimbaConfig.log.debug(`:: EXIT : ${fullURL}`); return fullURL; } /** * make get request. currently uses Axios * @param url * @param contentType * @param _queryParams * @param _buildURL - builds url using baseURL and url if true * @returns {Promise<Record<any, any> | Error | void>} */ async doGetRequest(url, contentType, _queryParams, _buildURL = true) { const funcParams = { url, _queryParams, contentType, }; lib_1.SimbaConfig.log.debug(`:: ENTER : ${JSON.stringify(funcParams)}`); const authProviderInfo = await lib_1.SimbaConfig.setAndGetAuthProviderInfo(); const clientID = authProviderInfo.client_id; if (this.tokenExpired()) { lib_1.SimbaConfig.log.info(`${chalk_1.default.cyanBright(`\nsimba: auth token expired`)}`); if (this.refreshTokenExpired()) { lib_1.SimbaConfig.log.info(`${chalk_1.default.cyanBright(`\nsimba: refresh token expired, acquiring new auth token`)}`); const authToken = await this.loginAndGetAuthToken(); if (!authToken) { lib_1.SimbaConfig.log.error(`${chalk_1.default.red(`\nsimba: EXIT : ${this.authErrors.authTokenError}`)}`); throw new Error(`${this.authErrors.authTokenError}`); } } else { lib_1.SimbaConfig.log.info(`${chalk_1.default.cyanBright(`\nsimba: refreshing token`)}`); const newAuthToken = await this.refreshToken(); if (!newAuthToken) { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : ${this.authErrors.authTokenError}`)}`); lib_1.SimbaConfig.log.info(`${chalk_1.default.cyanBright(`\nsimba: there was an error with your request, please log out and then login again, then try your request again`)}`); return; } } } const queryParams = _queryParams ? _queryParams : {}; const headers = await this.accessTokenHeader(); if (headers) { if (!contentType) { headers["content-type"] = "application/json"; } else { headers["content-type"] = contentType; } const params = new url_1.URLSearchParams(); params.append('client_id', clientID); for (const [key, value] of Object.entries(queryParams)) { params.append(key, value); } const config = { headers: headers, }; try { if (_buildURL) { url = (0, lib_1.buildURL)(this.baseURL, url); } const res = await axios_1.default.get(url, config); const resData = res.data; lib_1.SimbaConfig.log.debug(`:: EXIT : ${JSON.stringify(resData)}`); return resData; } catch (error) { if (axios_1.default.isAxiosError(error) && error.response) { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: ${JSON.stringify(error.response.data)}`)}`); } else { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: ${JSON.stringify(error)}`)}`); } lib_1.SimbaConfig.log.debug(`simba: ${chalk_1.default.redBright(`${JSON.stringify(error)}`)}`); if (axios_1.default.isAxiosError(error) && error.response && error.response.status === 401) { lib_1.SimbaConfig.log.debug(`:: received 401 response, attempting to refresh token`); // if 401 from Simba, then try refreshing token. try { const newAuthToken = await this.refreshToken(); if (newAuthToken) { lib_1.SimbaConfig.log.info(`${chalk_1.default.cyanBright(`\nsimba: new token acquired. Please try your request again`)}`); return; } else { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: there was a problem acquiring your access token. Please log out and then login and then try your request again`)}`); return; } } catch (e) { if (axios_1.default.isAxiosError(e) && e.response) { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: ${JSON.stringify(e.response.data)}`)}`); } else { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: ${JSON.stringify(e)}`)}`); } try { lib_1.SimbaConfig.log.info(`${chalk_1.default.cyanBright(`\nsimba: you need to login again; redirecting you to login. Then please try your request again.`)}`); await this.loginAndGetAuthToken(false); return; } catch (e) { if (axios_1.default.isAxiosError(e) && e.response) { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: ${JSON.stringify(e.response.data)}`)}`); } else { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: ${JSON.stringify(e)}`)}`); } const err = e; lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : there was a problem with your request. Please log out and then login and then try your request again`)}`); return err; } } } else { const message = `simba: there was a problem with your request. To view debug logs, please set your loglevel to debug and try your request again.`; lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`${message}`)}`); throw new Error(message); } } } else { const message = `${this.authErrors.authTokenError}`; lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : ${message}`)}`); throw new Error(message); } } /** * do post request. uses axios library * @param url * @param _postData * @param contentType * @param _buildURL - builds url using baseURL and url if true * @returns {Promise<Record<any, any> | void>} */ async doPostRequest(url, _postData, contentType, _buildURL = true) { return await this.doPutPostRequest("POST", url, _postData, contentType, _buildURL); } /** * do put request * @param url * @param _postData * @param contentType * @param _buildURL - builds url using baseURL and url if true * @returns {Promise<Record<any, any> | void>} */ async doPutRequest(url, _postData, contentType, _buildURL = true) { return await this.doPutPostRequest("PUT", url, _postData, contentType, _buildURL); } /** * do put or post request. uses axios library * @param method * @param url * @param _postData * @param contentType * @param _buildURL - builds url using baseURL and url if true * @returns {Promise<Record<any, any> | void>} */ async doPutPostRequest(method, url, _postData, contentType, _buildURL = true) { const funcParams = { url, _postData, contentType, }; lib_1.SimbaConfig.log.debug(`:: ENTER : ${JSON.stringify(funcParams)}`); if (!(['POST', 'PUT'].includes(method))) { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : Invalid method, must be 'POST' or 'PUT'`)}`); } if (this.tokenExpired()) { lib_1.SimbaConfig.log.info(`${chalk_1.default.cyanBright(`\nsimba: auth token expired`)}`); if (this.refreshTokenExpired()) { lib_1.SimbaConfig.log.info(`${chalk_1.default.cyanBright(`\nsimba: refresh token expired, acquiring new auth token`)}`); const authToken = await this.loginAndGetAuthToken(); if (!authToken) { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : ${this.authErrors.authTokenError}`)}`); throw new Error(`${this.authErrors.authTokenError}`); } } else { lib_1.SimbaConfig.log.info(`${chalk_1.default.cyanBright(`\nsimba: refreshing token`)}`); const newAuthToken = await this.refreshToken(); if (!newAuthToken) { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : ${this.authErrors.authTokenError}`)}`); lib_1.SimbaConfig.log.info(`${chalk_1.default.cyanBright(`\nsimba: there was an error with your request, please log out and then login again, then try your request again`)}`); return; } } } const postData = _postData ? _postData : {}; const headers = await this.accessTokenHeader(); if (headers) { if (!contentType) { headers["content-type"] = "application/json"; } else { headers["content-type"] = contentType; } const config = { headers: headers, }; try { if (_buildURL) { url = (0, lib_1.buildURL)(this.baseURL, url); } let res; if (method === "POST") { res = await axios_1.default.post(url, postData, config); } else if (method === "PUT") { res = await axios_1.default.put(url, postData, config); } const resData = res.data; lib_1.SimbaConfig.log.debug(`:: EXIT : ${JSON.stringify(resData)}`); return resData; } catch (error) { if (axios_1.default.isAxiosError(error) && error.response) { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: ${JSON.stringify(error.response.data)}`)}`); } else { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: ${JSON.stringify(error)}`)}`); } lib_1.SimbaConfig.log.debug(`simba: ${JSON.stringify(error)}`); if (axios_1.default.isAxiosError(error) && error.response && error.response.data && error.response.data.errors && error.response.data.errors[0].detail && error.response.data.errors[0].detail.includes("unsupported version")) { const detail = error.response.data.errors[0].detail; const version = detail.split("version")[1]; const message = `\nsimba: you are attempting to export a contract that uses solc compiler version ${version}, which is not supported. Please switch your solc compiler to a supported version. This likely includes updating your compiler version in the contract source code, as well as configuring the compiler that your project is using. Please navigate to the following URL for supported versions of Solidity: https://simba-chain.gitbook.io/documentation/faq/faq#supported-versions\n`; lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`${message}`)}`); throw new Error(message); } if (axios_1.default.isAxiosError(error) && error.response && error.response.status === 401) { lib_1.SimbaConfig.log.debug(`:: received 401 response, attempting to refresh token`); // if 401 from Simba, then try refreshing token. try { const newAuthToken = await this.refreshToken(); if (newAuthToken) { lib_1.SimbaConfig.log.info(`${chalk_1.default.cyanBright(`\nsimba: new token acquired. Please try your request again`)}`); return; } else { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: there was a problem acquiring your access token. Please log out and then login and then try your request again`)}`); return; } } catch (e) { if (axios_1.default.isAxiosError(e) && e.response) { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: ${JSON.stringify(e.response.data)}`)}`); } else { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: ${JSON.stringify(e)}`)}`); } try { lib_1.SimbaConfig.log.info(`${chalk_1.default.cyanBright(`\nsimba: you need to login again; redirecting you to login. Then please try your request again.`)}`); await this.loginAndGetAuthToken(false); return; } catch (e) { if (axios_1.default.isAxiosError(e) && e.response) { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: ${JSON.stringify(e.response.data)}`)}`); } else { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: ${JSON.stringify(e)}`)}`); } const err = e; lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : there was a problem with your request. Please log out and then login and then try your request again`)}`); return err; } } } else { const message = `simba: there was a problem with your request. To view debug logs, please set your loglevel to debug and try your request again.`; lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`${message}`)}`); throw new Error(message); } } } else { const message = `${this.authErrors.headersError}`; lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : ${message}`)}`); throw new Error(message); } } /** * * @param url * @param contentType * @param _buildURL - builds url using baseURL and url if true * @returns {Promise<Record<any, any> | void>} */ async doDeleteRequest(url, contentType, _buildURL = true) { const entryParams = { url, contentType, _buildURL, }; lib_1.SimbaConfig.log.debug(`:: ENTER : ${JSON.stringify(entryParams)}`); if (this.tokenExpired()) { lib_1.SimbaConfig.log.info(`${chalk_1.default.cyanBright(`\nsimba: auth token expired`)}`); if (this.refreshTokenExpired()) { lib_1.SimbaConfig.log.info(`${chalk_1.default.cyanBright(`\nsimba: refresh token expired, acquiring new auth token`)}`); const authToken = await this.loginAndGetAuthToken(); if (!authToken) { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : ${this.authErrors.authTokenError}`)}`); throw new Error(`${this.authErrors.authTokenError}`); } } else { lib_1.SimbaConfig.log.info(`${chalk_1.default.cyanBright(`\nsimba: refreshing token`)}`); const newAuthToken = await this.refreshToken(); if (!newAuthToken) { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : ${this.authErrors.authTokenError}`)}`); lib_1.SimbaConfig.log.info(`${chalk_1.default.cyanBright(`\nsimba: there was an error with your request, please log out and then login again, then try your request again`)}`); return; } } } const headers = await this.accessTokenHeader(); if (headers) { if (!contentType) { headers["content-type"] = "application/json"; } else { headers["content-type"] = contentType; } const config = { headers: headers, }; try { if (_buildURL) { url = (0, lib_1.buildURL)(this.baseURL, url); } let res; res = await axios_1.default.delete(url, config); const resData = res.data; lib_1.SimbaConfig.log.debug(`:: EXIT : ${JSON.stringify(resData)}`); return resData; } catch (error) { if (axios_1.default.isAxiosError(error) && error.response) { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: ${JSON.stringify(error.response.data)}`)}`); } else { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: ${JSON.stringify(error)}`)}`); } lib_1.SimbaConfig.log.debug(`err: ${JSON.stringify(error)}`); if (axios_1.default.isAxiosError(error) && error.response && error.response.status === 401) { lib_1.SimbaConfig.log.debug(`:: received 401 response, attempting to refresh token`); // if 401 from Simba, then try refreshing token. try { const newAuthToken = await this.refreshToken(); if (newAuthToken) { lib_1.SimbaConfig.log.info(`${chalk_1.default.cyanBright(`\nsimba: new token acquired. Please try your request again`)}`); return; } else { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: there was a problem acquiring your access token. Please log out and then login and then try your request again`)}`); return; } } catch (e) { if (axios_1.default.isAxiosError(e) && e.response) { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: ${JSON.stringify(e.response.data)}`)}`); } else { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: ${JSON.stringify(e)}`)}`); } try { lib_1.SimbaConfig.log.info(`${chalk_1.default.cyanBright(`\nsimba: you need to login again; redirecting you to login. Then please try your request again.`)}`); await this.loginAndGetAuthToken(false); return; } catch (e) { if (axios_1.default.isAxiosError(e) && e.response) { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: ${JSON.stringify(e.response.data)}`)}`); } else { lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: ${JSON.stringify(e)}`)}`); } const err = e; lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : there was a problem with your request. Please log out and then login and then try your request again`)}`); return err; } } } else { const message = `simba: there was a problem with your request. To view debug logs, please set your loglevel to debug and try your request again.`; lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`${message}`)}`); throw new Error(message); } } } else { const message = `${this.authErrors.headersError}`; lib_1.SimbaConfig.log.error(`${chalk_1.default.redBright(`\nsimba: EXIT : ${message}`)}`); throw new Error(`${message}`); } } } exports.KeycloakHandler = KeycloakHandler; //# sourceMappingURL=authentication.js.map