import axios, { AxiosError, AxiosRequestHeaders } from 'axios'; import SessionManager from './SessionManager'; import FormData from 'form-data'; import { StatusCodes } from 'http-status-codes'; import ClientsSharedConfig from '../sharedByClients/config/ClientsSharedConfig'; import { version } from '../config/Version'; import DojoBackendResponse from '../shared/types/Dojo/DojoBackendResponse'; import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode'; import boxen from 'boxen'; import Config from '../config/Config'; import SharedConfig from '../shared/config/SharedConfig'; import { stateConfigFile } from '../config/ConfigFiles'; class HttpManager { public handleAuthorizationCommandErrors: boolean = true; registerAxiosInterceptor() { this.registerRequestInterceptor(); this.registerResponseInterceptor(); } private registerRequestInterceptor() { axios.interceptors.request.use((config) => { if ( config.data instanceof FormData ) { config.headers = { ...config.headers, ...(config.data as FormData).getHeaders() } as AxiosRequestHeaders; } if ( config.url && (config.url.indexOf(ClientsSharedConfig.apiURL) !== -1) ) { config.headers['Accept-Encoding'] = 'gzip'; if ( config.data && Object.keys(config.data).length > 0 ) { config.headers['Content-Type'] = 'multipart/form-data'; } if ( SessionManager.isLogged ) { config.headers.Authorization = `Bearer ${ SessionManager.apiToken }`; } config.headers['client'] = 'DojoCLI'; config.headers['client-version'] = version; } if ( SessionManager.gitlabCredentials.accessToken && config.url && config.url.indexOf(SharedConfig.gitlab.apiURL) !== -1 ) { config.headers.Authorization = `Bearer ${ SessionManager.gitlabCredentials.accessToken }`; } return config; }); } private requestError(message: string) { console.log(boxen(message, { title : 'Request error', titleAlignment: 'center', borderColor : 'red', borderStyle : 'bold', margin : 1, padding : 1, textAlignment : 'left' })); process.exit(1); } private registerResponseInterceptor() { axios.interceptors.response.use((response) => { if ( response.data && response.data.sessionToken ) { SessionManager.apiToken = response.data.sessionToken; } if ( response.headers['dojocli-latest-version'] ) { const latestDojoCliVersion = response.headers['dojocli-latest-version']; const storedLatestDojoCliVersion = stateConfigFile.getParam('latestDojoCliVersion') as string | null || '0.0.0'; if ( latestDojoCliVersion !== storedLatestDojoCliVersion ) { stateConfigFile.setParam('latestDojoCliVersion', latestDojoCliVersion); stateConfigFile.setParam('latestDojoCliVersionNotification', 0); } } return response; }, async (error) => { if ( error.response ) { const originalConfig = error.config; const isFromApi = error.response.config.url && error.response.config.url.indexOf(ClientsSharedConfig.apiURL) !== -1; const isFromGitlab = error.response.config.url && error.response.config.url.indexOf(SharedConfig.gitlab.URL) !== -1; // Try to refresh the Gitlab tokens if the request have failed with a 401 error if ( error.response.status === StatusCodes.UNAUTHORIZED && isFromGitlab && !originalConfig._retry ) { originalConfig._retry = true; try { await SessionManager.refreshTokens(); return axios(originalConfig); } catch ( error: unknown ) { if ( error instanceof AxiosError ) { if ( error.response && error.response.data ) { return Promise.reject(error.response.data); } } return Promise.reject(error); } } if ( error.response.status === StatusCodes.METHOD_NOT_ALLOWED && isFromApi && error.response.data ) { const data: DojoBackendResponse<void> = error.response.data; switch ( data.code ) { case DojoStatusCode.CLIENT_NOT_SUPPORTED: this.requestError('Client not recognized by the server. Please contact the administrator.'); break; case DojoStatusCode.CLIENT_VERSION_NOT_SUPPORTED: this.requestError(`CLI version not anymore supported by the server. Please update the CLI.\nYou can download the latest stable version on this page:\n${ Config.gitlab.cliReleasePage }`); break; default: break; } } if ( this.handleAuthorizationCommandErrors ) { if ( isFromApi ) { switch ( error.response.status ) { case StatusCodes.UNAUTHORIZED: this.requestError('Session expired or does not exist. Please login again.'); break; case StatusCodes.FORBIDDEN: this.requestError('Forbidden access.'); break; } } } else { this.handleAuthorizationCommandErrors = true; } } else { this.requestError('Error connecting to the server. Please check your internet connection. If the problem persists, please contact the administrator.'); } return Promise.reject(error); }); } } export default new HttpManager();