@capacitor/cli 6.2.1 → 6.2.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.
Binary file
Binary file
Binary file
package/dist/index.js CHANGED
@@ -97,8 +97,8 @@ function runProgram(config) {
97
97
  .option('--keystorealias <keystoreAlias>', 'Key Alias in the keystore')
98
98
  .option('--configuration <name>', 'Configuration name of the iOS Scheme')
99
99
  .option('--keystorealiaspass <keystoreAliasPass>', 'Password for the Key Alias')
100
- .addOption(new commander_1.Option('--androidreleasetype <androidreleasetype>', 'Android release type; APK or AAB').choices(['AAB', 'APK']))
101
- .addOption(new commander_1.Option('--signing-type <signingtype>', 'Program used to sign apps (default: jarsigner)').choices(['apksigner', 'jarsigner']))
100
+ .addOption(new commander_1.Option('--androidreleasetype <androidreleasetype>', 'Android release type; APK or AAB').choices([...telemetry_1.TELEMETRY_SAFE_CHOICES.androidreleasetype]))
101
+ .addOption(new commander_1.Option('--signing-type <signingtype>', 'Program used to sign apps (default: jarsigner)').choices([...telemetry_1.TELEMETRY_SAFE_CHOICES.signingType]))
102
102
  .action((0, cli_1.wrapAction)((0, telemetry_1.telemetryAction)(config, async (platform, { scheme, flavor, keystorepath, keystorepass, keystorealias, keystorealiaspass, androidreleasetype, signingType, configuration, }) => {
103
103
  const { buildCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/build')));
104
104
  await buildCommand(config, platform, {
package/dist/telemetry.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.sendMetric = exports.telemetryAction = exports.THANK_YOU = void 0;
3
+ exports.sendMetric = exports.getTelemetryVersion = exports.getTelemetryArguments = exports.getTelemetryError = exports.getTelemetryOptions = exports.telemetryAction = exports.TELEMETRY_SAFE_CHOICES = exports.THANK_YOU = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const commander_1 = require("commander");
6
6
  const debug_1 = tslib_1.__importDefault(require("debug"));
@@ -13,6 +13,51 @@ const term_1 = require("./util/term");
13
13
  const debug = (0, debug_1.default)('capacitor:telemetry');
14
14
  exports.THANK_YOU = `\nThank you for helping to make Capacitor better! 💖` +
15
15
  `\nInformation about the data we collect is available on our website: ${colors_1.default.strong('https://capacitorjs.com/telemetry')}\n`;
16
+ /**
17
+ * The option values that are safe to report, keyed by the option's resolved
18
+ * name (commander's `attributeName()`, so `--signing-type` is `signingType`).
19
+ * This is an allowlist by design: a denylist of password-like names would leak
20
+ * the first sensitive option someone adds.
21
+ *
22
+ * The option declarations in `index.ts` spread these same lists into
23
+ * `.choices()`, so an option cannot offer a choice this does not list.
24
+ */
25
+ exports.TELEMETRY_SAFE_CHOICES = {
26
+ androidreleasetype: ['AAB', 'APK'],
27
+ signingType: ['apksigner', 'jarsigner'],
28
+ };
29
+ const telemetrySafeChoices = new Map(Object.entries(exports.TELEMETRY_SAFE_CHOICES).map(([name, choices]) => [
30
+ name,
31
+ new Set(choices),
32
+ ]));
33
+ /**
34
+ * Positional argument values that are safe to report. Everything else is
35
+ * dropped, since arguments like `cap init`'s app name are user content.
36
+ */
37
+ const TELEMETRY_ARGUMENT_ALLOWLIST = new Set(['android', 'ios', 'web']);
38
+ /**
39
+ * Upper bound on the reported error, so a failed Gradle build cannot ship its
40
+ * entire log as a metric.
41
+ */
42
+ const TELEMETRY_ERROR_MAX_LENGTH = 500;
43
+ /**
44
+ * Shortest value worth scrubbing out of a reported error. An empty string would
45
+ * match between every character, and a one- or two-character option value--a
46
+ * port, a target index--appears throughout unrelated output, so redacting
47
+ * either destroys the error instead of sanitizing it.
48
+ */
49
+ const TELEMETRY_REDACTION_MIN_LENGTH = 3;
50
+ /**
51
+ * The characters a dependency spec may contain to be reported as-is. A version
52
+ * range has none of the `:/@` a URL or path spec needs, so specs such as
53
+ * `git+https://x-access-token:<token>@github.com/acme/plugin.git` and
54
+ * `file:/Users/<name>/dev/plugin` are reported as {@link NON_REGISTRY_VERSION}
55
+ * instead of shipping a credential or a local path. The pnpm and yarn workspace
56
+ * protocols are allowed through as the only exception, since they resolve
57
+ * within the repo and so cannot carry either.
58
+ */
59
+ const TELEMETRY_SAFE_VERSION_PATTERN = /^(?:(?:workspace|catalog):)?[\w.\-+^~><=|* ]*$/;
60
+ const NON_REGISTRY_VERSION = 'non-registry';
16
61
  function telemetryAction(config, action) {
17
62
  return async (...actionArgs) => {
18
63
  const start = new Date();
@@ -39,15 +84,16 @@ function telemetryAction(config, action) {
39
84
  const capacitorPackages = packages.filter(([k]) => k.startsWith('@capacitor/'));
40
85
  const versions = capacitorPackages.map(([k, v]) => [
41
86
  `${k.replace(/^@capacitor\//, '').replace(/-/g, '_')}_version`,
42
- v,
87
+ getTelemetryVersion(v),
43
88
  ]);
89
+ const options = getTelemetryOptions(cmd);
44
90
  const data = {
45
91
  app_id: await getAppIdentifier(config),
46
92
  command,
47
- arguments: cmd.args.join(' '),
48
- options: JSON.stringify(cmd.opts()),
93
+ arguments: getTelemetryArguments(cmd),
94
+ options: JSON.stringify(options),
49
95
  duration,
50
- error: error ? (error.message ? error.message : String(error)) : null,
96
+ error: getTelemetryError(cmd, error, config, options),
51
97
  node_version: process.version,
52
98
  os: config.cli.os,
53
99
  ...Object.fromEntries(versions),
@@ -67,6 +113,91 @@ function telemetryAction(config, action) {
67
113
  };
68
114
  }
69
115
  exports.telemetryAction = telemetryAction;
116
+ /**
117
+ * Build the reported option map: every option name the command resolved, but
118
+ * only the values that cannot carry a secret. Booleans are kept because they
119
+ * cannot encode one, allowlisted options are kept when the value is one this
120
+ * file lists, and every other value--keystore passwords, paths, signing
121
+ * identities--becomes `null`.
122
+ */
123
+ function getTelemetryOptions(cmd) {
124
+ return Object.fromEntries(Object.entries(cmd.opts()).map(([name, value]) => [
125
+ name,
126
+ isTelemetrySafeValue(name, value) ? value : null,
127
+ ]));
128
+ }
129
+ exports.getTelemetryOptions = getTelemetryOptions;
130
+ function isTelemetrySafeValue(name, value) {
131
+ var _a, _b;
132
+ if (typeof value === 'boolean') {
133
+ return true;
134
+ }
135
+ return (typeof value === 'string' &&
136
+ ((_b = (_a = telemetrySafeChoices.get(name)) === null || _a === void 0 ? void 0 : _a.has(value)) !== null && _b !== void 0 ? _b : false));
137
+ }
138
+ /**
139
+ * The signing credentials `capacitor.config` can supply. `cap build` falls back
140
+ * to the config for each of these when the flag is absent, and the resolved
141
+ * value still reaches the `jarsigner` command line--so it can come back in its
142
+ * output without ever having appeared in `cmd.opts()`.
143
+ */
144
+ function getConfiguredCredentials(config) {
145
+ return [
146
+ config.android.buildOptions.keystorePath,
147
+ config.android.buildOptions.keystorePassword,
148
+ config.android.buildOptions.keystoreAlias,
149
+ config.android.buildOptions.keystoreAliasPassword,
150
+ ].filter((value) => typeof value === 'string');
151
+ }
152
+ /**
153
+ * Build the reported error, scrubbed of every option value and positional
154
+ * argument the rest of the payload drops, plus the signing credentials the
155
+ * config can supply in place of a flag, then truncated.
156
+ *
157
+ * Failed subprocesses rethrow the tool's combined output, which echoes back
158
+ * the very values that were redacted out of the option map--`jarsigner` prints
159
+ * the keystore it was pointed at.
160
+ */
161
+ function getTelemetryError(cmd, error, config, options = getTelemetryOptions(cmd)) {
162
+ if (!error) {
163
+ return null;
164
+ }
165
+ const values = cmd.opts();
166
+ const redacted = [
167
+ ...Object.entries(options)
168
+ .filter(([, value]) => value === null)
169
+ .map(([name]) => values[name]),
170
+ ...cmd.args.filter(arg => !TELEMETRY_ARGUMENT_ALLOWLIST.has(arg)),
171
+ ...getConfiguredCredentials(config),
172
+ ]
173
+ .filter((value) => typeof value === 'string' &&
174
+ value.length >= TELEMETRY_REDACTION_MIN_LENGTH)
175
+ .sort((a, b) => b.length - a.length);
176
+ const message = redacted.reduce((message, value) => message.split(value).join('<redacted>'), error.message ? error.message : String(error));
177
+ return message.slice(0, TELEMETRY_ERROR_MAX_LENGTH);
178
+ }
179
+ exports.getTelemetryError = getTelemetryError;
180
+ /**
181
+ * Build the reported positional arguments, keeping only allowlisted values.
182
+ */
183
+ function getTelemetryArguments(cmd) {
184
+ return cmd.args
185
+ .filter(arg => TELEMETRY_ARGUMENT_ALLOWLIST.has(arg))
186
+ .join(' ');
187
+ }
188
+ exports.getTelemetryArguments = getTelemetryArguments;
189
+ /**
190
+ * Build the reported version of a Capacitor dependency, keeping the spec only
191
+ * when it is a version range. Specs that point somewhere--a git URL, a local
192
+ * path--are reported as being just that, since they can carry a token or a
193
+ * username.
194
+ */
195
+ function getTelemetryVersion(spec) {
196
+ return spec && TELEMETRY_SAFE_VERSION_PATTERN.test(spec)
197
+ ? spec
198
+ : NON_REGISTRY_VERSION;
199
+ }
200
+ exports.getTelemetryVersion = getTelemetryVersion;
70
201
  /**
71
202
  * If telemetry is enabled, send a metric via IPC to a forked process for uploading.
72
203
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capacitor/cli",
3
- "version": "6.2.1",
3
+ "version": "6.2.3",
4
4
  "description": "Capacitor: Cross-platform apps with JavaScript and the web",
5
5
  "homepage": "https://capacitorjs.com",
6
6
  "author": "Ionic Team <hi@ionic.io> (https://ionic.io)",