trm-core
Version:
TRM (Transport Request Manager) Core
400 lines (399 loc) • 17.2 kB
JavaScript
"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;