@capacitor/cli 7.6.9 → 7.6.10

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