UNPKG

@confluentinc/schemaregistry

Version:
145 lines (144 loc) 6.99 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.RestService = void 0; const axios_1 = __importDefault(require("axios")); const rest_error_1 = require("./rest-error"); const axios_retry_1 = __importDefault(require("axios-retry")); const retry_helper_1 = require("./retry-helper"); const package_json_1 = require("./package.json"); const static_token_provider_1 = require("./oauth/static-token-provider"); const oauth_client_1 = require("./oauth/oauth-client"); const oauth_client_azure_imds_1 = require("./oauth/oauth-client-azure-imds"); const toBase64 = (str) => Buffer.from(str).toString('base64'); class RestService { constructor(baseURLs, isForward, axiosDefaults, basicAuthCredentials, bearerAuthCredentials, maxRetries, retriesWaitMs, retriesMaxWaitMs) { this.client = axios_1.default.create(axiosDefaults); (0, axios_retry_1.default)(this.client, { retries: maxRetries ?? 3, retryDelay: (retryCount) => { return (0, retry_helper_1.fullJitter)(retriesWaitMs ?? 1000, retriesMaxWaitMs ?? 20000, retryCount - 1); }, retryCondition: (error) => { return (0, retry_helper_1.isRetriable)(error.response?.status ?? 0); } }); this.baseURLs = baseURLs; if (isForward) { this.setHeaders({ 'X-Forward': 'true' }); } this.setHeaders({ 'Content-Type': 'application/vnd.schemaregistry.v1+json' }); this.setHeaders({ 'Confluent-Accept-Unknown-Properties': 'true' }); this.setHeaders({ 'Confluent-Client-Version': `javascript/${package_json_1.version}` }); this.handleBasicAuth(basicAuthCredentials); this.handleBearerAuth(maxRetries ?? 2, retriesWaitMs ?? 1000, retriesMaxWaitMs ?? 20000, bearerAuthCredentials); } handleBasicAuth(basicAuthCredentials) { if (basicAuthCredentials) { switch (basicAuthCredentials.credentialsSource) { case 'USER_INFO': if (!basicAuthCredentials.userInfo) { throw new Error('User info not provided'); } this.setAuth(toBase64(basicAuthCredentials.userInfo)); break; case 'SASL_INHERIT': if (!basicAuthCredentials.sasl) { throw new Error('Sasl info not provided'); } if (basicAuthCredentials.sasl.mechanism?.toUpperCase() === 'GSSAPI') { throw new Error('SASL_INHERIT support PLAIN and SCRAM SASL mechanisms only'); } this.setAuth(toBase64(`${basicAuthCredentials.sasl.username}:${basicAuthCredentials.sasl.password}`)); break; case 'URL': if (!basicAuthCredentials.userInfo) { throw new Error('User info not provided'); } const basicAuthUrl = new URL(basicAuthCredentials.userInfo); this.setAuth(toBase64(`${basicAuthUrl.username}:${basicAuthUrl.password}`)); break; default: throw new Error('Invalid basic auth credentials source'); } } } handleBearerAuth(maxRetries, retriesWaitMs, retriesMaxWaitMs, bearerAuthCredentials) { if (bearerAuthCredentials) { delete this.client.defaults.auth; const headers = ['logicalCluster', 'identityPoolId']; const missingHeader = headers.find(header => !(header in bearerAuthCredentials)); if (missingHeader) { throw new Error(`Bearer auth header '${missingHeader}' not provided`); } if (!(bearerAuthCredentials.credentialsSource in RestService.oauthBearerTokenProviderBuilders)) { throw new Error('Invalid bearer auth credentials source'); } this.bearerTokenProvider = RestService.oauthBearerTokenProviderBuilders[bearerAuthCredentials.credentialsSource](bearerAuthCredentials).build(maxRetries, retriesWaitMs, retriesMaxWaitMs); this.setHeaders(this.bearerTokenProvider.getAdditionalHeaders()); } } async handleRequest(url, method, data, // eslint-disable-line @typescript-eslint/no-explicit-any config) { if (this.bearerTokenProvider && this.bearerTokenProvider.tokenExpired()) { await this.setOAuthBearerToken(); } for (let i = 0; i < this.baseURLs.length; i++) { try { this.setBaseURL(this.baseURLs[i]); const response = await this.client.request({ url, method, data, ...config, }); return response; } catch (error) { if (axios_1.default.isAxiosError(error) && error.response && !(0, retry_helper_1.isSuccess)(error.response.status)) { const data = error.response.data; if (data.error_code && data.message) { error = new rest_error_1.RestError(data.message, error.response.status, data.error_code); } else { error = new Error(`Unknown error: ${error.message}`); } } if (i === this.baseURLs.length - 1) { throw error; } } } throw new Error('Internal HTTP retry error'); // Should never reach here } setHeaders(headers) { this.client.defaults.headers.common = { ...this.client.defaults.headers.common, ...headers }; } setAuth(basicAuth, bearerToken) { if (basicAuth) { this.client.defaults.headers.common['Authorization'] = `Basic ${basicAuth}`; } if (bearerToken) { this.client.defaults.headers.common['Authorization'] = `Bearer ${bearerToken}`; } } async setOAuthBearerToken() { const bearerToken = await this.bearerTokenProvider.getAccessToken(); this.setAuth(undefined, bearerToken); } setTimeout(timeout) { this.client.defaults.timeout = timeout; } setBaseURL(baseUrl) { this.client.defaults.baseURL = baseUrl; } } exports.RestService = RestService; RestService.oauthBearerTokenProviderBuilders = { 'STATIC_TOKEN': (credentials) => new static_token_provider_1._StaticTokenProviderBuilder(credentials), 'OAUTHBEARER': (credentials) => new oauth_client_1._OAuthClientBuilder(credentials), 'OAUTHBEARER_AZURE_IMDS': (credentials) => new oauth_client_azure_imds_1._AzureIMDSOAuthClientBuilder(credentials) };