UNPKG

ydb-sdk

Version:

Node.js bindings for working with YDB API over gRPC

118 lines (117 loc) 6.09 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.StaticCredentialsAuthService = void 0; const ydb_sdk_proto_1 = require("ydb-sdk-proto"); var AuthServiceResult = ydb_sdk_proto_1.Ydb.Auth.LoginResult; const utils_1 = require("../utils"); const retries_obsoleted_1 = require("../retries_obsoleted"); const process_ydb_operation_result_1 = require("../utils/process-ydb-operation-result"); const add_credentials_to_metadata_1 = require("./add-credentials-to-metadata"); const get_default_logger_1 = require("../logger/get-default-logger"); const TOKEN_EXPIRY_MARGIN = 60; // seconds class StaticCredentialsGrpcService extends utils_1.GrpcService { constructor(endpoint, sslCredentials, logger = (0, get_default_logger_1.getDefaultLogger)()) { super(endpoint, 'Ydb.Auth.V1.AuthService', ydb_sdk_proto_1.Ydb.Auth.V1.AuthService, sslCredentials); this.logger = logger; } login(request) { return this.api.login(request); } destroy() { this.api.end(); } } __decorate([ (0, retries_obsoleted_1.retryable)() ], StaticCredentialsGrpcService.prototype, "login", null); class StaticCredentialsAuthService { constructor(user, password, endpoint, loggerOrOptions, options) { this.tokenRequestTimeout = 10 * 1000; this.tokenRefreshInterval = null; this.token = null; // Mutex this.promise = null; this.user = user; this.password = password; this.endpoint = endpoint; this.sslCredentials = options === null || options === void 0 ? void 0 : options.sslCredentials; if (typeof loggerOrOptions === 'object' && loggerOrOptions !== null && 'error' in loggerOrOptions) { this.logger = loggerOrOptions; } else { options = loggerOrOptions; this.logger = (0, get_default_logger_1.getDefaultLogger)(); } this.logger.info(`[StaticCredentialsAuthService] Initialized for endpoint: ${this.endpoint}`); if (options === null || options === void 0 ? void 0 : options.tokenRequestTimeout) this.tokenRequestTimeout = options.tokenRequestTimeout; if (options === null || options === void 0 ? void 0 : options.tokenExpirationTimeout) this.tokenRefreshInterval = options.tokenExpirationTimeout; if (options === null || options === void 0 ? void 0 : options.tokenRefreshInterval) this.tokenRefreshInterval = options.tokenRefreshInterval; if (this.tokenRefreshInterval) { let timer = setInterval(() => { if (this.promise) { this.logger.debug('[StaticCredentialsAuthService] Token refresh already in progress, skipping interval refresh.'); return; } this.logger.info('[StaticCredentialsAuthService] Periodic token refresh triggered.'); this.promise = this.updateToken() .then(token => (0, add_credentials_to_metadata_1.addCredentialsToMetadata)(token.value)) .finally(() => { this.promise = null; }); }, this.tokenRefreshInterval); timer.unref(); } } async sendTokenRequest() { this.logger.debug('[StaticCredentialsAuthService] Sending token request...'); let runtimeAuthService = new StaticCredentialsGrpcService(this.endpoint, this.sslCredentials, this.logger); const tokenPromise = runtimeAuthService.login({ user: this.user, password: this.password, }); const response = await (0, utils_1.withTimeout)(tokenPromise, this.tokenRequestTimeout); const result = AuthServiceResult.decode((0, process_ydb_operation_result_1.getOperationPayload)(response)); runtimeAuthService.destroy(); this.logger.debug('[StaticCredentialsAuthService] Token request completed.'); return result; } async updateToken() { this.logger.info('[StaticCredentialsAuthService] Updating token...'); const { token } = await this.sendTokenRequest(); if (!token) { this.logger.error('[StaticCredentialsAuthService] Received empty token from static credentials!'); throw new Error('Received empty token from static credentials!'); } // Parse the JWT token to extract expiration time const [, payload] = token.split('.'); const decodedPayload = JSON.parse(Buffer.from(payload, 'base64').toString()); this.token = Object.assign({ value: token }, decodedPayload); this.logger.info(`[StaticCredentialsAuthService] Token updated. Expires at: ${new Date(this.token.exp * 1000).toISOString()}`); return this.token; } async getAuthMetadata() { if (this.token && (this.token.exp - TOKEN_EXPIRY_MARGIN) > Date.now() / 1000) { return (0, add_credentials_to_metadata_1.addCredentialsToMetadata)(this.token.value); } if (this.promise) { return this.promise; } this.logger.info('[StaticCredentialsAuthService] Token expired or missing, refreshing...'); this.promise = this.updateToken() .then(token => (0, add_credentials_to_metadata_1.addCredentialsToMetadata)(token.value)) .finally(() => { this.promise = null; }); return this.promise; } } exports.StaticCredentialsAuthService = StaticCredentialsAuthService;