@mikeyt23/node-cli-utils 1.3.1 → 1.4.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.
Files changed (2) hide show
  1. package/index.js +142 -23
  2. package/package.json +4 -3
package/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  const fs = require('fs')
2
2
  const fsp = require('fs').promises
3
+ const fse = require('fs-extra')
3
4
  const which = require('which')
4
- const {spawn, spawnSync} = require('child_process')
5
+ const { spawn, spawnSync } = require('child_process')
5
6
  const path = require('path')
6
7
  const tar = require('tar')
7
8
 
@@ -9,7 +10,7 @@ const defaultSpawnOptions = {
9
10
  shell: true,
10
11
  stdio: ['ignore', 'inherit', 'inherit']
11
12
  }
12
- const defaultSpawnOptionsWithInput = {...defaultSpawnOptions, stdio: 'inherit'}
13
+ const defaultSpawnOptionsWithInput = { ...defaultSpawnOptions, stdio: 'inherit' }
13
14
 
14
15
  function waitForProcess(childProcess) {
15
16
  return new Promise((resolve, reject) => {
@@ -39,7 +40,7 @@ async function throwIfDockerNotRunning() {
39
40
  throw Error('docker command not found')
40
41
  }
41
42
 
42
- let childProcess = spawnSync('docker', ['info'], {encoding: 'utf8'})
43
+ let childProcess = spawnSync('docker', ['info'], { encoding: 'utf8' })
43
44
  if (childProcess.error) {
44
45
  throw childProcess.error
45
46
  }
@@ -51,7 +52,7 @@ async function throwIfDockerNotRunning() {
51
52
  async function bashIntoRunningDockerContainer(containerNamePartial, entryPoint = 'bash') {
52
53
  await throwIfDockerNotRunning()
53
54
 
54
- let childProcess = spawnSync('docker', ['container', 'ls'], {encoding: 'utf8'})
55
+ let childProcess = spawnSync('docker', ['container', 'ls'], { encoding: 'utf8' })
55
56
  if (childProcess.error) {
56
57
  throw childProcess.error
57
58
  }
@@ -79,7 +80,7 @@ async function bashIntoRunningDockerContainer(containerNamePartial, entryPoint =
79
80
  async function dockerContainerIsRunning(containerNamePartial) {
80
81
  await throwIfDockerNotRunning()
81
82
 
82
- let childProcess = spawnSync('docker', ['container', 'ls'], {encoding: 'utf8'})
83
+ let childProcess = spawnSync('docker', ['container', 'ls'], { encoding: 'utf8' })
83
84
  if (childProcess.error) {
84
85
  throw childProcess.error
85
86
  }
@@ -188,12 +189,12 @@ async function createTarball(directoryToTarball, outputDirectory, tarballName, c
188
189
  }
189
190
  }
190
191
 
191
- let options = {gzip: true, file: tarballPath}
192
+ let options = { gzip: true, file: tarballPath }
192
193
  if (!!cwd) {
193
194
  options.cwd = cwd
194
195
  }
195
196
 
196
- await tar.c(options, [directoryToTarball])
197
+ tar.c(options, [directoryToTarball])
197
198
  }
198
199
 
199
200
  async function dockerCompose(command, projectName, dockerRelativeDirectory = 'docker', detached = false) {
@@ -210,7 +211,7 @@ async function dockerCompose(command, projectName, dockerRelativeDirectory = 'do
210
211
 
211
212
  await throwIfDockerNotRunning()
212
213
 
213
- const dockerSpawnOptions = {...defaultSpawnOptions, cwd: dockerWorkingDir, stdio: 'inherit'}
214
+ const dockerSpawnOptions = { ...defaultSpawnOptions, cwd: dockerWorkingDir, stdio: 'inherit' }
214
215
 
215
216
  let args = ['--project-name', projectName, command]
216
217
  if (detached) {
@@ -255,7 +256,7 @@ async function dotnetPack(projectDirectoryPath, release = true) {
255
256
  args.push('-c', 'Release')
256
257
  }
257
258
 
258
- const spawnOptions = {...defaultSpawnOptions, cwd: projectDirectoryPath}
259
+ const spawnOptions = { ...defaultSpawnOptions, cwd: projectDirectoryPath }
259
260
  logCommand('dotnet', args, spawnOptions)
260
261
  await waitForProcess(spawn('dotnet', args, spawnOptions))
261
262
  }
@@ -270,7 +271,7 @@ async function dotnetNugetPublish(projectDirectoryPath, csprojFilename, release
270
271
 
271
272
  const packageName = await getPackageName(projectDirectoryPath, csprojFilename)
272
273
  console.log('publishing package ' + packageName)
273
- const spawnOptions = {...defaultSpawnOptions, cwd: packageDir}
274
+ const spawnOptions = { ...defaultSpawnOptions, cwd: packageDir }
274
275
  await waitForProcess(spawn('dotnet', [
275
276
  'nuget',
276
277
  'push',
@@ -304,21 +305,21 @@ async function dotnetDllCommand(relativeDllPath, argsArray, cwd = null, useStdin
304
305
 
305
306
  let args = [relativeDllPath, ...argsArray]
306
307
 
307
- let spawnOptions = {...defaultSpawnOptions}
308
+ let spawnOptions = { ...defaultSpawnOptions }
308
309
  if (cwd !== null) {
309
- spawnOptions = {...spawnOptions, cwd: cwd}
310
+ spawnOptions = { ...spawnOptions, cwd: cwd }
310
311
  }
311
312
  if (useStdin) {
312
- spawnOptions = {...spawnOptions, stdio: 'inherit'}
313
+ spawnOptions = { ...spawnOptions, stdio: 'inherit' }
313
314
  }
314
315
 
315
316
  return waitForProcess(spawn('dotnet', args, spawnOptions))
316
317
  }
317
318
 
318
319
  async function dotnetPublish(cwd = null, outputDir = 'publish') {
319
- let spawnOptions = {...defaultSpawnOptions}
320
+ let spawnOptions = { ...defaultSpawnOptions }
320
321
  if (!!cwd) {
321
- spawnOptions = {...spawnOptions, cwd: cwd}
322
+ spawnOptions = { ...spawnOptions, cwd: cwd }
322
323
  }
323
324
  if (!outputDir) {
324
325
  outputDir = 'publish'
@@ -330,7 +331,7 @@ async function dotnetPublish(cwd = null, outputDir = 'publish') {
330
331
  async function dotnetDbMigrationsList(dbContextName, relativeDbMigratorDirectoryPath) {
331
332
  throwIfRequiredIsFalsy(dbContextName, 'dbContextName')
332
333
  throwIfRequiredIsFalsy(relativeDbMigratorDirectoryPath, 'relativeDbMigratorDirectoryPath')
333
- let spawnOptions = {...defaultSpawnOptions, cwd: relativeDbMigratorDirectoryPath}
334
+ let spawnOptions = { ...defaultSpawnOptions, cwd: relativeDbMigratorDirectoryPath }
334
335
  return waitForProcess(spawn('dotnet', ['ef', 'migrations', 'list', '--context', dbContextName], spawnOptions))
335
336
  }
336
337
 
@@ -342,7 +343,7 @@ async function dotnetDbMigrate(dbContextName, relativeDbMigratorDirectoryPath, m
342
343
  args.push(migrationName)
343
344
  }
344
345
  args = [...args, '--context', dbContextName]
345
- let spawnOptions = {...defaultSpawnOptions, cwd: relativeDbMigratorDirectoryPath}
346
+ let spawnOptions = { ...defaultSpawnOptions, cwd: relativeDbMigratorDirectoryPath }
346
347
  return waitForProcess(spawn('dotnet', args, spawnOptions))
347
348
  }
348
349
 
@@ -354,7 +355,7 @@ async function dotnetDbAddMigration(dbContextName, relativeDbMigratorDirectoryPa
354
355
  const migrationsOutputDir = `Migrations/${dbContextName}Migrations`
355
356
 
356
357
  let args = ['ef', 'migrations', 'add', migrationName, '--context', dbContextName, '-o', migrationsOutputDir]
357
- let spawnOptions = {...defaultSpawnOptions, cwd: relativeDbMigratorDirectoryPath}
358
+ let spawnOptions = { ...defaultSpawnOptions, cwd: relativeDbMigratorDirectoryPath }
358
359
  await waitForProcess(spawn('dotnet', args, spawnOptions))
359
360
 
360
361
  if (withBoilerplate) {
@@ -388,7 +389,7 @@ async function dotnetDbAddMigrationBoilerplate(dbContextName, relativeDbMigrator
388
389
  const upLine = `MigrationScriptRunner.RunScript(migrationBuilder, "${migrationName}.sql");`
389
390
  const downLine = `MigrationScriptRunner.RunScript(migrationBuilder, "${migrationName}_Down.sql");`
390
391
 
391
- const fileContents = await fsp.readFile(filePath, {encoding: 'utf8'})
392
+ const fileContents = await fsp.readFile(filePath, { encoding: 'utf8' })
392
393
  let lines = fileContents.replaceAll('\r', '').split('\n')
393
394
 
394
395
  let newLines = []
@@ -429,7 +430,7 @@ async function dotnetDbAddMigrationBoilerplate(dbContextName, relativeDbMigrator
429
430
 
430
431
  const newFileContents = newLines.join('\n')
431
432
 
432
- await fsp.writeFile(filePath, newFileContents, {encoding: 'utf8'})
433
+ await fsp.writeFile(filePath, newFileContents, { encoding: 'utf8' })
433
434
 
434
435
  console.log(`Updated file with boilerplate - please ensure it is correct: ${filePath}`)
435
436
 
@@ -441,13 +442,13 @@ async function dotnetDbAddMigrationBoilerplate(dbContextName, relativeDbMigrator
441
442
  console.log(` - ${downScriptPath}`)
442
443
 
443
444
  if (!fs.existsSync(upScriptPath)) {
444
- await fsp.writeFile(upScriptPath, '', {encoding: 'utf8'})
445
+ await fsp.writeFile(upScriptPath, '', { encoding: 'utf8' })
445
446
  } else {
446
447
  console.log('Skipping Up sql script (already exists)')
447
448
  }
448
449
 
449
450
  if (!fs.existsSync(downScriptPath)) {
450
- await fsp.writeFile(downScriptPath, '', {encoding: 'utf8'})
451
+ await fsp.writeFile(downScriptPath, '', { encoding: 'utf8' })
451
452
  } else {
452
453
  console.log('Skipping Down sql script (already exists)')
453
454
  }
@@ -456,7 +457,7 @@ async function dotnetDbAddMigrationBoilerplate(dbContextName, relativeDbMigrator
456
457
  async function dotnetDbRemoveMigration(dbContextName, relativeDbMigratorDirectoryPath) {
457
458
  throwIfRequiredIsFalsy(dbContextName, 'dbContextName')
458
459
  throwIfRequiredIsFalsy(relativeDbMigratorDirectoryPath, 'relativeDbMigratorDirectoryPath')
459
- let spawnOptions = {...defaultSpawnOptions, cwd: relativeDbMigratorDirectoryPath}
460
+ let spawnOptions = { ...defaultSpawnOptions, cwd: relativeDbMigratorDirectoryPath }
460
461
  return waitForProcess(spawn('dotnet', ['ef', 'migrations', 'remove', '--context', dbContextName], spawnOptions))
461
462
  }
462
463
 
@@ -472,6 +473,120 @@ function throwIfRequiredArrayIsFalsyOrEmpty(requiredArrayArg, argName) {
472
473
  }
473
474
  }
474
475
 
476
+ async function generateCertWithOpenSsl(url, outputDirectory = './cert') {
477
+ if (!url) {
478
+ throw Error('Param \'url\' is required.')
479
+ }
480
+
481
+ // Check if openssl is installed
482
+ let macOpenSslPath
483
+ if (process.platform !== 'darwin') {
484
+ if (!which.sync('openssl', { nothrow: true })) {
485
+ throw Error('openssl is required but was not found in the path')
486
+ }
487
+ } else {
488
+ console.log('*****************************************************************')
489
+ console.log('* Important: mac support requires openssl be installed via brew *')
490
+ console.log('*****************************************************************')
491
+
492
+ macOpenSslPath = `${getBrewOpensslPath()}/bin/openssl`
493
+ console.log(`openssl path: ${macOpenSslPath}`)
494
+ }
495
+
496
+ console.log('openssl is installed, continuing...')
497
+
498
+ fse.mkdirpSync(outputDirectory)
499
+
500
+ const keyName = url + '.key'
501
+ const crtName = url + '.crt'
502
+ const pfxName = url + '.pfx'
503
+
504
+ pfxPath = path.join(outputDirectory, pfxName)
505
+
506
+ if (fse.pathExistsSync(pfxPath)) {
507
+ throw Error(`File ${pfxPath} already exists. Delete this first if you want to generate a new version.`)
508
+ }
509
+
510
+ console.log(`attempting to generate cert ${pfxName}`)
511
+
512
+ const genCertSpawnArgs = { ...defaultSpawnOptions, cwd: outputDirectory }
513
+
514
+ const genKeyAndCrtArgs = `req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout ${keyName} -out ${crtName} -subj "/CN=${url}" -addext "subjectAltName=DNS:${url},IP:127.0.0.1"`.split(' ')
515
+
516
+ const cmd = process.platform !== 'darwin' ? 'openssl' : macOpenSslPath
517
+
518
+ console.log('cmd: ' + cmd)
519
+
520
+ await waitForProcess(spawn(cmd, genKeyAndCrtArgs, genCertSpawnArgs))
521
+
522
+ console.log('converting key and crt to pfx...')
523
+
524
+ const convertToPfxArgs = `pkcs12 -certpbe AES-256-CBC -export -out ${pfxName} -aes256 -inkey ${keyName} -in ${crtName} -password pass:`.split(' ')
525
+
526
+ await waitForProcess(spawn(cmd, convertToPfxArgs, genCertSpawnArgs))
527
+ }
528
+
529
+ function getBrewOpensslPath() {
530
+ let childProc = spawnSync('brew', ['--prefix', 'openssl'], { encoding: 'utf-8' })
531
+ if (childProc.error) {
532
+ throw Error('error attempting to find openssl installed by brew')
533
+ }
534
+
535
+ const output = childProc.stdout
536
+
537
+ if (!output || output.length === 0 || output.toLowerCase().startsWith('error')) {
538
+ throw Error('unexpected output while attempting to find openssl')
539
+ }
540
+
541
+ return output.replace('\n', '')
542
+ }
543
+
544
+ async function winInstallCert(urlOrCertFilename, relativeCertDirectoryPath = './cert') {
545
+ if (!urlOrCertFilename) {
546
+ throw Error('Param \'urlOrCertFilename\' is required.')
547
+ }
548
+
549
+ console.log('******************************\n* Requires admin permissions *\n******************************')
550
+
551
+ let certName = urlOrCertFilename.endsWith('.pfx') ? urlOrCertFilename : urlOrCertFilename + '.pfx'
552
+
553
+ const certPath = path.join(process.cwd(), relativeCertDirectoryPath, certName)
554
+
555
+ if (!fse.pathExistsSync(certPath)) {
556
+ throw Error(`File ${certPath} does not exist. Generate this first if you want to install it.`)
557
+ }
558
+
559
+ const psCommand = `$env:PSModulePath = [Environment]::GetEnvironmentVariable('PSModulePath', 'Machine'); Import-PfxCertificate -FilePath '${certPath}' -CertStoreLocation Cert:\\LocalMachine\\Root`
560
+
561
+ await waitForProcess(spawn('powershell', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command', psCommand]))
562
+ }
563
+
564
+ async function winUninstallCert(urlOrSubject) {
565
+ if (!urlOrSubject) {
566
+ throw Error('Param \'urlOrSubject\' is required.')
567
+ }
568
+
569
+ console.log('******************************\n* Requires admin permissions *\n******************************')
570
+
571
+ const psCommand = `$env:PSModulePath = [Environment]::GetEnvironmentVariable('PSModulePath', 'Machine'); Get-ChildItem Cert:\\LocalMachine\\Root | Where-Object { $_.Subject -match '${urlOrSubject}' } | Remove-Item`;
572
+
573
+ await waitForProcess(spawn('powershell', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command', psCommand]))
574
+ }
575
+
576
+ function linuxInstallCert() {
577
+ const instructions = `
578
+ Automated linux cert install not supported (chrome does not use system certs without significant extra configuration).
579
+
580
+ Manual Instructions:
581
+ - In Chrome, go to chrome://settings/certificates
582
+ - Select Authorities -> import
583
+ - Select your generated .crt file (in the ./cert/ directory by default - if you haven't generated it, see the generateCertWithOpenSsl method)
584
+ - Check box for "Trust certificate for identifying websites"
585
+ - Click OK
586
+ - Reload site`
587
+ console.log(instructions)
588
+ }
589
+
475
590
  exports.defaultSpawnOptions = defaultSpawnOptions
476
591
  exports.defaultSpawnOptionsWithInput = defaultSpawnOptionsWithInput
477
592
  exports.waitForProcess = waitForProcess
@@ -494,3 +609,7 @@ exports.dotnetDbMigrationsList = dotnetDbMigrationsList
494
609
  exports.dotnetDbMigrate = dotnetDbMigrate
495
610
  exports.dotnetDbAddMigration = dotnetDbAddMigration
496
611
  exports.dotnetDbRemoveMigration = dotnetDbRemoveMigration
612
+ exports.generateCertWithOpenSsl = generateCertWithOpenSsl
613
+ exports.winInstallCert = winInstallCert
614
+ exports.winUninstallCert = winUninstallCert
615
+ exports.linuxInstallCert = linuxInstallCert
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikeyt23/node-cli-utils",
3
- "version": "1.3.1",
3
+ "version": "1.4.0",
4
4
  "description": "Some node cli utility functions",
5
5
  "author": "Mike Thompson",
6
6
  "license": "MIT",
@@ -15,7 +15,8 @@
15
15
  },
16
16
  "main": "index.js",
17
17
  "dependencies": {
18
- "tar": "^6.1.11",
19
- "which": "^2.0.2"
18
+ "fs-extra": "^11.1.1",
19
+ "tar": "^6.1.15",
20
+ "which": "^3.0.1"
20
21
  }
21
22
  }