@sap-ux/system-access
Version:
Reusable module allowing to access systems using the store or prompts.
195 lines • 7.83 kB
JavaScript
import { AbapCloudEnvironment, createForAbapOnCloud, createForAbap, createForDestination } from '@sap-ux/axios-extension';
import { getCredentialsFromEnvVariables, getCredentialsFromStore, getCredentialsWithPrompts, isBasicAuth, isServiceAuth } from './credentials.js';
import { isAppStudio, listDestinations } from '@sap-ux/btp-utils';
import { questions } from './prompts.js';
import prompts from 'prompts';
import { readFileSync } from 'node:fs';
import { AuthenticationType } from '@sap-ux/store';
/**
* Check if it is a url target.
*
* @param target target configuration
* @returns true if it is a UrlAbapTarget
*/
export function isUrlTarget(target) {
return target.url !== undefined;
}
/**
* Check if it is a destination target.
*
* @param target target configuration
* @returns true if it is a DestinationAbapTarget
*/
export function isDestinationTarget(target) {
return target.destination !== undefined;
}
/**
* Enhance axios options and create a service provider instance for an ABAP Cloud system.
*
* @param options - predefined axios options
* @param target - url target configuration
* @param prompt - prompt the user for missing information
* @param logger - reference to the logger instance
* @returns an abap service provider
*/
async function createAbapCloudServiceProvider(options, target, prompt, logger) {
const providerConfig = {
...options,
environment: AbapCloudEnvironment.Standalone,
service: target.serviceKey
};
if (!providerConfig.service) {
// first try reading the keys from the store
const storedOpts = await getCredentialsFromStore(target, logger);
if (isServiceAuth(storedOpts)) {
providerConfig.service = storedOpts.serviceKeys;
providerConfig.refreshToken = storedOpts.refreshToken;
logger.info(`Using system [${storedOpts.name}] from System store`);
}
if (!providerConfig.service && prompt) {
const { path } = await prompts(questions.serviceKeysPath);
providerConfig.service = JSON.parse(readFileSync(path, 'utf-8'));
}
}
// if no keys are available throw and error
if (providerConfig.service) {
return createForAbapOnCloud(providerConfig);
}
else {
throw new Error('Service keys required for ABAP Cloud environment.');
}
}
/**
* Resolve and apply credentials for an on-premise ABAP target.
* Reads from store, env variables, or prompts the user as needed.
*
* @param options - predefined axios options (mutated if credentials are found)
* @param target - url target configuration (authenticationType may be set)
* @param prompt - prompt the user for missing information
* @param logger - reference to the logger instance
*/
async function resolveOnPremCredentials(options, target, prompt, logger) {
const storedOpts = await getCredentialsFromStore(target, logger);
if (isBasicAuth(storedOpts)) {
options.auth = {
username: storedOpts.username,
password: storedOpts.password
};
return;
}
if (isServiceAuth(storedOpts)) {
throw new Error('This is an ABAP Cloud system, please correct your configuration.');
}
options.auth ??= getCredentialsFromEnvVariables();
if (!options.auth && prompt) {
const { authType } = await prompts([questions.authType]);
if (authType === AuthenticationType.ReentranceTicket) {
target.authenticationType = AuthenticationType.ReentranceTicket;
}
else {
const credentials = await getCredentialsWithPrompts(storedOpts?.username);
options.auth = credentials;
process.env.FIORI_TOOLS_USER = credentials.username;
process.env.FIORI_TOOLS_PASSWORD = credentials.password;
}
}
}
/**
* Enhance axios options and create a service provider instance for an on-premise ABAP system.
*
* @param options predefined axios options
* @param target url target configuration
* @param prompt - prompt the user for missing information
* @param logger reference to the logger instance
* @returns an ABAPServiceProvider instance
*/
async function createAbapOnPremServiceProvider(options, target, prompt, logger) {
if (!options.auth) {
await resolveOnPremCredentials(options, target, prompt, logger);
}
return target.authenticationType === AuthenticationType.ReentranceTicket
? createForAbapOnCloud({
...options,
...target,
environment: AbapCloudEnvironment.EmbeddedSteampunk
})
: createForAbap(options);
}
/**
* Enhance axios options and create a service provider instance for a destination.
*
* @param options predefined axios options
* @param target url target configuration
* @param prompt - prompt the user for missing information
* @returns an ABAPServiceProvider instance
*/
async function createAbapDestinationServiceProvider(options, target, prompt) {
// Need additional properties to determine the type of destination we are dealing with
const destinations = await listDestinations();
const destination = destinations?.[target.destination];
if (!destination) {
throw new Error(`Destination ${target.destination} not found on subaccount`);
}
const provider = createForDestination(options, destination);
// if prompting is enabled, check if the destination works or basic auth is required
if (prompt) {
const id = provider.interceptors.response.use(undefined, async (error) => {
provider.interceptors.response.eject(id);
if (error.response?.status === 401) {
const credentials = await getCredentialsWithPrompts();
provider.defaults.auth = credentials;
process.env.FIORI_TOOLS_USER = credentials.username;
process.env.FIORI_TOOLS_PASSWORD = credentials.password;
return provider.request(error.config);
}
else {
throw error;
}
});
}
return provider;
}
/**
* Create an instance of an ABAP service provider connected to the given target configuration.
*
* @param target - target configuration
* @param requestOptions - additional AxiosRequestOptions
* @param prompt - prompt the user for missing information
* @param logger - optional reference to the logger instance
* @returns service instance
*/
export async function createAbapServiceProvider(target, requestOptions, prompt, logger) {
let provider;
const options = {
params: target.params ?? {},
...requestOptions
};
// Destination only supported in Business Application Studio
if (isAppStudio() && isDestinationTarget(target)) {
provider = await createAbapDestinationServiceProvider(options, target, prompt);
}
else if (isUrlTarget(target)) {
if (target.scp || target.serviceKey) {
provider = await createAbapCloudServiceProvider(options, target, prompt, logger);
}
else if (target.authenticationType === AuthenticationType.ReentranceTicket) {
provider = createForAbapOnCloud({
ignoreCertErrors: options.ignoreCertErrors,
environment: AbapCloudEnvironment.EmbeddedSteampunk,
...target
});
}
else {
options.baseURL = target.url;
if (target.client) {
options.params['sap-client'] = target.client;
}
provider = await createAbapOnPremServiceProvider(options, target, prompt, logger);
}
}
else {
throw new Error('Unable to handle the configuration in the current environment.');
}
return provider;
}
//# sourceMappingURL=connect.js.map