UNPKG

trm-core

Version:

TRM (Transport Request Manager) Core

400 lines (399 loc) 17.2 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Registry = exports.PUBLIC_RESERVED_KEYWORD = void 0; const RegistryType_1 = require("./RegistryType"); const normalize_url_1 = __importDefault(require("@esm2cjs/normalize-url")); const axios_1 = require("axios"); const trm_registry_types_1 = require("trm-registry-types"); const TrmArtifact_1 = require("../trmPackage/TrmArtifact"); const FormData = __importStar(require("form-data")); const logger_1 = require("../logger"); const crypto_1 = require("crypto"); const protocol_1 = require("../protocol"); const opener_1 = __importDefault(require("opener")); const Inquirer_1 = require("../inquirer/Inquirer"); const commons_1 = require("../commons"); const AXIOS_CTX = "Registry"; exports.PUBLIC_RESERVED_KEYWORD = 'public'; class Registry { constructor(endpoint, name = 'Unknown') { this.endpoint = endpoint; this.name = name; var envEndpoint = process.env.TRM_PUBLIC_REGISTRY_ENDPOINT; logger_1.Logger.log(`TRM_PUBLIC_REGISTRY_ENDPOINT Environment variable: ${envEndpoint}`, true); if (!envEndpoint || envEndpoint.trim().toLowerCase() === exports.PUBLIC_RESERVED_KEYWORD) { envEndpoint = 'https://www.trmregistry.com/registry'; } if (endpoint.trim().toLowerCase() === exports.PUBLIC_RESERVED_KEYWORD) { this._registryType = RegistryType_1.RegistryType.PUBLIC; } else { this._registryType = RegistryType_1.RegistryType.PRIVATE; } if (this._registryType === RegistryType_1.RegistryType.PUBLIC) { this.endpoint = envEndpoint; this.name = exports.PUBLIC_RESERVED_KEYWORD; } else { this.endpoint = endpoint; } logger_1.Logger.log(`Endpoint type: ${this._registryType}`, true); logger_1.Logger.log(`Endpoint before normalize: ${this.endpoint}`, true); this.endpoint = (0, normalize_url_1.default)(this.endpoint, { stripHash: true, removeQueryParameters: true }); logger_1.Logger.log(`Endpoint after normalize: ${this.endpoint}`, true); if (this.endpoint.length > 100) { throw new Error(`Registry address length is too long! Maximum allowed is 100.`); } this._axiosInstance = (0, commons_1.getAxiosInstance)({ baseURL: this.endpoint }, AXIOS_CTX); } getRegistryType() { return this._registryType; } authenticate() { return __awaiter(this, arguments, void 0, function* (defaultData = {}) { logger_1.Logger.log(`Registry authentication request`, true); const ping = yield this.ping(); logger_1.Logger.log(`Registry authentication type is: ${ping.authenticationType}`, true); if (ping.authenticationType !== trm_registry_types_1.AuthenticationType.NO_AUTH) { if (ping.authenticationType === trm_registry_types_1.AuthenticationType.BASIC) { yield this._basicAuth(defaultData); } if (ping.authenticationType === trm_registry_types_1.AuthenticationType.OAUTH2) { yield this._oauth2(defaultData); } if (ping.authenticationType === trm_registry_types_1.AuthenticationType.TOKEN) { yield this._tokenAuth(defaultData); } } this._whoami = null; return this; }); } _basicAuth() { return __awaiter(this, arguments, void 0, function* (defaultData = {}) { var axiosHeaders = new axios_1.AxiosHeaders(); var axiosDefaults = { baseURL: this.endpoint, headers: axiosHeaders }; var username = defaultData.username; var password = defaultData.password; const inq1 = yield Inquirer_1.Inquirer.prompt([{ type: "input", name: "username", message: "Registry username", validate: (input) => { return input ? true : false; }, when: !username }, { type: "password", name: "password", message: "Registry password", validate: (input) => { return input ? true : false; }, when: !password }]); username = username || inq1.username; password = password || inq1.password; const basicAuth = `${username}:${password}`; const encodedBasicAuth = Buffer.from(basicAuth).toString('base64'); axiosHeaders.setAuthorization(`Basic ${encodedBasicAuth}`); this._axiosInstance = (0, commons_1.getAxiosInstance)(axiosDefaults, AXIOS_CTX); this._authData = { username, password }; }); } _tokenAuth() { return __awaiter(this, arguments, void 0, function* (defaultData = {}) { var axiosHeaders = new axios_1.AxiosHeaders(); var axiosDefaults = { baseURL: this.endpoint, headers: axiosHeaders }; var token = defaultData.token; if (!token && this._registryType == RegistryType_1.RegistryType.PUBLIC) { logger_1.Logger.info(`To authenticate, generate a new token.`); logger_1.Logger.info(`Follow the instructions https://docs.trmregistry.com/#/registry/public/authentication.`); } const inq1 = yield Inquirer_1.Inquirer.prompt([{ type: "input", name: "token", message: "Registry token", validate: (input) => { return input ? true : false; }, when: !token }]); token = token || inq1.token; axiosHeaders.setAuthorization(`token ${token}`); this._axiosInstance = (0, commons_1.getAxiosInstance)(axiosDefaults, AXIOS_CTX); this._authData = { token }; }); } _oauth2() { return __awaiter(this, arguments, void 0, function* (defaultData = {}) { const ping = yield this.ping(); var runAuthFlow = false; const accessToken = defaultData.access_token; const refreshToken = defaultData.refresh_token; const tokenExpiry = defaultData.expires_in; const accessTokenTimestamp = defaultData.access_token_timestamp; const currentDate = new Date(); var authData; var oAuth2Request; var oAuth2Response; if (accessToken && accessTokenTimestamp && tokenExpiry) { try { const tokenDate = new Date(accessTokenTimestamp); const elapsedSeconds = (currentDate.getTime() - tokenDate.getTime()) / 1000; if (elapsedSeconds >= parseInt(tokenExpiry)) { if (refreshToken) { oAuth2Request = { grant_type: "refresh_token", refresh_token: refreshToken }; oAuth2Response = (yield ((0, commons_1.getAxiosInstance)({ baseURL: this.endpoint }, AXIOS_CTX)).post('/auth', oAuth2Request)).data; runAuthFlow = false; authData = { access_token: oAuth2Response.access_token, expires_in: oAuth2Response.expires_in, refresh_token: refreshToken, access_token_timestamp: currentDate.getTime() }; } else { runAuthFlow = true; } } else { runAuthFlow = false; authData = { access_token: accessToken, expires_in: tokenExpiry, refresh_token: refreshToken, access_token_timestamp: accessTokenTimestamp }; } } catch (e) { runAuthFlow = true; } } else { runAuthFlow = true; } if (runAuthFlow) { const oAuth2 = ping.authenticationData; const oAuth2ProtocolPath = "//oauth2"; const sRedirectUri = `trm:${oAuth2ProtocolPath}`; const oAuth2Url = new URL(oAuth2.authorizationUrl); const oAuth2State = (0, crypto_1.randomUUID)(); oAuth2Url.searchParams.append("client_id", oAuth2.clientId); oAuth2Url.searchParams.append("response_type", oAuth2.responseType); oAuth2Url.searchParams.append("redirect_uri", sRedirectUri); oAuth2Url.searchParams.append("state", oAuth2State); var sAuth2Url = oAuth2Url.toString(); if (oAuth2.scope) { sAuth2Url = `${sAuth2Url}&scope=${oAuth2.scope}`; } logger_1.Logger.info(`Open login url at ${sAuth2Url}`); (0, opener_1.default)(sAuth2Url); const oAuth2Callback = yield new protocol_1.Protocol().run(); if (oAuth2Callback.path.startsWith(sRedirectUri)) { if (oAuth2Callback.parameters.state != oAuth2State) { throw new Error("Different state received in callback."); } oAuth2Request = { code: oAuth2Callback.parameters.code, grant_type: "authorization_code", redirect_uri: sRedirectUri }; oAuth2Response = (yield ((0, commons_1.getAxiosInstance)({ baseURL: this.endpoint }, AXIOS_CTX)).post('/auth', oAuth2Request)).data; if (oAuth2Response.token_type !== "Bearer") { throw new Error('Unknown token type.'); } authData = { access_token: oAuth2Response.access_token, expires_in: oAuth2Response.expires_in, refresh_token: oAuth2Response.refresh_token, access_token_timestamp: currentDate.getTime() }; } else { throw new Error("Callback received on a different uri."); } } this._authData = authData; var axiosHeaders = new axios_1.AxiosHeaders(); var axiosDefaults = { baseURL: this.endpoint, headers: axiosHeaders }; axiosHeaders.setAuthorization(`Bearer ${this._authData.access_token}`); this._axiosInstance = (0, commons_1.getAxiosInstance)(axiosDefaults, AXIOS_CTX); }); } getAuthData() { return this._authData; } ping() { return __awaiter(this, void 0, void 0, function* () { if (!this._ping) { try { this._ping = (yield this._axiosInstance.get('/')).data; } catch (e) { throw new Error('Registry cannot be reached.'); } } return this._ping; }); } whoAmI() { return __awaiter(this, void 0, void 0, function* () { if (!this._whoami) { this._whoami = (yield this._axiosInstance.get('/whoami')).data; } return this._whoami; }); } packageExists(name, version) { return __awaiter(this, void 0, void 0, function* () { var responseStatus; try { responseStatus = (yield this._axiosInstance.get('/view', { params: { name, version } })).status; } catch (e) { responseStatus = 404; } return responseStatus === 200; }); } view(name_1) { return __awaiter(this, arguments, void 0, function* (name, version = 'latest') { const response = (yield this._axiosInstance.get('/view', { params: { name, version } })).data; return response; }); } getArtifact(name_1) { return __awaiter(this, arguments, void 0, function* (name, version = 'latest') { const response = (yield this._axiosInstance.get('/install', { params: { name, version }, headers: { 'Accept': 'application/octet-stream' }, responseType: 'arraybuffer' })).data; return new TrmArtifact_1.TrmArtifact(response); }); } publishArtifact(packageName, version, artifact, readme) { return __awaiter(this, void 0, void 0, function* () { const fileName = `${packageName}@${version}`.replace('.', '_') + '.trm'; const formData = new FormData.default(); formData.append('artifact', artifact.binary, fileName); formData.append('readme', readme); yield this._axiosInstance.post('/publish', formData, { headers: formData.getHeaders() }); }); } unpublish(packageName, version) { return __awaiter(this, void 0, void 0, function* () { yield this._axiosInstance.post('/unpublish', { package: packageName, version }); }); } getReleases(packageName, versionRange) { return __awaiter(this, void 0, void 0, function* () { const response = (yield this._axiosInstance.get('/releases', { params: { name: packageName, version: versionRange } })).data; return response; }); } static compare(o1, o2) { const s1 = o1.endpoint; const s2 = o2.endpoint; return s1 === s2; } } exports.Registry = Registry;