homebridge-viessmann-vicare 2.0.5 → 2.0.7

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.
@@ -113,8 +113,11 @@ export declare class AuthManager {
113
113
  this.log.warn('⚠️ Error opening browser:', error);
114
114
  }
115
115
  }
116
+
117
+
116
118
  **/
117
119
  private openBrowser;
120
+ private tryOpenBrowserDirect;
118
121
  private exchangeCodeForTokens;
119
122
  refreshAccessToken(): Promise<void>;
120
123
  private setTokens;
@@ -1 +1 @@
1
- {"version":3,"file":"auth-manager.d.ts","sourceRoot":"","sources":["../src/auth-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth-manager.d.ts","sourceRoot":"","sources":["../src/auth-manager.ts"],"names":[],"mappings":"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"}
@@ -422,41 +422,56 @@ class AuthManager {
422
422
  async performFullAuth() {
423
423
  return new Promise((resolve, reject) => {
424
424
  const authUrl = this.buildAuthUrl();
425
- this.log.info('='.repeat(80));
426
- this.log.info('🔐 VIESSMANN OAUTH AUTHENTICATION');
427
- this.log.info('='.repeat(80));
428
- this.log.info('⚠️ CRITICAL: You have only 20 seconds after browser authorization!');
429
- this.log.info('');
430
- this.log.info('🔗 Please open this URL in your browser to authenticate:');
431
- this.log.info('');
432
- this.log.info(authUrl);
433
- this.log.info('');
434
- this.log.info('⏳ Waiting for authentication callback...');
435
- const authTimeout = this.config.authTimeout || 300000;
436
- this.log.info(`⏰ This process will timeout after ${authTimeout / 1000} seconds.`);
437
- this.log.info('='.repeat(80));
425
+ const isSystemdService = !!(process.env.SYSTEMD_EXEC_PID || process.env.INVOCATION_ID);
426
+ if (isSystemdService) {
427
+ // Messaggio semplificato per servizi
428
+ this.log.info('='.repeat(80));
429
+ this.log.info('🔐 VIESSMANN AUTHENTICATION REQUIRED');
430
+ this.log.info('='.repeat(80));
431
+ }
432
+ else {
433
+ // Messaggio dettagliato per installazioni desktop
434
+ this.log.info('='.repeat(80));
435
+ this.log.info('🔐 VIESSMANN OAUTH AUTHENTICATION');
436
+ this.log.info('='.repeat(80));
437
+ this.log.info('⚠️ CRITICAL: You have only 20 seconds after browser authorization!');
438
+ this.log.info('');
439
+ }
438
440
  // Set timeout for authentication process
441
+ const authTimeout = this.config.authTimeout || 300000;
439
442
  this.authTimeout = setTimeout(() => {
440
443
  this.stopAuthServer();
441
444
  reject(new Error(`Authentication timeout - no response received within ${authTimeout / 1000} seconds`));
442
445
  }, authTimeout);
443
446
  // Start local server to capture callback
444
447
  this.startAuthServer((code, error) => {
445
- if (this.authTimeout) {
446
- clearTimeout(this.authTimeout);
447
- this.authTimeout = undefined;
448
- }
449
448
  if (error) {
449
+ if (this.authTimeout) {
450
+ clearTimeout(this.authTimeout);
451
+ this.authTimeout = undefined;
452
+ }
450
453
  reject(error);
451
454
  return;
452
455
  }
453
456
  if (code) {
454
457
  this.exchangeCodeForTokens(code)
455
- .then(() => resolve())
456
- .catch(reject);
458
+ .then(() => {
459
+ if (this.authTimeout) {
460
+ clearTimeout(this.authTimeout);
461
+ this.authTimeout = undefined;
462
+ }
463
+ resolve();
464
+ })
465
+ .catch((err) => {
466
+ if (this.authTimeout) {
467
+ clearTimeout(this.authTimeout);
468
+ this.authTimeout = undefined;
469
+ }
470
+ reject(err);
471
+ });
457
472
  }
458
473
  });
459
- // Auto-open browser if possible
474
+ // Try to open browser (will show URL if systemd service)
460
475
  this.openBrowser(authUrl);
461
476
  });
462
477
  }
@@ -472,10 +487,13 @@ class AuthManager {
472
487
  return `${this.authURL}/authorize?${params.toString()}`;
473
488
  }
474
489
  startAuthServer(callback) {
490
+ // Verifica se server è già attivo
491
+ if (this.authServer && this.authServer.listening) {
492
+ this.log.debug('🟢 Auth server already listening, reusing existing server');
493
+ return;
494
+ }
475
495
  this.authServer = http.createServer((req, res) => {
476
496
  const url = new URL(req.url, `http://localhost:${this.config.redirectPort || 4200}`);
477
- this.log.warn(`🟢 Auth server listening on http://${this.hostIp}:${this.config.redirectPort || 4200}/`);
478
- this.log.warn(`👉 If the browser does not open automatically, open this URL manually from another device:\nhttp://${this.hostIp}:${this.config.redirectPort || 4200}/login`);
479
497
  if (url.pathname === '/') {
480
498
  const code = url.searchParams.get('code');
481
499
  const error = url.searchParams.get('error');
@@ -483,42 +501,60 @@ class AuthManager {
483
501
  const errorDescription = url.searchParams.get('error_description') || error;
484
502
  res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
485
503
  res.end(`
486
- <html>
487
- <head><title>Authentication Failed</title></head>
488
- <body style="font-family: -apple-system, sans-serif; text-align: center; padding: 50px;">
489
- <h1 style="color: #ff4757;">❌ Authentication Failed</h1>
490
- <p>${errorDescription}</p>
491
- <p>Please close this window and check your Homebridge logs.</p>
492
- </body>
493
- </html>
494
- `);
504
+ <html>
505
+ <head><title>Authentication Failed</title></head>
506
+ <body style="font-family: -apple-system, sans-serif; text-align: center; padding: 50px;">
507
+ <h1 style="color: #ff4757;">❌ Authentication Failed</h1>
508
+ <p>${errorDescription}</p>
509
+ <p>Please close this window and check your Homebridge logs.</p>
510
+ </body>
511
+ </html>
512
+ `);
495
513
  callback(undefined, new Error(`OAuth error: ${errorDescription}`));
496
- //this.stopAuthServer();
514
+ // 🆕 Chiudi dopo un delay per far vedere la pagina
515
+ setTimeout(() => this.stopAuthServer(), 3000);
497
516
  return;
498
517
  }
499
518
  if (code) {
500
519
  res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
501
520
  res.end(`
502
- <html>
503
- <head><title>Authentication Successful</title></head>
504
- <body style="font-family: -apple-system, sans-serif; text-align: center; padding: 50px;">
505
- <h1 style="color: #2ed573;">✅ Authentication Successful!</h1>
506
- <p>You can now close this window.</p>
507
- <p>Homebridge will continue setup automatically.</p>
508
- </body>
509
- </html>
510
- `);
521
+ <html>
522
+ <head><title>Authentication Successful</title></head>
523
+ <body style="font-family: -apple-system, sans-serif; text-align: center; padding: 50px;">
524
+ <h1 style="color: #2ed573;">✅ Authentication Successful!</h1>
525
+ <p>You can now close this window.</p>
526
+ <p>Homebridge will continue setup automatically.</p>
527
+ </body>
528
+ </html>
529
+ `);
511
530
  callback(code);
512
- //this.stopAuthServer();
531
+ // 🆕 Chiudi dopo un delay per far vedere la pagina
532
+ setTimeout(() => this.stopAuthServer(), 3000);
513
533
  return;
514
534
  }
515
535
  }
516
- // Handle other requests
536
+ // Handle other requests - root path senza parametri
537
+ if (url.pathname === '/') {
538
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
539
+ res.end(`
540
+ <html>
541
+ <head><title>Viessmann Authentication</title></head>
542
+ <body style="font-family: -apple-system, sans-serif; text-align: center; padding: 50px;">
543
+ <h1>🔐 Viessmann Authentication</h1>
544
+ <p>Waiting for authentication callback...</p>
545
+ <p>If you see this page, the authentication server is working correctly.</p>
546
+ <p style="color: #666; font-size: 14px;">Server: ${this.hostIp}:${this.config.redirectPort || 4200}</p>
547
+ </body>
548
+ </html>
549
+ `);
550
+ return;
551
+ }
552
+ // 404 per altre richieste
517
553
  res.writeHead(404, { 'Content-Type': 'text/plain' });
518
554
  res.end('Not found');
519
555
  });
520
- this.authServer.listen(this.config.redirectPort || 4200, () => {
521
- this.log.debug(`🌐 Auth server listening on ${this.hostIp}:${this.config.redirectPort || 4200}`);
556
+ this.authServer.listen(this.config.redirectPort || 4200, '0.0.0.0', () => {
557
+ this.log.info(`🟢 Auth server ready at: http://${this.hostIp}:${this.config.redirectPort || 4200}/`);
522
558
  });
523
559
  this.authServer.on('error', (error) => {
524
560
  this.log.error('❌ Auth server error:', error);
@@ -570,99 +606,58 @@ class AuthManager {
570
606
  this.log.warn('⚠️ Error opening browser:', error);
571
607
  }
572
608
  }
609
+
610
+
573
611
  **/
574
612
  openBrowser(url) {
575
- const { execFile, exec } = require('child_process');
576
- const tryExecFile = (cmd, args, env) => new Promise((resolve, reject) => {
577
- execFile(cmd, args, { env }, (err) => err ? reject(err) : resolve());
578
- });
579
- const tryExec = (command, env) => new Promise((resolve, reject) => {
580
- exec(command, { env }, (err) => err ? reject(err) : resolve());
581
- });
582
- // Copia pulita dell'ambiente
583
- const env = { ...process.env };
584
- // Migliora compatibilità Linux (X/Wayland) senza toccare il servizio
585
- if (process.platform === 'linux') {
586
- if (!env.DISPLAY) {
587
- // fallback tipico X11
588
- env.DISPLAY = ':0';
589
- }
590
- if (!env.XDG_RUNTIME_DIR && typeof process.getuid === 'function') {
591
- env.XDG_RUNTIME_DIR = `/run/user/${process.getuid()}`;
592
- }
613
+ // 🆕 Per servizi systemd: NON tentare di aprire automaticamente
614
+ // L'utente può aprire da qualsiasi dispositivo sulla rete
615
+ const isSystemdService = !!(process.env.SYSTEMD_EXEC_PID || process.env.INVOCATION_ID);
616
+ const isHomebridge = process.env.USER === 'homebridge';
617
+ // Se siamo in un servizio systemd o utente homebridge, non aprire automaticamente
618
+ if (isSystemdService || isHomebridge) {
619
+ this.log.info('='.repeat(80));
620
+ this.log.info('🔐 AUTHENTICATION REQUIRED');
621
+ this.log.info('='.repeat(80));
622
+ this.log.info('');
623
+ this.log.info('📱 Open this URL from ANY device on your network:');
624
+ this.log.info('');
625
+ this.log.info(` ${url}`);
626
+ this.log.info('');
627
+ this.log.info('✅ You can open it from:');
628
+ this.log.info(' • Your computer/laptop');
629
+ this.log.info(' • Your smartphone/tablet');
630
+ this.log.info(' • This Raspberry Pi (if you have a browser)');
631
+ this.log.info('');
632
+ this.log.info(`🌐 Auth server is listening on: ${this.hostIp}:${this.config.redirectPort || 4200}`);
633
+ this.log.info('⏳ Waiting for authentication...');
634
+ this.log.info('='.repeat(80));
635
+ return;
593
636
  }
594
- const tryLinux = async () => {
595
- // 1) Standard freedesktop
596
- try {
597
- await tryExecFile('xdg-open', [url], env);
598
- this.log.debug('🌐 xdg-open OK');
599
- return;
600
- }
601
- catch { }
602
- // 2) Gio / GVFS
603
- try {
604
- await tryExec(`gio open "${url}"`, env);
605
- this.log.debug('🌐 gio open OK');
606
- return;
607
- }
608
- catch { }
609
- // 3) Debian-like helpers
610
- try {
611
- await tryExecFile('sensible-browser', [url], env);
612
- this.log.debug('🌐 sensible-browser OK');
613
- return;
614
- }
615
- catch { }
616
- try {
617
- await tryExecFile('x-www-browser', [url], env);
618
- this.log.debug('🌐 x-www-browser OK');
619
- return;
620
- }
621
- catch { }
622
- // 4) xdg-desktop-portal (DBus OpenURI) — compatibile Wayland/X
623
- try {
624
- await tryExec(`gdbus call --session ` +
625
- `--dest org.freedesktop.portal.Desktop ` +
626
- `--object-path /org/freedesktop/portal/desktop ` +
627
- `--method org.freedesktop.portal.OpenURI.OpenURI "" "${url}" "{}"`, env);
628
- this.log.debug('🌐 xdg-desktop-portal OpenURI OK');
629
- return;
630
- }
631
- catch { }
632
- // 5) backend specifici (best-effort, non bloccanti)
633
- try {
634
- await tryExecFile('kde-open5', [url], env);
635
- this.log.debug('🌐 kde-open5 OK');
636
- return;
637
- }
638
- catch { }
639
- try {
640
- await tryExecFile('gnome-open', [url], env);
641
- this.log.debug('🌐 gnome-open OK');
642
- return;
643
- }
644
- catch { }
645
- // Nessun metodo disponibile/riuscito
646
- throw new Error('No Linux opener succeeded');
647
- };
648
- (async () => {
649
- try {
650
- switch (process.platform) {
651
- case 'darwin':
652
- await tryExec(`open "${url}"`, env);
653
- break;
654
- case 'win32':
655
- await tryExec(`start "" "${url}"`, env);
656
- break;
657
- default:
658
- await tryLinux();
659
- }
660
- this.log.info('✅ Tentativo di apertura browser completato');
637
+ // Solo per installazioni non-systemd (es. macOS, sviluppo locale)
638
+ this.tryOpenBrowserDirect(url);
639
+ }
640
+ tryOpenBrowserDirect(url) {
641
+ const { exec } = require('child_process');
642
+ let command;
643
+ switch (process.platform) {
644
+ case 'darwin':
645
+ command = `open "${url}"`;
646
+ break;
647
+ case 'win32':
648
+ command = `start "" "${url}"`;
649
+ break;
650
+ default: // Linux desktop (non-systemd)
651
+ command = `xdg-open "${url}" 2>/dev/null || firefox "${url}" 2>/dev/null || chromium-browser "${url}" 2>/dev/null`;
652
+ }
653
+ exec(command, (error) => {
654
+ if (error) {
655
+ this.log.info('📱 Please open the authentication URL manually in your browser');
661
656
  }
662
- catch (e) {
663
- this.log.warn(`⚠️ Impossibile aprire automaticamente il browser (${e?.message || e}). Apri l’URL manualmente.`);
657
+ else {
658
+ this.log.info('🌐 Opening browser...');
664
659
  }
665
- })();
660
+ });
666
661
  }
667
662
  async exchangeCodeForTokens(authCode) {
668
663
  const tokenData = new url_1.URLSearchParams({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homebridge-viessmann-vicare",
3
- "version": "2.0.5",
3
+ "version": "2.0.7",
4
4
  "description": "Complete Homebridge plugin for Viessmann ViCare heating systems with full control capabilities, advanced rate limiting protection, and intelligent cache management",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {