@react-native-windows/cli 0.80.0-preview.6 → 0.80.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-native-windows/cli",
3
- "version": "0.80.0-preview.6",
3
+ "version": "0.80.0",
4
4
  "license": "MIT",
5
5
  "main": "lib-commonjs/index.js",
6
6
  "repository": {
@@ -17,10 +17,10 @@
17
17
  "watch": "rnw-scripts watch"
18
18
  },
19
19
  "dependencies": {
20
- "@react-native-windows/codegen": "0.80.0-preview.1",
21
- "@react-native-windows/fs": "0.80.0-preview.1",
22
- "@react-native-windows/package-utils": "0.80.0-preview.1",
23
- "@react-native-windows/telemetry": "0.80.0-preview.2",
20
+ "@react-native-windows/codegen": "0.80.0",
21
+ "@react-native-windows/fs": "0.80.0",
22
+ "@react-native-windows/package-utils": "0.80.0",
23
+ "@react-native-windows/telemetry": "0.80.0",
24
24
  "@xmldom/xmldom": "^0.7.7",
25
25
  "chalk": "^4.1.0",
26
26
  "cli-spinners": "^2.2.0",
@@ -73,11 +73,11 @@
73
73
  "src/powershell"
74
74
  ],
75
75
  "beachball": {
76
- "defaultNpmTag": "preview",
76
+ "defaultNpmTag": "latest",
77
77
  "disallowedChangeTypes": [
78
78
  "major",
79
79
  "minor",
80
- "patch",
80
+ "prerelease",
81
81
  "premajor",
82
82
  "preminor",
83
83
  "prepatch"
@@ -16,6 +16,13 @@
16
16
  specific language governing permissions and limitations
17
17
  under the License.
18
18
  #>
19
+
20
+ # SDL CE.10116 SECURITY FIX: Removed PowerShell injection vulnerabilities
21
+ # - Replaced Invoke-Expression with direct cmdlet invocation
22
+ # - Implemented parameterized ScriptBlock pattern for elevated execution
23
+ # - Added input validation for package IDs and paths
24
+ # Date: October 14, 2025
25
+
19
26
  $code = @"
20
27
  using System;
21
28
  using System.Runtime.CompilerServices;
@@ -53,21 +60,150 @@ namespace StoreAppRunner
53
60
  }
54
61
  "@
55
62
 
63
+ #region Security Helper Functions
64
+
65
+ <#
66
+ .SYNOPSIS
67
+ Validates package identifier format to prevent injection attacks.
68
+ .DESCRIPTION
69
+ Ensures package ID contains only safe characters and matches expected format.
70
+ SDL CE.10116 compliance - prevents PowerShell injection via package names.
71
+ #>
72
+ function Validate-PackageIdentifier {
73
+ param(
74
+ [Parameter(Mandatory=$true)]
75
+ [string]$PackageId
76
+ )
77
+
78
+ # Valid format: alphanumeric, dots, hyphens, underscores only
79
+ if ($PackageId -notmatch '^[a-zA-Z0-9\.\-_]+$') {
80
+ throw "Invalid package identifier format. Only alphanumeric characters, dots, hyphens, and underscores are allowed."
81
+ }
82
+
83
+ # Prevent common injection patterns
84
+ $dangerousPatterns = @(';', '|', '&', '$', '`', '<', '>', "`n", "`r", '(', ')', '{', '}')
85
+ foreach ($pattern in $dangerousPatterns) {
86
+ if ($PackageId.Contains($pattern)) {
87
+ throw "Package identifier contains forbidden characters: $pattern"
88
+ }
89
+ }
90
+
91
+ return $true
92
+ }
93
+
94
+ <#
95
+ .SYNOPSIS
96
+ Validates and canonicalizes script path to prevent path traversal attacks.
97
+ .DESCRIPTION
98
+ Ensures path is a valid .ps1 file and resolves to canonical path.
99
+ SDL CE.10116 compliance - prevents path injection attacks.
100
+ #>
101
+ function Validate-ScriptPath {
102
+ param(
103
+ [Parameter(Mandatory=$true)]
104
+ [string]$Path
105
+ )
106
+
107
+ # Check file exists
108
+ if (!(Test-Path $Path -PathType Leaf)) {
109
+ throw "Script path does not exist: $Path"
110
+ }
111
+
112
+ # Check .ps1 extension
113
+ if ([System.IO.Path]::GetExtension($Path) -ne '.ps1') {
114
+ throw "Path must reference a PowerShell script (.ps1)"
115
+ }
116
+
117
+ # Get canonical path (prevents ../ traversal)
118
+ $canonicalPath = [System.IO.Path]::GetFullPath($Path)
119
+
120
+ return $canonicalPath
121
+ }
122
+
123
+ <#
124
+ .SYNOPSIS
125
+ Executes a ScriptBlock with optional elevation using parameterized approach.
126
+ .DESCRIPTION
127
+ SDL CE.10116 compliant - uses ScriptBlock with ArgumentList instead of string concatenation.
128
+ Prevents PowerShell injection attacks by properly isolating parameters.
129
+ #>
130
+ function Invoke-ElevatedScriptBlock {
131
+ param(
132
+ [Parameter(Mandatory=$true)]
133
+ [ScriptBlock]$ScriptBlock,
134
+
135
+ [Parameter(Mandatory=$false)]
136
+ [object[]]$ArgumentList = @()
137
+ )
138
+
139
+ if (!(IsElevated)) {
140
+ # Serialize ScriptBlock and arguments for elevated execution
141
+ $encodedCommand = [Convert]::ToBase64String(
142
+ [System.Text.Encoding]::Unicode.GetBytes($ScriptBlock.ToString())
143
+ )
144
+
145
+ $encodedArgs = [Convert]::ToBase64String(
146
+ [System.Text.Encoding]::Unicode.GetBytes(
147
+ ($ArgumentList | ConvertTo-Json -Compress -Depth 10)
148
+ )
149
+ )
150
+
151
+ # Create secure argument list (no string interpolation)
152
+ $startArgs = @(
153
+ '-NoProfile',
154
+ '-NonInteractive',
155
+ '-Command',
156
+ "& ([ScriptBlock]::Create([System.Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('$encodedCommand')))) @(ConvertFrom-Json ([System.Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('$encodedArgs'))))"
157
+ )
158
+
159
+ $process = Start-Process PowerShell -ArgumentList $startArgs `
160
+ -Verb RunAs -Wait -PassThru -WindowStyle Hidden -ErrorAction Stop
161
+
162
+ if ($process.ExitCode -ne 0) {
163
+ throw "Elevated command failed with exit code $($process.ExitCode)"
164
+ }
165
+ }
166
+ else {
167
+ # Already elevated, execute directly with splatting
168
+ & $ScriptBlock @ArgumentList
169
+ }
170
+ }
171
+
172
+ #endregion
173
+
174
+ #region Core Functions
175
+
176
+ <#
177
+ .SYNOPSIS
178
+ Uninstalls an AppX package by package identifier.
179
+ .DESCRIPTION
180
+ SDL CE.10116 FIX: Replaced Invoke-Expression with direct Remove-AppxPackage cmdlet.
181
+ Uses parameterized ScriptBlock for elevated execution.
182
+ #>
56
183
  function Uninstall-App {
57
184
  param(
58
185
  [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)]
59
186
  [string] $ID <# package.appxmanifest//Identity@name #>
60
187
  )
61
188
 
189
+ # SDL FIX: Validate package ID to prevent injection
190
+ Validate-PackageIdentifier -PackageId $ID | Out-Null
191
+
62
192
  $package = Get-AppxPackage $ID
63
193
 
64
194
  if($package) {
65
195
  $pfn = $package.PackageFullName
66
- $command = "Remove-AppxPackage $pfn -ErrorAction Stop"
196
+
197
+ # SDL FIX: Direct cmdlet invocation instead of Invoke-Expression
67
198
  try {
68
- Invoke-Expression $command
199
+ Remove-AppxPackage $pfn -ErrorAction Stop
69
200
  } catch {
70
- Invoke-Expression-MayElevate $command -ErrorAction Stop
201
+ # SDL FIX: Use parameterized ScriptBlock for elevation
202
+ $scriptBlock = {
203
+ param($PackageFullName)
204
+ Remove-AppxPackage $PackageFullName -ErrorAction Stop
205
+ }
206
+ Invoke-ElevatedScriptBlock -ScriptBlock $scriptBlock -ArgumentList @($pfn)
71
207
  }
72
208
  }
73
209
  }
@@ -91,44 +227,60 @@ function IsElevated {
91
227
  return [bool](([System.Security.Principal.WindowsIdentity]::GetCurrent()).groups -match "S-1-5-32-544");
92
228
  }
93
229
 
94
- function RunElevatedPowerShellSync([string]$Command) {
95
- $process = Start-Process Powershell -ArgumentList "$Command" -Verb RunAs -ErrorAction Stop -PassThru
96
- if ($process -ne $null) {
97
- $process.WaitForExit();
98
- if ($process.ExitCode -ne 0) {
99
- $code = $process.ExitCode;
100
- throw "Command exited with code $code";
101
- }
102
- } else {
103
- throw "Process creation failed for $Command";
104
- }
105
- }
106
-
107
- function Invoke-Expression-MayElevate([string]$Command) {
108
- if (!(IsElevated))
109
- {
110
- RunElevatedPowerShellSync($Command) -ErrorAction Stop
111
- }
112
- else
113
- {
114
- Invoke-Expression ("& $Command") -ErrorAction Stop
115
- }
116
- }
117
-
230
+ <#
231
+ .SYNOPSIS
232
+ Enables developer mode by setting registry keys.
233
+ .DESCRIPTION
234
+ SDL CE.10116 FIX: Replaced Invoke-Expression-MayElevate with direct cmdlet calls
235
+ and parameterized ScriptBlock for elevation.
236
+ #>
118
237
  function EnableDevmode {
119
238
  $RegistryKeyPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock"
120
239
 
240
+ # Create registry key if it doesn't exist
121
241
  if (-not(Test-Path -Path $RegistryKeyPath)) {
122
- New-Item -Path $RegistryKeyPath -ItemType Directory -Force
242
+ if (!(IsElevated)) {
243
+ $scriptBlock = {
244
+ param($Path)
245
+ New-Item -Path $Path -ItemType Directory -Force | Out-Null
246
+ }
247
+ Invoke-ElevatedScriptBlock -ScriptBlock $scriptBlock -ArgumentList @($RegistryKeyPath)
248
+ }
249
+ else {
250
+ New-Item -Path $RegistryKeyPath -ItemType Directory -Force | Out-Null
251
+ }
123
252
  }
124
253
 
125
- $value = get-ItemProperty -Path $RegistryKeyPath -Name AllowDevelopmentWithoutDevLicense -ErrorAction SilentlyContinue
254
+ # SDL FIX: Direct cmdlet invocation for AllowDevelopmentWithoutDevLicense
255
+ $value = Get-ItemProperty -Path $RegistryKeyPath -Name AllowDevelopmentWithoutDevLicense -ErrorAction SilentlyContinue
126
256
  if (($value -eq $null) -or ($value.AllowDevelopmentWithoutDevLicense -ne 1)) {
127
- Invoke-Expression-MayElevate("Set-ItemProperty -Path $RegistryKeyPath -Name AllowDevelopmentWithoutDevLicense -Value 1 -ErrorAction Stop") -ErrorAction Stop;
257
+ if (!(IsElevated)) {
258
+ $scriptBlock = {
259
+ param($Path, $Name, $Value)
260
+ Set-ItemProperty -Path $Path -Name $Name -Value $Value -ErrorAction Stop
261
+ }
262
+ Invoke-ElevatedScriptBlock -ScriptBlock $scriptBlock `
263
+ -ArgumentList @($RegistryKeyPath, 'AllowDevelopmentWithoutDevLicense', 1)
264
+ }
265
+ else {
266
+ Set-ItemProperty -Path $RegistryKeyPath -Name AllowDevelopmentWithoutDevLicense -Value 1 -ErrorAction Stop
267
+ }
128
268
  }
129
- $value = get-ItemProperty -Path $RegistryKeyPath -Name AllowAllTrustedApps -ErrorAction SilentlyContinue
269
+
270
+ # SDL FIX: Direct cmdlet invocation for AllowAllTrustedApps
271
+ $value = Get-ItemProperty -Path $RegistryKeyPath -Name AllowAllTrustedApps -ErrorAction SilentlyContinue
130
272
  if (($value -eq $null) -or ($value.AllowAllTrustedApps -ne 1)) {
131
- Invoke-Expression-MayElevate("Set-ItemProperty -Path $RegistryKeyPath -Name AllowAllTrustedApps -Value 1 -ErrorAction Stop") -ErrorAction Stop;
273
+ if (!(IsElevated)) {
274
+ $scriptBlock = {
275
+ param($Path, $Name, $Value)
276
+ Set-ItemProperty -Path $Path -Name $Name -Value $Value -ErrorAction Stop
277
+ }
278
+ Invoke-ElevatedScriptBlock -ScriptBlock $scriptBlock `
279
+ -ArgumentList @($RegistryKeyPath, 'AllowAllTrustedApps', 1)
280
+ }
281
+ else {
282
+ Set-ItemProperty -Path $RegistryKeyPath -Name AllowAllTrustedApps -Value 1 -ErrorAction Stop
283
+ }
132
284
  }
133
285
  }
134
286
 
@@ -174,22 +326,44 @@ function CheckIfNeedInstallCertificate
174
326
  return (-not $Valid)
175
327
  }
176
328
 
329
+ <#
330
+ .SYNOPSIS
331
+ Installs an app package using Add-AppDevPackage.ps1 script.
332
+ .DESCRIPTION
333
+ SDL CE.10116 FIX: Replaced Invoke-Expression with call operator (&) and
334
+ parameterized ScriptBlock for elevated execution.
335
+ #>
177
336
  function Install-App {
178
337
  param(
179
338
  [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)]
180
339
  [string] $Path, <# Full path to Add-AppDevPackage.ps1 #>
181
340
  [switch] $Force = $false
182
341
  )
183
- $needInstallCertificate = CheckIfNeedInstallCertificate (Join-Path $Path "..");
342
+
343
+ # SDL FIX: Validate script path
344
+ $Path = Validate-ScriptPath -Path $Path
345
+
346
+ $needInstallCertificate = CheckIfNeedInstallCertificate (Join-Path $Path "..")
347
+
184
348
  if (!$Force -and ((CheckIfNeedDeveloperLicense) -or ($needInstallCertificate)))
185
349
  {
186
- # we can't run the script with -force param if license/certificate installation step is required
187
- Invoke-Expression ("& `"$Path`"")
350
+ # SDL FIX: Use call operator (&) instead of Invoke-Expression
351
+ # No user input in path (validated above), so safe to execute
352
+ & $Path
188
353
  }
189
354
  else
190
355
  {
191
- $Path = [System.IO.Path]::GetFullPath($Path);
192
- Invoke-Expression-MayElevate("`"$Path`" -force") -ErrorAction Stop;
356
+ # SDL FIX: Use parameterized ScriptBlock for elevation
357
+ if (!(IsElevated)) {
358
+ $scriptBlock = {
359
+ param($ScriptPath)
360
+ & $ScriptPath -Force
361
+ }
362
+ Invoke-ElevatedScriptBlock -ScriptBlock $scriptBlock -ArgumentList @($Path)
363
+ }
364
+ else {
365
+ & $Path -Force
366
+ }
193
367
  }
194
368
  }
195
369
 
@@ -220,6 +394,9 @@ function Start-Locally {
220
394
  [string[]] $argv
221
395
  )
222
396
 
397
+ # SDL FIX: Validate package ID
398
+ Validate-PackageIdentifier -PackageId $ID | Out-Null
399
+
223
400
  $package = Get-AppxPackage $ID
224
401
  $manifest = Get-appxpackagemanifest $package
225
402
  $applicationUserModelId = $package.PackageFamilyName + "!" + $manifest.package.applications.application.id
@@ -240,7 +417,6 @@ function Start-Locally {
240
417
  }
241
418
  }
242
419
 
243
-
244
420
  function Map-PackageNameToPackage {
245
421
  param([Parameter(Mandatory=$true)] [string]$DependenciesPath)
246
422
  $mapP2N = @{};
@@ -272,3 +448,18 @@ function Install-AppDependencies {
272
448
  $packagePaths = $packageNamesToInstall | % { $map[$_] }
273
449
  $packagePaths | % { Add-AppxPackage -Path $_ }
274
450
  }
451
+
452
+ #endregion
453
+
454
+ # Export functions
455
+ Export-ModuleMember -Function @(
456
+ 'Uninstall-App',
457
+ 'EnableDevmode',
458
+ 'CheckIfNeedDeveloperLicense',
459
+ 'CheckIfNeedInstallCertificate',
460
+ 'Install-App',
461
+ 'Install-AppFromDirectory',
462
+ 'Install-AppFromAppx',
463
+ 'Start-Locally',
464
+ 'Install-AppDependencies'
465
+ )