@sap/cds-dk 6.0.4 → 6.1.3
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 +60 -1
- package/bin/add.js +29 -16
- package/bin/compile/index.js +7 -2
- package/bin/fix-redirects.js +4 -2
- package/bin/init.js +5 -0
- package/bin/login.js +20 -4
- package/bin/pull.js +58 -0
- package/bin/push.js +52 -0
- package/bin/subscribe.js +45 -0
- package/lib/bind/bindingUtil.js +1 -2
- package/lib/cds.js +2 -3
- package/lib/client/activate.js +17 -16
- package/lib/client/auth_manager.js +10 -5
- package/lib/client/base_command.js +4 -6
- package/lib/client/extend.js +3 -2
- package/lib/client/helper/cf_helper.js +1 -0
- package/lib/client/helper/errors.js +11 -0
- package/lib/client/helper/logging.js +3 -10
- package/lib/client/helper/url_helper.js +7 -3
- package/lib/client/index.js +1 -1
- package/lib/client/params.js +9 -6
- package/lib/client/pull.js +48 -0
- package/lib/client/push.js +45 -0
- package/lib/client/settings_manager.js +81 -27
- package/lib/compile/openapi/csdl2openapi.js +135 -163
- package/lib/compile/openapi/index.js +0 -1
- package/lib/import/common.js +9 -1
- package/lib/import/odata/metadataconverter/MetadataConverter.js +17 -4
- package/lib/import/odata/v2parser.js +50 -26
- package/lib/import/odata/v4parser.js +110 -29
- package/lib/import/openapi/importOpenAPI.js +3 -3
- package/lib/init/constants.js +9 -3
- package/lib/init/template/_merging/registry-mta.js +284 -0
- package/lib/init/template/approuter/files/xs-app.json.hbs +7 -7
- package/lib/init/template/approuter/index.js +22 -32
- package/lib/init/template/auditlog/index.js +7 -9
- package/lib/init/template/data/index.js +2 -4
- package/lib/init/template/extensibility/files/cds.package.json +7 -0
- package/lib/init/template/extensibility/files/cds.package.json.hbs +9 -0
- package/lib/init/template/extensibility/files/xs-security.json.hbs +26 -0
- package/lib/init/template/extensibility/index.js +48 -0
- package/lib/init/template/hana/files/java/cdsrc.json.hbs +1 -1
- package/lib/init/template/hana/files/java/profile.cdsrc.json.hbs +2 -2
- package/lib/init/template/hana/files/mta.yaml.hbs +10 -0
- package/lib/init/template/hana/files/nodejs/cds.package.json.hbs +1 -1
- package/lib/init/template/hana/files/nodejs/cds.profile.package.json.hbs +2 -2
- package/lib/init/template/hana/index.js +74 -61
- package/lib/init/template/kibana-logging/index.js +31 -37
- package/lib/init/template/lint/files/.eslint/rules/no-entity-moo.js +14 -14
- package/lib/init/template/mta/files/mta.yaml.hbs +1 -1
- package/lib/init/template/mta/index.js +13 -7
- package/lib/init/template/mtx/index.js +2 -142
- package/lib/init/template/multitenancy/files/cds.package.json +7 -0
- package/lib/init/template/multitenancy/files/cds.package.json.hbs +9 -0
- package/lib/init/template/{mtx → multitenancy}/files/dependencies.package.json +1 -1
- package/lib/init/template/multitenancy/files/java/.cdsrc.json +19 -0
- package/lib/init/template/multitenancy/files/java/package.json +31 -0
- package/lib/init/template/{mtx → multitenancy}/files/mta.yaml.hbs +13 -6
- package/lib/init/template/multitenancy/files/xs-security.json.hbs +18 -0
- package/lib/init/template/multitenancy/index.js +109 -0
- package/lib/init/template/nodejs/files/package.json.hbs +4 -1
- package/lib/init/template/templateBase.js +2 -1
- package/lib/init/template/toggles/files/cds.package.json +7 -0
- package/lib/init/template/toggles/files/cds.package.json.hbs +9 -0
- package/lib/init/template/toggles/index.js +24 -0
- package/lib/init/template/xsuaa/files/mta.yaml.hbs +10 -0
- package/lib/init/template/xsuaa/index.js +44 -33
- package/lib/init/util/projectReader.js +12 -7
- package/lib/init/util/templateUtil.js +113 -111
- package/lib/k8s/ChartAdder.js +13 -3
- package/lib/k8s/ChartBuilder.js +6 -0
- package/lib/k8s/buildModel.js +1 -3
- package/lib/k8s/connectivity/index.js +5 -5
- package/lib/k8s/deployment/index.js +2 -4
- package/lib/k8s/deployment/subchart/Chart.yaml +1 -1
- package/lib/k8s/deployment/subchart/templates/_helpers.tpl +22 -11
- package/lib/k8s/deployment/subchart/templates/deployment.yaml +12 -5
- package/lib/k8s/deployment/subchart/templates/network-policy.yaml +3 -1
- package/lib/k8s/deployment/subchart/templates/pod-disruption-budget.yaml +1 -1
- package/lib/k8s/deployment/subchart/values.md +812 -0
- package/lib/k8s/deployment/subchart/values.schema.json +125 -30
- package/lib/k8s/deployment/subchart/values.yaml +7 -3
- package/lib/k8s/hana-deployer/index.js +10 -0
- package/lib/k8s/hana-deployer/templates/hana-deployer-job.yaml +8 -0
- package/lib/k8s/html5-apps-deployer/index.js +10 -0
- package/lib/k8s/html5-apps-deployer/templates/html5-apps-deployer-job.yaml +8 -0
- package/lib/k8s/index.js +2 -2
- package/lib/k8s/resources/helm/chart/schemas/values.root.schema.json +11 -0
- package/lib/k8s/resources/helm/chart/schemas/values.schema.json +479 -0
- package/lib/k8s/resources/helm/chart/templates/_deployment_helpers.tpl +1 -159
- package/lib/k8s/resources/helm/chart/templates/_helpers.tpl +0 -33
- package/lib/k8s/resources/helm/chart/templates/_sapcp_helpers.tpl +1 -1
- package/lib/lint/Linter.js +155 -158
- package/lib/lint/io.js +12 -5
- package/npm-shrinkwrap.json +214 -74
- package/package.json +5 -4
- package/lib/init/template/_merging/existences.js +0 -297
- package/lib/init/template/mtx/files/cds.package.json +0 -12
- package/lib/init/template/mtx/files/cds.package.json.hbs +0 -14
- package/lib/init/template/mtx/files/java/.cdsrc.json +0 -17
- package/lib/init/template/mtx/files/java/package.json +0 -43
- package/lib/init/template/mtx/files/java/server.js +0 -30
- package/lib/init/template/mtx/files/xs-security.json.hbs +0 -48
- package/lib/lint/.eslintrc.js +0 -3
package/lib/client/extend.js
CHANGED
|
@@ -7,6 +7,7 @@ const BaseCommand = require('./base_command');
|
|
|
7
7
|
const { normalizePath, isParent } = require('./helper/fs_helper');
|
|
8
8
|
const Logger = require('./helper/logging');
|
|
9
9
|
const Question = require('./helper/question');
|
|
10
|
+
const { CliError } = require('./helper/errors');
|
|
10
11
|
|
|
11
12
|
const COMMAND_URL_SUFFIX = 'content';
|
|
12
13
|
const CUSTOM_FILE_FOLDERS = ['wsdl'];
|
|
@@ -71,7 +72,7 @@ module.exports = class Extend extends BaseCommand {
|
|
|
71
72
|
|
|
72
73
|
static async run(paramValues) {
|
|
73
74
|
try {
|
|
74
|
-
const params = await AuthManager.
|
|
75
|
+
const params = await AuthManager.login(paramValues);
|
|
75
76
|
|
|
76
77
|
if (process.env.DEBUG) {
|
|
77
78
|
Logger.log(`\n\nCreating extension project with parameters ${JSON.stringify({
|
|
@@ -88,7 +89,7 @@ module.exports = class Extend extends BaseCommand {
|
|
|
88
89
|
|
|
89
90
|
const runOnExistingProject = await Extend.checkProject(params.get('projectFolder'));
|
|
90
91
|
if (runOnExistingProject && !(params.get('force') || params.get('templates'))) {
|
|
91
|
-
throw new
|
|
92
|
+
throw new CliError(folderExists(params.get('projectFolder')));
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
try {
|
|
@@ -17,20 +17,13 @@ module.exports = class Logger {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
static getMessage(errorText, error) {
|
|
20
|
-
let message = errorText
|
|
20
|
+
let message = errorText ? errorText + '\n' : '';
|
|
21
21
|
if (!error) {
|
|
22
22
|
return message;
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const body = error.response.data;
|
|
27
|
-
if (body.error && body.error.message) {
|
|
28
|
-
message += body.error.message + '\n';
|
|
29
|
-
}
|
|
30
|
-
}
|
|
24
|
+
message += error.response?.data?.error?.message || error.message;
|
|
25
|
+
if (process.env.DEBUG && error.stack) {
|
|
31
26
|
message += '\n' + error.stack;
|
|
32
|
-
} else {
|
|
33
|
-
message += error.message;
|
|
34
27
|
}
|
|
35
28
|
return message;
|
|
36
29
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
const IP_ADDR = /^[1-9][0-9]{0,2}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/;
|
|
2
2
|
const schemaRegex = /^https?:\/\//;
|
|
3
|
-
const
|
|
3
|
+
const localhostRegex = /^(https?:\/\/)?(localhost|127\.0\.0\.1|\[?::1]?)\b/;
|
|
4
|
+
const httpSchema = 'http://';
|
|
5
|
+
const httpsSchema = 'https://';
|
|
4
6
|
|
|
5
7
|
function extractSubdomain(url) {
|
|
6
8
|
const hostname = new URL(url).hostname;
|
|
7
|
-
if (hostname
|
|
9
|
+
if (localhostRegex.test(hostname) || IP_ADDR.test(hostname)) {
|
|
8
10
|
return undefined;
|
|
9
11
|
}
|
|
10
12
|
return hostname.split('.')[0];
|
|
@@ -12,6 +14,8 @@ function extractSubdomain(url) {
|
|
|
12
14
|
|
|
13
15
|
module.exports = {
|
|
14
16
|
schemaRegex,
|
|
15
|
-
|
|
17
|
+
localhostRegex,
|
|
18
|
+
httpSchema,
|
|
19
|
+
httpsSchema,
|
|
16
20
|
extractSubdomain
|
|
17
21
|
};
|
package/lib/client/index.js
CHANGED
|
@@ -7,7 +7,7 @@ const { SettingsManager } = require('./settings_manager');
|
|
|
7
7
|
module.exports = {
|
|
8
8
|
extend: Extend.run,
|
|
9
9
|
activate: Activate.run,
|
|
10
|
-
login: AuthManager.
|
|
10
|
+
login: AuthManager.login,
|
|
11
11
|
logout: AuthManager.logout,
|
|
12
12
|
question: Question,
|
|
13
13
|
config: SettingsManager.config
|
package/lib/client/params.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const Logger = require('./helper/logging');
|
|
2
2
|
const { escapeRegex } = require('./helper/string_helper');
|
|
3
|
+
const { CliError } = require('./helper/errors');
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
// PARAM BASE TYPES
|
|
@@ -104,10 +105,10 @@ class Param {
|
|
|
104
105
|
expectedType = typeof this.allowedValues[0];
|
|
105
106
|
}
|
|
106
107
|
if (typeof val !== expectedType) {
|
|
107
|
-
throw new
|
|
108
|
+
throw new CliError(`Failed to set '${(this.name)}' = ${JSON.stringify(val)}: expected value of type ${expectedType}`);
|
|
108
109
|
}
|
|
109
110
|
if (this.allowedValues && !(this.allowedValues).includes(val)) {
|
|
110
|
-
throw new
|
|
111
|
+
throw new CliError(`Failed to set '${(this.name)}' = ${JSON.stringify(val)}: expected one of ${JSON.stringify(this.allowedValues)}`);
|
|
111
112
|
}
|
|
112
113
|
}
|
|
113
114
|
|
|
@@ -163,11 +164,13 @@ class BasicParams {
|
|
|
163
164
|
|
|
164
165
|
// - auth-related
|
|
165
166
|
this.passcode = new Param('passcode', '', { obfuscate: ObfuscationLevel.partial });
|
|
166
|
-
this.tokenStorage = new Param('tokenStorage',
|
|
167
|
+
this.tokenStorage = new Param('tokenStorage', undefined, { allowedValues: ['plain', 'keyring'] });
|
|
167
168
|
this.plain = new Param('plain', false, { internal: true }); // for backward compatibility - ignored
|
|
169
|
+
this.saveData = new Param('saveData', false, { internal: true });
|
|
168
170
|
this.renewLogin = new Param('renewLogin', false);
|
|
169
|
-
this.username = new Param('username', '');
|
|
171
|
+
this.username = new Param('username', '', { persist: Persistence.setting }); // only saved against localhost (non-productive); as setting due to ambiguous app URL
|
|
170
172
|
this.password = new Param('password', '', { obfuscate: ObfuscationLevel.full });
|
|
173
|
+
this.isEmptyPassword = new Param('isEmptyPassword', false, { internal: true, persist: Persistence.setting }); // extra param so we can ensure we never save a password
|
|
171
174
|
this.clientid = new Param('clientid', '');
|
|
172
175
|
this.clientsecret = new Param('clientsecret', '', { obfuscate: ObfuscationLevel.partial });
|
|
173
176
|
|
|
@@ -244,7 +247,7 @@ class ParamCollection {
|
|
|
244
247
|
*/
|
|
245
248
|
checkFrozen() {
|
|
246
249
|
if (this.isFrozen) {
|
|
247
|
-
throw new
|
|
250
|
+
throw new CliError('cannot modify read-only parameter collection');
|
|
248
251
|
}
|
|
249
252
|
}
|
|
250
253
|
|
|
@@ -265,7 +268,7 @@ class ParamCollection {
|
|
|
265
268
|
static mainName(name) {
|
|
266
269
|
const paramDef = ParamDefs[name];
|
|
267
270
|
if (!paramDef) {
|
|
268
|
-
throw new
|
|
271
|
+
throw new CliError(`Unknown parameter: '${name}'`);
|
|
269
272
|
}
|
|
270
273
|
return paramDef.mainName;
|
|
271
274
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const { join } = require('path');
|
|
3
|
+
const axios = require('axios');
|
|
4
|
+
|
|
5
|
+
const { unpackTarArchive } = require('@sap/cds/lib/utils/resources');
|
|
6
|
+
|
|
7
|
+
const { login } = require('./auth_manager');
|
|
8
|
+
const BaseCommand = require('./base_command');
|
|
9
|
+
const Logger = require('./helper/logging');
|
|
10
|
+
const { CliError } = require('./helper/errors');
|
|
11
|
+
|
|
12
|
+
module.exports = class Pull extends BaseCommand {
|
|
13
|
+
|
|
14
|
+
static async run(paramValues) {
|
|
15
|
+
try {
|
|
16
|
+
const params = await login(paramValues);
|
|
17
|
+
Logger.log(`Pulling base model from ${params.get('appUrl')}, for subdomain '${params.get('subdomain')}', to project folder '${params.get('projectFolder')}'`);
|
|
18
|
+
|
|
19
|
+
const projectFolder = params.get('projectFolder');
|
|
20
|
+
const targetDir = join(projectFolder, 'node_modules', this.getAppPackageName(projectFolder));
|
|
21
|
+
fs.rmSync(targetDir, { force: true, recursive: true });
|
|
22
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
23
|
+
|
|
24
|
+
const tgzBuffer = Buffer.from(await this.getTgz(params));
|
|
25
|
+
return unpackTarArchive(tgzBuffer, targetDir, false);
|
|
26
|
+
|
|
27
|
+
} catch (error) {
|
|
28
|
+
throw new CliError(undefined, error);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static getAppPackageName(projectFolder) {
|
|
33
|
+
try {
|
|
34
|
+
return require(join(projectFolder, 'package.json')).cds.extends;
|
|
35
|
+
} catch (error) {
|
|
36
|
+
return '_base';
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static async getTgz(params) {
|
|
41
|
+
const pullUrl = `${(params.get('appUrl'))}/-/cds/extensibility/pull`;
|
|
42
|
+
const options = { ...params.get('reqAuth'), responseType: 'arraybuffer' };
|
|
43
|
+
|
|
44
|
+
return axios.post(pullUrl, {}, options)
|
|
45
|
+
.then(response => response.data)
|
|
46
|
+
.catch(error => this.handleHttpError(error, params));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const { join } = require('path');
|
|
3
|
+
const axios = require('axios');
|
|
4
|
+
|
|
5
|
+
const { login } = require('./auth_manager');
|
|
6
|
+
const BaseCommand = require('./base_command');
|
|
7
|
+
const Logger = require('./helper/logging');
|
|
8
|
+
const { CliError } = require('./helper/errors');
|
|
9
|
+
|
|
10
|
+
module.exports = class Push extends BaseCommand {
|
|
11
|
+
|
|
12
|
+
static async run(paramValues) {
|
|
13
|
+
try {
|
|
14
|
+
const params = await login(paramValues);
|
|
15
|
+
const projectFolder = params.get('projectFolder');
|
|
16
|
+
Logger.log(`Pushing extension from project folder '${projectFolder}', for subdomain '${params.get('subdomain')}', to app URL ${params.get('appUrl')}`);
|
|
17
|
+
|
|
18
|
+
const tgz = fs.readFileSync(join(projectFolder, 'gen', 'extension.tgz'), { encoding: 'base64' });
|
|
19
|
+
const extensionName = this.getExtensionName(projectFolder);
|
|
20
|
+
return this.pushTgz(params, tgz, extensionName);
|
|
21
|
+
|
|
22
|
+
} catch (error) {
|
|
23
|
+
throw new CliError(undefined, error);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static getExtensionName(projectFolder) {
|
|
28
|
+
try {
|
|
29
|
+
return require(join(projectFolder, 'package.json')).name;
|
|
30
|
+
} catch (error) {
|
|
31
|
+
throw new CliError(`Extension project at ${projectFolder} is missing package.json`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static async pushTgz(params, tgz, extensionName) {
|
|
36
|
+
const pushUrl = `${params.get('appUrl')}/-/cds/extensibility/push`;
|
|
37
|
+
const options = { ...params.get('reqAuth') };
|
|
38
|
+
|
|
39
|
+
return axios.post(pushUrl, {
|
|
40
|
+
extension: tgz,
|
|
41
|
+
tag: extensionName
|
|
42
|
+
}, options)
|
|
43
|
+
.catch(error => this.handleHttpError(error, params));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -9,9 +9,11 @@ const { getAppFromSuggestions, getAppName, getSubdomain } = require('./helper/cf
|
|
|
9
9
|
const isBas = require('./helper/env_helper');
|
|
10
10
|
const Logger = require('./helper/logging');
|
|
11
11
|
const Question = require('./helper/question');
|
|
12
|
-
const {
|
|
12
|
+
const { CliError } = require('./helper/errors');
|
|
13
|
+
const { httpSchema, httpsSchema, extractSubdomain, schemaRegex, localhostRegex } = require('./helper/url_helper');
|
|
13
14
|
const { ParamCollection, Persistence } = require('./params');
|
|
14
15
|
const { capitalize } = require('./helper/string_helper');
|
|
16
|
+
const axios = require('axios');
|
|
15
17
|
|
|
16
18
|
const CONFIG_SUBDIRS = {
|
|
17
19
|
linux: '.config',
|
|
@@ -31,7 +33,8 @@ const KEYRING_DESC = {
|
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
const MTX_FULLY_QUALIFIED = 'com.sap.cds.mtx';
|
|
34
|
-
const
|
|
36
|
+
const OAUTH_PATH_OLD_MTX = '/mtx/v1/oauth/token';
|
|
37
|
+
const OAUTH_PATH_STREAMLINED_MTX = '/-/cds/login/token';
|
|
35
38
|
|
|
36
39
|
const SETTINGS_DIR = path.join(os.homedir(), CONFIG_SUBDIRS[os.platform()] || '', MTX_FULLY_QUALIFIED);
|
|
37
40
|
const SETTINGS_FILE = 'projects.json';
|
|
@@ -88,16 +91,38 @@ async function getSubdomainFromCfAndNotify(appName) {
|
|
|
88
91
|
return subdomain;
|
|
89
92
|
}
|
|
90
93
|
|
|
91
|
-
function getTokenBaseUrl(params, renewUrl) {
|
|
94
|
+
async function getTokenBaseUrl(params, renewUrl) {
|
|
92
95
|
if (params.has('tokenUrl') && !renewUrl) {
|
|
93
96
|
return params.get('tokenUrl');
|
|
94
97
|
}
|
|
95
98
|
if (!params.has('appUrl')) {
|
|
96
|
-
throw new
|
|
99
|
+
throw new CliError('Failed to determine token URL: app URL not given');
|
|
97
100
|
}
|
|
98
101
|
const baseUrl = new URL(params.get('appUrl'));
|
|
99
|
-
|
|
100
|
-
|
|
102
|
+
const cleanPathname = pathname => baseUrl.pathname.replace(/\/?$/, pathname);
|
|
103
|
+
const getBaseUrl = pathname => {
|
|
104
|
+
const url = new URL(baseUrl.toString());
|
|
105
|
+
url.pathname = cleanPathname(pathname);
|
|
106
|
+
return url;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
let existingPath;
|
|
110
|
+
const oauthPaths = [OAUTH_PATH_STREAMLINED_MTX/*, OAUTH_PATH_OLD_MTX*/]; // The old MTX does not support HEAD requests
|
|
111
|
+
for (const path of oauthPaths) {
|
|
112
|
+
try {
|
|
113
|
+
await axios.head(getBaseUrl(path).toString());
|
|
114
|
+
existingPath = path;
|
|
115
|
+
break;
|
|
116
|
+
} catch (e) {
|
|
117
|
+
if (e.response?.status === 404) {
|
|
118
|
+
continue;
|
|
119
|
+
} else {
|
|
120
|
+
throw new CliError(`Failed with root cause ${e.message}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
existingPath = existingPath ?? OAUTH_PATH_OLD_MTX;
|
|
125
|
+
return getBaseUrl(existingPath).toString();
|
|
101
126
|
}
|
|
102
127
|
|
|
103
128
|
function getKeyringAccountName(params) {
|
|
@@ -134,7 +159,16 @@ class SettingsManager {
|
|
|
134
159
|
static async saveSettings(params) {
|
|
135
160
|
Logger.debug(`Saving settings for project ${params.get('projectFolder')}`);
|
|
136
161
|
|
|
137
|
-
|
|
162
|
+
const paramsMap = params.toValueMap(Persistence.setting);
|
|
163
|
+
if (localhostRegex.test(params.get('appUrl'))) {
|
|
164
|
+
Logger.log(`Saving username${(params.get('isEmptyPassword') ? ' and empty-password hint' : '')} with project settings.`);
|
|
165
|
+
} else {
|
|
166
|
+
// Save only against localhost for security reasons.
|
|
167
|
+
Logger.debug('Not saving username because app is not recognized to run on localhost.');
|
|
168
|
+
delete paramsMap.username;
|
|
169
|
+
delete paramsMap.isEmptyPassword;
|
|
170
|
+
}
|
|
171
|
+
await this._saveToFile(params.get('projectFolder'), paramsMap);
|
|
138
172
|
|
|
139
173
|
if (!params.has('token')) {
|
|
140
174
|
return;
|
|
@@ -173,15 +207,22 @@ class SettingsManager {
|
|
|
173
207
|
|
|
174
208
|
static async updateUrls(params, logout, loadedAppUrl) {
|
|
175
209
|
async function addAppUrlAndSubdomain() {
|
|
176
|
-
if (params.has('appUrl')
|
|
177
|
-
|
|
178
|
-
|
|
210
|
+
if (params.has('appUrl')) {
|
|
211
|
+
const appUrl = params.get('appUrl');
|
|
212
|
+
if (!schemaRegex.test(appUrl)) {
|
|
213
|
+
if (localhostRegex.test(appUrl)) {
|
|
214
|
+
params.set('appUrl', httpSchema + appUrl);
|
|
215
|
+
} else {
|
|
216
|
+
params.set('appUrl', httpsSchema + appUrl);
|
|
217
|
+
}
|
|
218
|
+
Logger.debug(`Added schema to app URL: ${params.get('appUrl')}`);
|
|
219
|
+
}
|
|
179
220
|
}
|
|
180
221
|
if (!logout) {
|
|
181
222
|
if (!params.has('appUrl')) {
|
|
182
223
|
Logger.debug('App URL not given');
|
|
183
224
|
await getAppUrlAndSubdomainFromSuggestions(params);
|
|
184
|
-
} else if (!params.has('subdomain')) {
|
|
225
|
+
} else if (!params.has('subdomain') && !localhostRegex.test(params.get('appUrl'))) {
|
|
185
226
|
Logger.debug('Subdomain not given');
|
|
186
227
|
const appName = await getAppName(params.get('appUrl'));
|
|
187
228
|
if (appName) {
|
|
@@ -190,27 +231,28 @@ class SettingsManager {
|
|
|
190
231
|
}
|
|
191
232
|
}
|
|
192
233
|
if (!params.has('appUrl')) {
|
|
193
|
-
throw new
|
|
234
|
+
throw new CliError('App URL not given. Please specify it or log in to Cloud Foundry and repeat this command.');
|
|
194
235
|
}
|
|
195
236
|
if (!params.has('subdomain')) {
|
|
196
|
-
|
|
197
|
-
if (!
|
|
198
|
-
throw new
|
|
237
|
+
const subdomain = extractSubdomain(params.get('appUrl'));
|
|
238
|
+
if (!subdomain) {
|
|
239
|
+
throw new CliError('Subdomain not given');
|
|
199
240
|
}
|
|
200
|
-
|
|
241
|
+
params.set('subdomain', subdomain);
|
|
242
|
+
Logger.log(`Subdomain determined from app URL: ${subdomain}`);
|
|
201
243
|
}
|
|
202
244
|
}
|
|
203
|
-
function renewTokenUrl() {
|
|
245
|
+
async function renewTokenUrl() {
|
|
204
246
|
const renewUrl = params.get('appUrl') !== loadedAppUrl;
|
|
205
247
|
if (!params.get('tokenUrl') || renewUrl) {
|
|
206
|
-
params.set('tokenUrl', getTokenBaseUrl(params, renewUrl));
|
|
248
|
+
params.set('tokenUrl', await getTokenBaseUrl(params, renewUrl));
|
|
207
249
|
}
|
|
208
250
|
}
|
|
209
251
|
|
|
210
252
|
await addAppUrlAndSubdomain();
|
|
211
253
|
|
|
212
254
|
if (!logout) {
|
|
213
|
-
renewTokenUrl();
|
|
255
|
+
await renewTokenUrl();
|
|
214
256
|
}
|
|
215
257
|
}
|
|
216
258
|
|
|
@@ -226,7 +268,7 @@ class SettingsManager {
|
|
|
226
268
|
return;
|
|
227
269
|
}
|
|
228
270
|
if (params.get('tokenStorage') === 'keyring') {
|
|
229
|
-
throw new
|
|
271
|
+
throw new CliError(`${capitalize(TOKEN_STORAGE_DESC.keyring)} requested but keytar not installed. Run 'npm install -g keytar' or ` +
|
|
230
272
|
`switch to ${TOKEN_STORAGE_DESC.plain} by adding '--plain' (discouraged).`);
|
|
231
273
|
}
|
|
232
274
|
if (params.get('renewLogin') || logout) {
|
|
@@ -236,23 +278,26 @@ class SettingsManager {
|
|
|
236
278
|
|
|
237
279
|
static async addAuth(params, logout) {
|
|
238
280
|
async function addPassword() {
|
|
239
|
-
params.
|
|
240
|
-
|
|
241
|
-
|
|
281
|
+
if (params.get('isEmptyPassword')) {
|
|
282
|
+
params.set('password', '');
|
|
283
|
+
} else {
|
|
284
|
+
params.set('password', await Question.askQuestion('Password: ', undefined, true));
|
|
285
|
+
console.log();
|
|
242
286
|
}
|
|
243
287
|
}
|
|
244
288
|
async function addClientSecret() {
|
|
245
289
|
params.set('clientsecret', await Question.askQuestion('clientsecret: ', undefined, true));
|
|
290
|
+
console.log();
|
|
246
291
|
if (params.get('clientsecret') === '') {
|
|
247
|
-
throw new
|
|
292
|
+
throw new CliError('clientsecret cannot be empty');
|
|
248
293
|
}
|
|
249
294
|
}
|
|
250
295
|
async function addPasscode() {
|
|
251
296
|
const prompt = `Passcode${params.get('passcodeUrl') ? ' (visit ' + params.get('passcodeUrl') + ' to generate)' : ''}: `;
|
|
252
297
|
params.set('passcode', await Question.askQuestion(prompt, undefined, true));
|
|
253
|
-
console.log();
|
|
298
|
+
console.log();
|
|
254
299
|
if (params.get('passcode') === '') {
|
|
255
|
-
throw new
|
|
300
|
+
throw new CliError('Passcode cannot be empty');
|
|
256
301
|
}
|
|
257
302
|
}
|
|
258
303
|
function setRelevantAuth(auth) {
|
|
@@ -288,10 +333,19 @@ class SettingsManager {
|
|
|
288
333
|
}
|
|
289
334
|
|
|
290
335
|
if (params.has('username')) {
|
|
291
|
-
if (!params.
|
|
336
|
+
if (!params.has('password') && !logout) {
|
|
292
337
|
await addPassword();
|
|
293
338
|
}
|
|
339
|
+
if (params.get('password') === '') {
|
|
340
|
+
params.set('isEmptyPassword', true);
|
|
341
|
+
// TODO check password only in production env
|
|
342
|
+
// throw new CliError('Password cannot be empty');
|
|
343
|
+
} else {
|
|
344
|
+
params.delete('isEmptyPassword');
|
|
345
|
+
}
|
|
294
346
|
return;
|
|
347
|
+
} else {
|
|
348
|
+
params.delete('isEmptyPassword');
|
|
295
349
|
}
|
|
296
350
|
|
|
297
351
|
if (params.get('clientid') && !params.get('clientsecret') && !logout) {
|