easy-devops 0.1.8 → 0.1.9
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/cli/managers/ssl-manager.js +98 -13
- package/package.json +1 -1
|
@@ -310,51 +310,106 @@ async function installCertbot() {
|
|
|
310
310
|
}
|
|
311
311
|
|
|
312
312
|
const hasCurl = (await run('where.exe curl.exe 2>$null')).success;
|
|
313
|
+
let lastDownloadError = '';
|
|
313
314
|
|
|
314
|
-
async function downloadFile(url, dest) {
|
|
315
|
+
async function downloadFile(url, dest, showErrors = false) {
|
|
315
316
|
const safeUrl = url.replace(/'/g, "''");
|
|
316
317
|
const safeDest = dest.replace(/'/g, "''");
|
|
317
318
|
|
|
318
|
-
//
|
|
319
|
+
// Enable all TLS versions (1.0, 1.1, 1.2, 1.3) for maximum compatibility
|
|
320
|
+
const tlsSetup = `[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls13`;
|
|
321
|
+
|
|
322
|
+
// Method 1: Invoke-WebRequest with all TLS versions
|
|
319
323
|
let r = await run(
|
|
320
|
-
|
|
324
|
+
`${tlsSetup}; $ProgressPreference='SilentlyContinue'; Invoke-WebRequest -Uri '${safeUrl}' -OutFile '${safeDest}' -UseBasicParsing -TimeoutSec 120`,
|
|
321
325
|
{ timeout: 130000 },
|
|
322
326
|
);
|
|
323
327
|
if (r.success) return true;
|
|
328
|
+
if (showErrors && r.stderr) lastDownloadError = `Invoke-WebRequest: ${r.stderr}`;
|
|
324
329
|
|
|
325
|
-
// Method 2: WebClient
|
|
330
|
+
// Method 2: WebClient with TLS
|
|
326
331
|
r = await run(
|
|
327
|
-
|
|
332
|
+
`${tlsSetup}; (New-Object System.Net.WebClient).DownloadFile('${safeUrl}','${safeDest}')`,
|
|
328
333
|
{ timeout: 130000 },
|
|
329
334
|
);
|
|
330
335
|
if (r.success) return true;
|
|
336
|
+
if (showErrors && r.stderr && !lastDownloadError) lastDownloadError = `WebClient: ${r.stderr}`;
|
|
331
337
|
|
|
332
|
-
// Method 3: BITS
|
|
338
|
+
// Method 3: BITS Transfer
|
|
333
339
|
r = await run(
|
|
334
340
|
`Import-Module BitsTransfer -ErrorAction SilentlyContinue; Start-BitsTransfer -Source '${safeUrl}' -Destination '${safeDest}' -ErrorAction Stop`,
|
|
335
341
|
{ timeout: 130000 },
|
|
336
342
|
);
|
|
337
343
|
if (r.success) return true;
|
|
344
|
+
if (showErrors && r.stderr && !lastDownloadError) lastDownloadError = `BITS: ${r.stderr}`;
|
|
338
345
|
|
|
339
|
-
// Method 4: curl.exe
|
|
346
|
+
// Method 4: curl.exe (works on Windows 10+)
|
|
340
347
|
if (hasCurl) {
|
|
341
348
|
r = await run(
|
|
342
|
-
`curl.exe -L --ssl-no-revoke --
|
|
349
|
+
`curl.exe -L --ssl-no-revoke --max-time 120 -o '${safeDest}' '${safeUrl}'`,
|
|
343
350
|
{ timeout: 130000 },
|
|
344
351
|
);
|
|
345
352
|
if (r.success) return true;
|
|
353
|
+
if (showErrors && r.stderr && !lastDownloadError) lastDownloadError = `curl: ${r.stderr}`;
|
|
346
354
|
}
|
|
347
355
|
|
|
348
|
-
// Method 5: HttpClient
|
|
356
|
+
// Method 5: HttpClient with custom handler
|
|
357
|
+
r = await run(
|
|
358
|
+
`${tlsSetup}; $handler=[System.Net.Http.HttpClientHandler]::new(); $handler.ServerCertificateCustomValidationCallback={$true}; $handler.AllowAutoRedirect=$true; $hc=[System.Net.Http.HttpClient]::new($handler); $hc.DefaultRequestHeaders.Add('User-Agent','Mozilla/5.0 (Windows NT 10.0; Win64; x64)'); $hc.Timeout=[TimeSpan]::FromSeconds(120); $bytes=$hc.GetByteArrayAsync('${safeUrl}').GetAwaiter().GetResult(); [System.IO.File]::WriteAllBytes('${safeDest}',$bytes)`,
|
|
359
|
+
{ timeout: 130000 },
|
|
360
|
+
);
|
|
361
|
+
if (r.success) return true;
|
|
362
|
+
if (showErrors && r.stderr && !lastDownloadError) lastDownloadError = `HttpClient: ${r.stderr}`;
|
|
363
|
+
|
|
364
|
+
// Method 6: Certutil (built-in Windows tool)
|
|
365
|
+
r = await run(
|
|
366
|
+
`certutil.exe -urlcache -split -f "${safeUrl}" "${safeDest}"`,
|
|
367
|
+
{ timeout: 130000 },
|
|
368
|
+
);
|
|
369
|
+
if (r.success) return true;
|
|
370
|
+
if (showErrors && r.stderr && !lastDownloadError) lastDownloadError = `certutil: ${r.stderr}`;
|
|
371
|
+
|
|
372
|
+
// Method 7: PowerShell with DisableKeepAlive
|
|
349
373
|
r = await run(
|
|
350
|
-
|
|
374
|
+
`${tlsSetup}; $req=[System.Net.WebRequest]::Create('${safeUrl}'); $req.Method='GET'; $req.KeepAlive=$false; $req.UserAgent='Mozilla/5.0'; $resp=$req.GetResponse(); $stream=$resp.GetResponseStream(); $reader=[System.IO.BinaryReader]::new($stream); $bytes=$reader.ReadBytes($resp.ContentLength); $reader.Close(); [System.IO.File]::WriteAllBytes('${safeDest}',$bytes)`,
|
|
351
375
|
{ timeout: 130000 },
|
|
352
376
|
);
|
|
353
377
|
if (r.success) return true;
|
|
378
|
+
if (showErrors && r.stderr && !lastDownloadError) lastDownloadError = `WebRequest: ${r.stderr}`;
|
|
354
379
|
|
|
355
380
|
return false;
|
|
356
381
|
}
|
|
357
382
|
|
|
383
|
+
// Test network connectivity to common endpoints
|
|
384
|
+
async function testNetworkConnectivity() {
|
|
385
|
+
console.log(chalk.cyan('\n Testing network connectivity...'));
|
|
386
|
+
const tests = [
|
|
387
|
+
{ name: 'GitHub', url: 'https://github.com' },
|
|
388
|
+
{ name: 'Microsoft', url: 'https://microsoft.com' },
|
|
389
|
+
{ name: 'EFF', url: 'https://eff.org' },
|
|
390
|
+
];
|
|
391
|
+
const results = [];
|
|
392
|
+
|
|
393
|
+
for (const test of tests) {
|
|
394
|
+
const r = await run(`curl.exe -I --ssl-no-revoke --max-time 10 "${test.url}"`, { timeout: 15000 });
|
|
395
|
+
const success = r.success || r.stdout.includes('HTTP') || r.stdout.includes('200');
|
|
396
|
+
results.push({ name: test.name, success });
|
|
397
|
+
console.log(chalk.gray(` ${test.name}: ${success ? chalk.green('✓ Connected') : chalk.red('✗ Failed')}`));
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const allFailed = results.every(r => !r.success);
|
|
401
|
+
if (allFailed) {
|
|
402
|
+
console.log(chalk.yellow('\n ⚠ All external connections failed.'));
|
|
403
|
+
console.log(chalk.gray(' This could indicate:'));
|
|
404
|
+
console.log(chalk.gray(' • Firewall blocking outbound connections'));
|
|
405
|
+
console.log(chalk.gray(' • Proxy server required'));
|
|
406
|
+
console.log(chalk.gray(' • DNS resolution issues'));
|
|
407
|
+
console.log(chalk.gray(' • Antivirus blocking downloads'));
|
|
408
|
+
}
|
|
409
|
+
console.log();
|
|
410
|
+
return results;
|
|
411
|
+
}
|
|
412
|
+
|
|
358
413
|
async function runNsisInstaller(exePath) {
|
|
359
414
|
await run(
|
|
360
415
|
`$p = Start-Process -FilePath '${exePath}' -ArgumentList '/S' -PassThru -Wait; $p.ExitCode`,
|
|
@@ -517,6 +572,9 @@ async function installCertbot() {
|
|
|
517
572
|
// ── Method 7: Direct download win-acme (ZIP - smaller, no installer) ──────────
|
|
518
573
|
const WINACME_DEST = 'C:\\Program Files\\win-acme';
|
|
519
574
|
|
|
575
|
+
// Test network before attempting downloads
|
|
576
|
+
await testNetworkConnectivity();
|
|
577
|
+
|
|
520
578
|
step('Downloading win-acme from GitHub ...');
|
|
521
579
|
const winAcmeUrls = [
|
|
522
580
|
'https://github.com/win-acme/win-acme/releases/latest/download/win-acme.zip',
|
|
@@ -528,7 +586,8 @@ async function installCertbot() {
|
|
|
528
586
|
console.log(chalk.gray(` Downloading from ${hostname} ...`));
|
|
529
587
|
|
|
530
588
|
const zipDest = `$env:TEMP\\win-acme.zip`;
|
|
531
|
-
|
|
589
|
+
lastDownloadError = '';
|
|
590
|
+
if (await downloadFile(url, zipDest, true)) {
|
|
532
591
|
console.log(chalk.gray(' Extracting win-acme ...\n'));
|
|
533
592
|
await run(`New-Item -ItemType Directory -Force -Path '${WINACME_DEST}'`);
|
|
534
593
|
await run(`Expand-Archive -Path '${zipDest}' -DestinationPath '${WINACME_DEST}' -Force`);
|
|
@@ -541,6 +600,9 @@ async function installCertbot() {
|
|
|
541
600
|
console.log(chalk.yellow(' Extraction succeeded but verification failed, trying next...\n'));
|
|
542
601
|
} else {
|
|
543
602
|
console.log(chalk.yellow(` Could not download from ${hostname}`));
|
|
603
|
+
if (lastDownloadError) {
|
|
604
|
+
console.log(chalk.gray(` Error: ${lastDownloadError.substring(0, 200)}\n`));
|
|
605
|
+
}
|
|
544
606
|
}
|
|
545
607
|
}
|
|
546
608
|
|
|
@@ -556,7 +618,8 @@ async function installCertbot() {
|
|
|
556
618
|
const hostname = new URL(url).hostname;
|
|
557
619
|
step(`Downloading certbot installer from ${hostname} ...`);
|
|
558
620
|
|
|
559
|
-
|
|
621
|
+
lastDownloadError = '';
|
|
622
|
+
if (await downloadFile(url, INSTALLER_DEST, true)) {
|
|
560
623
|
console.log(chalk.gray(' Running installer silently ...\n'));
|
|
561
624
|
const ok = await runNsisInstaller(INSTALLER_DEST);
|
|
562
625
|
await run(`Remove-Item -Force '${INSTALLER_DEST}' -ErrorAction SilentlyContinue`);
|
|
@@ -564,6 +627,9 @@ async function installCertbot() {
|
|
|
564
627
|
console.log(chalk.yellow(' Installer ran but certbot not detected, trying next...\n'));
|
|
565
628
|
} else {
|
|
566
629
|
console.log(chalk.yellow(` Could not download from ${hostname}`));
|
|
630
|
+
if (lastDownloadError) {
|
|
631
|
+
console.log(chalk.gray(` Error: ${lastDownloadError.substring(0, 200)}\n`));
|
|
632
|
+
}
|
|
567
633
|
}
|
|
568
634
|
}
|
|
569
635
|
|
|
@@ -580,10 +646,29 @@ async function installCertbot() {
|
|
|
580
646
|
type: 'list',
|
|
581
647
|
name: 'localChoice',
|
|
582
648
|
message: 'What would you like to do?',
|
|
583
|
-
choices: [
|
|
649
|
+
choices: [
|
|
650
|
+
'Open download page in browser',
|
|
651
|
+
'Specify local installer path',
|
|
652
|
+
'Cancel'
|
|
653
|
+
],
|
|
584
654
|
}]));
|
|
585
655
|
} catch { return { success: false }; }
|
|
586
656
|
|
|
657
|
+
if (localChoice === 'Open download page in browser') {
|
|
658
|
+
console.log(chalk.cyan('\n Opening download pages in browser...'));
|
|
659
|
+
console.log(chalk.gray(' Download either win-acme.zip or certbot installer, then re-run this tool.\n'));
|
|
660
|
+
|
|
661
|
+
// Open win-acme releases
|
|
662
|
+
await run('Start-Process "https://github.com/win-acme/win-acme/releases/latest"');
|
|
663
|
+
// Also open EFF certbot page
|
|
664
|
+
await run('Start-Process "https://certbot.eff.org/instructions?ws=other&os=windows"');
|
|
665
|
+
|
|
666
|
+
console.log(chalk.green('✓ Browser opened. Download the installer, then run:'));
|
|
667
|
+
console.log(chalk.cyan(' easy-devops → SSL Manager → Install certbot → Specify local installer path\n'));
|
|
668
|
+
|
|
669
|
+
return { success: false };
|
|
670
|
+
}
|
|
671
|
+
|
|
587
672
|
if (localChoice === 'Specify local installer path') {
|
|
588
673
|
let localPath;
|
|
589
674
|
try {
|
package/package.json
CHANGED