@sap/cli-core 2025.19.0 → 2025.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## 2025.23.0
9
+
10
+ ### Added
11
+
12
+ - Support for Node v23 and v24
13
+
14
+ ### Fixed
15
+
16
+ - Changed confirmation prompts to default to "no" instead of "yes" for safer handling of destructive operations.
17
+
18
+ ## 2025.20.0
19
+
20
+ ### Fixed
21
+
22
+ - Fixed ESM dynamic import issues on Windows by converting file paths to proper file URLs using `pathToFileURL()`.
23
+
8
24
  ## 2025.18.0
9
25
 
10
26
  ### Changed
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Command-Line Interface (CLI) Core Module.
4
4
 
5
- [![Node Version](https://img.shields.io/badge/node-20.xx.x-brightgreen)](https://nodejs.org/dist/latest-v20.x/docs/api/#) [![Node Version](https://img.shields.io/badge/node-21.xx.x-brightgreen)](https://nodejs.org/dist/latest-v21.x/docs/api/#) [![Node Version](https://img.shields.io/badge/node-22.xx.x-brightgreen)](https://nodejs.org/dist/latest-v22.x/docs/api/#) [![npm version](https://badge.fury.io/js/@sap%2Fcli-core.svg)](https://badge.fury.io/js/@sap%2Fcli-core)
5
+ [![Node Version](https://img.shields.io/badge/node-20.xx.x-brightgreen)](https://nodejs.org/dist/latest-v20.x/docs/api/#) [![Node Version](https://img.shields.io/badge/node-21.xx.x-brightgreen)](https://nodejs.org/dist/latest-v21.x/docs/api/#) [![Node Version](https://img.shields.io/badge/node-22.xx.x-brightgreen)](https://nodejs.org/dist/latest-v22.x/docs/api/#) [![Node Version](https://img.shields.io/badge/node-23.xx.x-brightgreen)](https://nodejs.org/dist/latest-v23.x/docs/api/#) [![Node Version](https://img.shields.io/badge/node-24.xx.x-brightgreen)](https://nodejs.org/dist/latest-v24.x/docs/api/#) [![npm version](https://badge.fury.io/js/@sap%2Fcli-core.svg)](https://badge.fury.io/js/@sap%2Fcli-core)
6
6
 
7
7
  ## Content
8
8
 
@@ -2,7 +2,6 @@ import { OPTION_SECRETS_FILE } from "../../../constants.js";
2
2
  import { createNextHandler, createOptionsHandler, createParseArgumentsHandler, } from "../../handler/index.js";
3
3
  import { readSecretsFile } from "../../handler/authentication/oauth/secretsProvider/file.js";
4
4
  import { get } from "../../../logger/index.js";
5
- /* jscpd:ignore-end */
6
5
  const create = () => async () => async () => {
7
6
  const { output } = get("commands.secrets.check");
8
7
  await readSecretsFile();
@@ -1,7 +1,6 @@
1
1
  import { OPTION_HOST } from "../../../constants.js";
2
2
  import { createNextHandler, createOptionsHandler, createParseArgumentsHandler, createResilientHandler, } from "../../handler/index.js";
3
3
  import { create as createRefreshTokenHandler } from "../../handler/authentication/oauth/tokenProvider/refreshToken.js";
4
- /* jscpd:ignore-end */
5
4
  const refreshCommand = {
6
5
  type: "command",
7
6
  command: "refresh",
@@ -1,8 +1,6 @@
1
- /* jscpd:ignore-start */
2
1
  import { SecretsStorageSingleton } from "../../../cache/secrets/SecretsStorageSingleton.js";
3
2
  import { createNextHandler, createParseArgumentsHandler, createResilientHandler, } from "../../handler/index.js";
4
3
  import { create as createSecretsFromCacheProvider } from "../../handler/authentication/oauth/secretsProvider/cache.js";
5
- /* jscpd:ignore-end */
6
4
  const removeSecrets = async () => async () => {
7
5
  await SecretsStorageSingleton.SINGLETON.deleteAllSecrets();
8
6
  };
@@ -1,9 +1,7 @@
1
- /* jscpd:ignore-start */
2
1
  import { SecretsStorageSingleton } from "../../../cache/secrets/SecretsStorageSingleton.js";
3
2
  import { get as getLogger } from "../../../logger/index.js";
4
3
  import { createNextHandler, createParseArgumentsHandler, createResilientHandler, } from "../../handler/index.js";
5
4
  import { create as createSecretsFromCacheProvider } from "../../handler/authentication/oauth/secretsProvider/cache.js";
6
- /* jscpd:ignore-end */
7
5
  const showSecrets = async () => async () => {
8
6
  const { output, error } = getLogger("commands.secrets-show");
9
7
  try {
@@ -6,13 +6,10 @@ import { create as createCacheSecretsProvider } from "./oauth/secretsProvider/ca
6
6
  import { create as createRefreshTokenHandler } from "./oauth/tokenProvider/refreshToken.js";
7
7
  import { create as createSetAuthorizationHandler } from "./oauth/tokenProvider/setAuthorization.js";
8
8
  import { create as createPasscodeHandler } from "./passcode/index.js";
9
- import { create as createTechnicalJWTHandler } from "./technicalJWT/index.js";
10
9
  import { create as createOptionsHandler } from "../options/index.js";
11
10
  import { AuthenticationMethod, OPTION_ACCESS_TOKEN, OPTION_AUTHORIZATION_FLOW, OPTION_AUTHORIZATION_URL, OPTION_CLIENT_ID, OPTION_CLIENT_SECRET, OPTION_CODE, OPTION_PASSCODE, OPTION_REFRESH_TOKEN, OPTION_SECRETS_FILE, OPTION_TOKEN_URL, } from "../../../constants.js";
12
11
  import { getAuthenticationMethods } from "../../../config/core.js";
13
12
  import { create as createSucceedHandler } from "../succeed.js";
14
- export const create = process.env.SUPPORT === "true"
15
- ? createTechnicalJWTHandler
16
- : () => createNextHandler("commands.handler.authentication", createResilientHandler(createNextHandler("commands.handler.authentication$oauth", createCacheSecretsProvider(), createRefreshTokenHandler())), createOptionsHandler(OPTION_CLIENT_ID), createOptionsHandler(OPTION_CLIENT_SECRET), createOptionsHandler(OPTION_ACCESS_TOKEN), createOptionsHandler(OPTION_REFRESH_TOKEN), createOptionsHandler(OPTION_CODE), createOptionsHandler(OPTION_TOKEN_URL), createOptionsHandler(OPTION_AUTHORIZATION_URL), createOptionsHandler(OPTION_AUTHORIZATION_FLOW), getAuthenticationMethods().includes(AuthenticationMethod.passcode)
17
- ? createOptionsHandler(OPTION_PASSCODE)
18
- : createSucceedHandler(), createOptionsHandler(OPTION_SECRETS_FILE), createOrHandler("commands.handler.authentication$handler", createSetAuthorizationHandler(), createPasscodeHandler(), createOauthHandler()));
13
+ export const create = () => createNextHandler("commands.handler.authentication", createResilientHandler(createNextHandler("commands.handler.authentication$oauth", createCacheSecretsProvider(), createRefreshTokenHandler())), createOptionsHandler(OPTION_CLIENT_ID), createOptionsHandler(OPTION_CLIENT_SECRET), createOptionsHandler(OPTION_ACCESS_TOKEN), createOptionsHandler(OPTION_REFRESH_TOKEN), createOptionsHandler(OPTION_CODE), createOptionsHandler(OPTION_TOKEN_URL), createOptionsHandler(OPTION_AUTHORIZATION_URL), createOptionsHandler(OPTION_AUTHORIZATION_FLOW), getAuthenticationMethods().includes(AuthenticationMethod.passcode)
14
+ ? createOptionsHandler(OPTION_PASSCODE)
15
+ : createSucceedHandler(), createOptionsHandler(OPTION_SECRETS_FILE), createOrHandler("commands.handler.authentication$handler", createSetAuthorizationHandler(), createPasscodeHandler(), createOauthHandler()));
@@ -6,7 +6,6 @@ import { create as createTokenProvider } from "./tokenProvider/index.js";
6
6
  import { create as createCheckOptionsExistence } from "../../checkOptionsExistence.js";
7
7
  import { AuthenticationMethod, OPTION_PASSCODE, } from "../../../../constants.js";
8
8
  import { getAuthenticationMethods } from "../../../../config/core.js";
9
- /* jscpd:ignore-end */
10
9
  export const create = () => {
11
10
  if (getAuthenticationMethods().includes(AuthenticationMethod.oauth)) {
12
11
  return createErrorHandler("failed to handle OAuth authorization", createNextHandler("commands.handler.authentication.oauth", createCheckOptionsExistence(OPTION_PASSCODE), createSecretsProvider(), createTokenProvider()));
@@ -1,10 +1,7 @@
1
1
  import { set, get } from "../../../../config/index.js";
2
- import { CONFIG_PASSCODE_FUNCTION, OPTION_PASSCODE,
3
- /* jscpd:ignore-start */
4
- } from "../../../../constants.js";
2
+ import { CONFIG_PASSCODE_FUNCTION, OPTION_PASSCODE, } from "../../../../constants.js";
5
3
  export const create = () => async () => async () => {
6
4
  const config = get();
7
- /* jscpd:ignore-end */
8
5
  if (!config[CONFIG_PASSCODE_FUNCTION] ||
9
6
  typeof config[CONFIG_PASSCODE_FUNCTION] !== "function") {
10
7
  throw new Error("passcode function not available from configuration or provided argument is no function");
@@ -7,7 +7,6 @@ import { create as createFunctionHandler } from "./function.js";
7
7
  import { create as createSetPasscodeHandler } from "./setPasscode.js";
8
8
  import { AuthenticationMethod, OPTION_ACCESS_TOKEN, OPTION_CLIENT_ID, OPTION_SECRETS_FILE, } from "../../../../constants.js";
9
9
  import { getAuthenticationMethods } from "../../../../config/core.js";
10
- /* jscpd:ignore-end */
11
10
  export const create = () => {
12
11
  if (getAuthenticationMethods().includes(AuthenticationMethod.passcode)) {
13
12
  return createNextHandler("commands.handler.authentication.passcode", createCheckOptionsExistence(OPTION_CLIENT_ID), createCheckOptionsExistence(OPTION_ACCESS_TOKEN), createCheckOptionsExistence(OPTION_SECRETS_FILE), createOrHandler("commands.handler.authentication.passcode$value", createFunctionHandler(), createInputHandler()), createSetPasscodeHandler());
@@ -13,7 +13,7 @@ export const create = (message) => createOptionsHandler([
13
13
  required: true,
14
14
  prompts: {
15
15
  type: "confirm",
16
- initial: true,
16
+ initial: false,
17
17
  message: () => {
18
18
  const config = getConfig();
19
19
  let intMessage = message.replace(PARAM_REGEX, replacer);
@@ -19,4 +19,3 @@ const nextHandler = (origin, ...handlers) => async (command) => {
19
19
  };
20
20
  };
21
21
  export const create = (origin, ...handlers) => createStackTraceHandler(nextHandler(origin, ...handlers));
22
- /* jscpd:ignore-end */
package/config/core.js CHANGED
@@ -1,6 +1,4 @@
1
- /* jscpd:ignore-start */
2
1
  import { CLI_DEPRECATED, CLI_DEPRECATION_MESSAGE, CLI_DESCRIPTION, CLI_DISCOVERY_PATHS, CLI_GENERIC_OPTIONS_HELP, CLI_NAME, CLI_PACKAGE_NAME, CLI_SAP_HELP, CLI_SUPPORTED_AUTHENTICATION_METHODS, CLI_VERSION, } from "../constants.js";
3
- /* jscpd:ignore-end */
4
2
  import { get } from "./index.js";
5
3
  export const getName = () => get()[CLI_NAME];
6
4
  export const getPackageName = () => get()[CLI_PACKAGE_NAME];
package/dwc/utils.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { satisfies } from "compare-versions";
2
2
  import fs from "fs-extra";
3
3
  import path from "path";
4
+ import { pathToFileURL } from "url";
4
5
  import { getPackageName } from "../config/core.js";
5
6
  import { checkVersion as check, compareEtags as compare, } from "../discovery/index.js";
6
7
  import { get } from "../logger/index.js";
@@ -32,7 +33,7 @@ export const addCommandsFromFolder = async (pathToFolder, program) => {
32
33
  })).filter((f) => f.includes(".command") && !f.endsWith(".d.ts"))) {
33
34
  try {
34
35
  const importPath = await resolveCommandIndex(pathToFolder, file);
35
- const content = await import(importPath);
36
+ const content = await import(pathToFileURL(importPath).href);
36
37
  if (content.addCommands) {
37
38
  debug("adding commands from file %s.addCommands", file);
38
39
  await content.addCommands(program);
package/index.js CHANGED
@@ -1,9 +1,7 @@
1
1
  import * as dotenv from "dotenv";
2
2
  import { configureLoggers } from "./configureLoggers.js";
3
3
  import { set } from "./config/index.js";
4
- /* jscpd:ignore-start */
5
4
  import { AuthenticationMethod, CLI_DEPRECATED, CLI_DEPRECATION_MESSAGE, CLI_DESCRIPTION, CLI_DISCOVERY_PATHS, CLI_GENERIC_OPTIONS_HELP, CLI_NAME, CLI_PACKAGE_NAME, CLI_SAP_HELP, CLI_SUPPORTED_AUTHENTICATION_METHODS, CLI_VERSION, } from "./constants.js";
6
- /* jscpd:ignore-end */
7
5
  export { run } from "./dwc/run.js";
8
6
  export { configure, getCommands } from "./module.js";
9
7
  export { AuthenticationMethod };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/cli-core",
3
- "version": "2025.19.0",
3
+ "version": "2025.23.0",
4
4
  "description": "Command-Line Interface (CLI) Core Module",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "SAP SE",
@@ -8,8 +8,8 @@
8
8
  "homepage": "https://www.sap.com",
9
9
  "main": "index.js",
10
10
  "engines": {
11
- "node": "^20 || ^21 || ^22",
12
- "npm": "^9 || ^10"
11
+ "node": "^20 || ^21 || ^22 || ^23 || ^24",
12
+ "npm": "^9 || ^10 || ^11"
13
13
  },
14
14
  "keywords": [
15
15
  "cli",
@@ -19,13 +19,13 @@
19
19
  ],
20
20
  "dependencies": {
21
21
  "ajv": "8.17.1",
22
- "axios": "1.11.0",
22
+ "axios": "1.12.2",
23
23
  "commander": "12.1.0",
24
24
  "compare-versions": "6.1.1",
25
25
  "config": "4.1.1",
26
- "dotenv": "17.2.1",
26
+ "dotenv": "17.2.3",
27
27
  "form-data": "4.0.4",
28
- "fs-extra": "11.3.1",
28
+ "fs-extra": "11.3.2",
29
29
  "https": "1.0.0",
30
30
  "https-proxy-agent": "7.0.6",
31
31
  "jszip": "3.10.1",
@@ -1,4 +0,0 @@
1
- export function searchAllApps(names: any, targetOrg: any, targetSpace: any): any;
2
- export function getServiceKey(serviceName: any, serviceKeyName: any): Promise<any>;
3
- export function getEnv(names: any, targetOrg: any, targetSpace: any): any;
4
- export function getCurrentTarget(): any;
@@ -1,131 +0,0 @@
1
- import * as exec from "./exec.js";
2
- var getResults = exec.getResults;
3
- export function searchAllApps(names, targetOrg, targetSpace) {
4
- var nextUrl = "/v3/apps?names=" + names.join(",");
5
- var fnFetchPage = function () {
6
- return exec.cf(["curl", nextUrl], getResults);
7
- };
8
- var res = [];
9
- var fnSearchPage = function () {
10
- return fnFetchPage().then((apps) => {
11
- try {
12
- apps = JSON.parse(apps);
13
- }
14
- catch (e) {
15
- console.error("Failed to parse the following body:");
16
- console.error(apps);
17
- throw e;
18
- }
19
- if (apps.errors) {
20
- console.error(apps.errors[0]);
21
- throw apps.errors[0];
22
- }
23
- for (const curResource of apps.resources) {
24
- var resIndex = names.indexOf(curResource.name);
25
- if (resIndex > -1) {
26
- res[resIndex] = curResource;
27
- for (var x = 0; x < names.length; x++) {
28
- if (!res[x]) {
29
- break;
30
- }
31
- if (x === names.length - 1) {
32
- return Promise.resolve();
33
- }
34
- }
35
- }
36
- }
37
- if (apps.pagination &&
38
- apps.pagination.next &&
39
- apps.pagination.next.href) {
40
- nextUrl = "/v3/" + apps.pagination.next.href.split("/v3/")[1];
41
- }
42
- else {
43
- return Promise.resolve();
44
- }
45
- return fnSearchPage();
46
- });
47
- };
48
- return exec
49
- .cf(["curl", "/v3/organizations?names=" + targetOrg], getResults)
50
- .then((orgs) => {
51
- orgs = JSON.parse(orgs);
52
- var orgGuid = orgs.resources && orgs.resources[0] && orgs.resources[0].guid;
53
- nextUrl = nextUrl + "&organization_guids=" + orgGuid;
54
- return exec.cf([
55
- "curl",
56
- "/v3/spaces?organization_guids=" + orgGuid + "&names=" + targetSpace,
57
- ], getResults);
58
- })
59
- .then((spaces) => {
60
- spaces = JSON.parse(spaces);
61
- var spaceGuid = spaces.resources && spaces.resources[0] && spaces.resources[0].guid;
62
- nextUrl = nextUrl + "&space_guids=" + spaceGuid;
63
- })
64
- .then(() => fnSearchPage())
65
- .then(() => res);
66
- }
67
- export function getServiceKey(serviceName, serviceKeyName) {
68
- function resourceFromPagination(cfResult) {
69
- if (!cfResult || cfResult.length === 0) {
70
- return [];
71
- }
72
- const oResult = JSON.parse(cfResult);
73
- if (oResult.pagination["total_results"] > 0) {
74
- return oResult.resources;
75
- }
76
- return [];
77
- }
78
- return Promise.all([
79
- exec
80
- .cf(["curl", `/v3/service_instances?names=${serviceName}`], getResults)
81
- .then((result) => resourceFromPagination(result))
82
- .catch((err) => console.error(err.message)),
83
- exec
84
- .cf(["curl", `/v3/service_credential_bindings?names=${serviceKeyName}`], getResults)
85
- .then((result) => resourceFromPagination(result))
86
- .catch((err) => console.error(err.message)),
87
- ])
88
- .then((result) => {
89
- var serviceGuid = result[0][0].guid;
90
- var credKeys = result[1];
91
- if (!serviceGuid || credKeys.length === 0) {
92
- return null;
93
- }
94
- var serviceKey = credKeys.filter((key) => key.relationships["service_instance"].data.guid === serviceGuid);
95
- if (serviceKey.length === 0) {
96
- return null;
97
- }
98
- return exec
99
- .cf([
100
- "curl",
101
- `/v3/service_credential_bindings/${serviceKey[0].guid}/details`,
102
- ], getResults)
103
- .then((details) => JSON.parse(details));
104
- })
105
- .catch((err) => console.error(`Failed to fetch service key ${serviceKeyName}. ${err}`));
106
- }
107
- export function getEnv(names, targetOrg, targetSpace) {
108
- if (!Array.isArray(names)) {
109
- names = [names];
110
- }
111
- return module.exports
112
- .searchAllApps(names, targetOrg, targetSpace)
113
- .then((apps) => Promise.all(apps.map((a) => exec.cf(["curl", `/v3/apps/${a.guid}/env`], getResults))));
114
- }
115
- export function getCurrentTarget() {
116
- return exec.cf(["t"], getResults).then((result) => {
117
- var json = result
118
- .replace(/ /g, "")
119
- .split("\n")
120
- .map((l) => {
121
- var i = l.indexOf(":");
122
- if (i < 0) {
123
- return l;
124
- }
125
- return '"' + l.substring(0, i) + '":"' + l.substring(i + 1) + '"';
126
- });
127
- json.pop();
128
- json = "{" + json.join(",\n") + "}";
129
- return JSON.parse(json);
130
- });
131
- }
@@ -1,8 +0,0 @@
1
- export function exec(cmd: any, args: any, options: any): Promise<any>;
2
- export function kill(): Promise<any[]>;
3
- export namespace getResults {
4
- let stdio: (string | number)[];
5
- }
6
- export function cf(args: any, options: any): any;
7
- export function npm(args: any, options: any): any;
8
- export function git(args: any, options: any): Promise<any>;
@@ -1,192 +0,0 @@
1
- import * as jsZip from "jszip";
2
- import * as childProcess from "child_process";
3
- import * as path from "path";
4
- import * as http from "https";
5
- import * as fs from "fs-extra";
6
- process.on("message", (m) => {
7
- if (m.kill) {
8
- module.exports.kill().then(() => {
9
- process.send({ killed: true });
10
- });
11
- }
12
- });
13
- // Define exec
14
- var processes = {};
15
- var killCallbacks = {};
16
- export var exec = function (cmd, args, options) {
17
- options = options || {};
18
- options.stdio = options.stdio || [0, 1, 2];
19
- options.cwd = options.cwd || path.resolve(import.meta.dirname);
20
- console.log("Executing command: " + cmd + " " + args.join(" "));
21
- return new Promise((resolve, reject) => {
22
- var output = [];
23
- var proc = childProcess.spawn(cmd, args, options);
24
- processes[proc.pid] = proc;
25
- if (proc.stdout) {
26
- proc.stdout.on("data", (chunk) => {
27
- output.push(`${chunk}`);
28
- });
29
- }
30
- proc.on("error", reject);
31
- proc.on("exit", (code, signal) => {
32
- if (processes[proc.pid] === proc) {
33
- delete processes[proc.pid];
34
- }
35
- if (typeof killCallbacks[proc.pid] === "function") {
36
- console.log("Killed process: " + proc.spawnargs.join(" "));
37
- return killCallbacks[proc.pid]();
38
- }
39
- if (code !== 0) {
40
- return reject(new Error("Failed command: " +
41
- cmd +
42
- " " +
43
- args.join(" ") +
44
- ` (exited ${code})`));
45
- }
46
- return resolve(output.join(""));
47
- });
48
- });
49
- };
50
- export var kill = function () {
51
- var pids = Object.keys(processes);
52
- var proms = [];
53
- for (const pid of pids) {
54
- var curProc = processes[pid];
55
- if (!curProc.iskilled) {
56
- proms.push(
57
- // NOSONAR
58
- new Promise((resolve) => {
59
- setTimeout(resolve, 30 * 1000);
60
- killCallbacks[curProc.pid] = resolve;
61
- console.log("Killing process: " + curProc.spawnargs.join(" "));
62
- curProc.kill();
63
- }));
64
- }
65
- }
66
- return Promise.all(proms);
67
- };
68
- export const getResults = { stdio: [0, "pipe", 2] };
69
- // Define cf
70
- var cfReady;
71
- var cfCmd = "cf";
72
- process.env.CF_DEBUG = "1";
73
- var internalMessaging = process.env.CF_DEBUG === "1" ? "inherit" : "ignore";
74
- var checkCF = function () {
75
- var win = process.platform === "win32";
76
- var mac = process.platform === "darwin";
77
- var plat = win ? "windows64-exe" : mac ? "macosx64-binary" : "linux64-binary";
78
- var tmpFolder = path.resolve(import.meta.dirname, "../.tmp/cf");
79
- var cfZipFile = path.resolve(tmpFolder, "client.zip");
80
- var cfExeFile = path.resolve(tmpFolder, "cf.exe");
81
- var cfBinFile = path.resolve(tmpFolder, "cf");
82
- var downloadLink = `https://packages.cloudfoundry.org/stable?release=${plat}&source=github`;
83
- if (cfReady) {
84
- return cfReady;
85
- }
86
- cfReady = exec("cf", ["version"], { stdio: internalMessaging })
87
- .then(() => {
88
- console.log("Using global cf client");
89
- cfCmd = "cf";
90
- })
91
- .catch(() => {
92
- // TODO: enable local cf client after downloading
93
- return (fs
94
- .ensureDir(tmpFolder)
95
- .then(() => fs.exists(cfZipFile))
96
- .then((exists) => {
97
- if (exists) {
98
- return;
99
- }
100
- return new Promise((resolve, reject) => {
101
- console.log(`Downloading cf client for platform ${plat}`);
102
- console.log(downloadLink);
103
- var file = fs.createWriteStream(cfZipFile, { mode: 777 });
104
- var fnDownload = function (url) {
105
- http.get(url, (res, err) => {
106
- if (err) {
107
- return reject(err);
108
- }
109
- if (res.statusCode === 302 &&
110
- res.headers &&
111
- res.headers.location) {
112
- return fnDownload(res.headers.location);
113
- }
114
- res.pipe(file).on("finish", resolve);
115
- });
116
- };
117
- fnDownload(downloadLink);
118
- }).then(() => console.log("Downloading cf client Finished ..."));
119
- })
120
- // Unzip
121
- .then(() => {
122
- if (win) {
123
- console.log("Unzipping cf client");
124
- return fs
125
- .readFile(cfZipFile)
126
- .then((data) => {
127
- // NOSONAR we're dealing with cf and we're pretty sure nobody messes it up
128
- return jsZip.loadAsync(data);
129
- })
130
- .then((zip) => {
131
- var prom = [];
132
- Object.keys(zip.files).forEach((filename) => {
133
- if (zip.files[filename].dir) {
134
- return;
135
- }
136
- prom.push(zip.files[filename]
137
- .async("nodebuffer")
138
- .then((fileData) => {
139
- let dest = path.resolve(tmpFolder, filename);
140
- return fs.outputFile(dest, fileData);
141
- }));
142
- });
143
- return Promise.all(prom)
144
- .then(() => console.log("Unzipping cf client finished"))
145
- .then(() => {
146
- cfCmd = cfExeFile;
147
- });
148
- });
149
- }
150
- else {
151
- // Could be done with node as well
152
- // TODO: test for linux and mac os
153
- console.log("Unzipping cf client");
154
- console.log(cfZipFile);
155
- return exec("tar", ["-xf", cfZipFile, "-C", tmpFolder])
156
- .then(() => console.log("Unzipping cf client finished"))
157
- .then(() => {
158
- cfCmd = cfBinFile;
159
- });
160
- }
161
- }));
162
- })
163
- .then(() => {
164
- // This is expected
165
- });
166
- return cfReady;
167
- };
168
- var execCF = function (args, options) {
169
- return checkCF().then(() => exec(cfCmd, args, options));
170
- };
171
- export const cf = execCF;
172
- // Define npm
173
- var execNpm = function (args, options) {
174
- if (typeof args === "string") {
175
- return execNpmRun(args);
176
- }
177
- var cmd = process.platform === "win32" ? "npm.cmd" : "npm";
178
- options = options || {};
179
- options.cwd = options.cwd || path.resolve(import.meta.dirname, "..");
180
- return exec(cmd, args, options);
181
- };
182
- var execNpmRun = function (script) {
183
- return execNpm(["run", script], { cwd: path.resolve(import.meta.dirname, "..") });
184
- };
185
- export const npm = execNpm;
186
- // Define git
187
- var execGit = function (args, options) {
188
- options = options || {};
189
- options.stdio = options.stdio || ["pipe", 1, 2];
190
- return exec("git", args, options);
191
- };
192
- export const git = execGit;
@@ -1,2 +0,0 @@
1
- import { Handler } from "../../../../types.js";
2
- export declare const create: () => Handler;
@@ -1,11 +0,0 @@
1
- import { set as setConfig } from "../../../../config/index.js";
2
- import { buildOption } from "../../../../utils/commands.js";
3
- import { OPTION_SECRET } from "./types.js";
4
- import { getTechnicalJwt } from "./utils.js";
5
- export const create = () => async (command) => {
6
- command.addOption(await buildOption(command, OPTION_SECRET));
7
- return async () => {
8
- const token = await getTechnicalJwt();
9
- setConfig({ authorization: { Authorization: `Bearer ${token}` } });
10
- };
11
- };
@@ -1,2 +0,0 @@
1
- import { Option } from "../../../../types.js";
2
- export declare const OPTION_SECRET: Option;
@@ -1,5 +0,0 @@
1
- export const OPTION_SECRET = {
2
- longName: "secret",
3
- description: "specifies the path to the secret file",
4
- args: [{ name: "secret" }],
5
- };
@@ -1 +0,0 @@
1
- export declare const getTechnicalJwt: () => Promise<string>;
@@ -1,64 +0,0 @@
1
- import path from "path";
2
- import { URLSearchParams } from "url";
3
- import fs from "fs-extra";
4
- // eslint-disable-next-line import/extensions
5
- import * as cf from "./cf.js";
6
- import { get as getConfig } from "../../../../config/index.js";
7
- import { get } from "../../../../logger/index.js";
8
- import { fetch } from "../../../../utils/http/index.js";
9
- import { OPTION_SECRET } from "./types.js";
10
- import { GrantType } from "../../../../types.js";
11
- const getLogger = () => get("commands.handler.authentication.technicalJWT.utils");
12
- const APPNAME_GLOBAL = "dwaas-core";
13
- const getSecret = async () => {
14
- const { trace } = getLogger();
15
- const config = getConfig();
16
- const secretsFile = config.options[OPTION_SECRET.longName] ||
17
- path.join(process.cwd(), ".secret.json");
18
- trace("reading secret from", secretsFile);
19
- if (fs.existsSync(secretsFile)) {
20
- const content = await fs.readFile(secretsFile, "utf8");
21
- return JSON.parse(content);
22
- }
23
- const currentTarget = await cf.getCurrentTarget();
24
- let [env] = await cf.getEnv(APPNAME_GLOBAL, currentTarget.org, currentTarget.space);
25
- env = JSON.parse(env);
26
- const vcap = Object.keys(env)
27
- .map((k) => env[k].VCAP_SERVICES)
28
- .find((v) => v);
29
- const url = Object.keys(env)
30
- .map((k) => env[k].VCAP_APPLICATION)
31
- .find((v) => v && v.uris && v.uris[0]).uris[0];
32
- if (!vcap || !vcap.xsuaa) {
33
- throw new Error("The target application is missing a uaa binding.");
34
- }
35
- const uaa = vcap.xsuaa.find((v) => v.credentials);
36
- if (!uaa) {
37
- throw new Error("The target application is missing a uaa binding with credentials.");
38
- }
39
- return {
40
- url: `https://${url}`,
41
- uaaUrl: uaa.credentials.url,
42
- clientid: uaa.credentials.clientid,
43
- clientsecret: uaa.credentials.clientsecret,
44
- tenantid: uaa.credentials.tenantid,
45
- };
46
- };
47
- export const getTechnicalJwt = async () => {
48
- const secret = await getSecret();
49
- const { data } = await fetch({
50
- method: "POST",
51
- url: `${secret.uaaUrl}/oauth/token`,
52
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
53
- data: new URLSearchParams({
54
- grant_type: GrantType.client_credentials,
55
- response_type: "token",
56
- client_id: secret.clientid,
57
- client_secret: secret.clientsecret,
58
- }).toString(),
59
- });
60
- if (!data.access_token) {
61
- throw new Error("No token could be retrieved from the application.");
62
- }
63
- return data.access_token;
64
- };