homebridge-viessmann-vicare 2.0.6 β 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.
- package/dist/auth-manager.d.ts +1 -77
- package/dist/auth-manager.d.ts.map +1 -1
- package/dist/auth-manager.js +126 -318
- package/package.json +1 -1
package/dist/auth-manager.d.ts
CHANGED
|
@@ -114,86 +114,10 @@ export declare class AuthManager {
|
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
private openBrowser(url: string): void {
|
|
118
|
-
const { execFile, exec } = require('child_process');
|
|
119
117
|
|
|
120
|
-
const tryExecFile = (cmd: string, args: string[], env: NodeJS.ProcessEnv) =>
|
|
121
|
-
new Promise<void>((resolve, reject) => {
|
|
122
|
-
execFile(cmd, args, { env }, (err: any) => err ? reject(err) : resolve());
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
const tryExec = (command: string, env: NodeJS.ProcessEnv) =>
|
|
126
|
-
new Promise<void>((resolve, reject) => {
|
|
127
|
-
exec(command, { env }, (err: any) => err ? reject(err) : resolve());
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
// Copia pulita dell'ambiente
|
|
131
|
-
const env: NodeJS.ProcessEnv = { ...process.env };
|
|
132
|
-
|
|
133
|
-
// Migliora compatibilitΓ Linux (X/Wayland) senza toccare il servizio
|
|
134
|
-
if (process.platform === 'linux') {
|
|
135
|
-
if (!env.DISPLAY) {
|
|
136
|
-
// fallback tipico X11
|
|
137
|
-
env.DISPLAY = ':0';
|
|
138
|
-
}
|
|
139
|
-
if (!env.XDG_RUNTIME_DIR && typeof process.getuid === 'function') {
|
|
140
|
-
env.XDG_RUNTIME_DIR = `/run/user/${process.getuid()}`;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const tryLinux = async () => {
|
|
146
|
-
// 1) Standard freedesktop
|
|
147
|
-
try { await tryExecFile('xdg-open', [url], env); this.log.debug('π xdg-open OK'); return; } catch {}
|
|
148
|
-
|
|
149
|
-
// 2) Gio / GVFS
|
|
150
|
-
try { await tryExec(`gio open "${url}"`, env); this.log.debug('π gio open OK'); return; } catch {}
|
|
151
|
-
|
|
152
|
-
// 3) Debian-like helpers
|
|
153
|
-
try { await tryExecFile('sensible-browser', [url], env); this.log.debug('π sensible-browser OK'); return; } catch {}
|
|
154
|
-
try { await tryExecFile('x-www-browser', [url], env); this.log.debug('π x-www-browser OK'); return; } catch {}
|
|
155
|
-
|
|
156
|
-
// 4) xdg-desktop-portal (DBus OpenURI) β compatibile Wayland/X
|
|
157
|
-
try {
|
|
158
|
-
await tryExec(
|
|
159
|
-
`gdbus call --session ` +
|
|
160
|
-
`--dest org.freedesktop.portal.Desktop ` +
|
|
161
|
-
`--object-path /org/freedesktop/portal/desktop ` +
|
|
162
|
-
`--method org.freedesktop.portal.OpenURI.OpenURI "" "${url}" "{}"`,
|
|
163
|
-
env
|
|
164
|
-
);
|
|
165
|
-
this.log.debug('π xdg-desktop-portal OpenURI OK');
|
|
166
|
-
return;
|
|
167
|
-
} catch {}
|
|
168
|
-
|
|
169
|
-
// 5) backend specifici (best-effort, non bloccanti)
|
|
170
|
-
try { await tryExecFile('kde-open5', [url], env); this.log.debug('π kde-open5 OK'); return; } catch {}
|
|
171
|
-
try { await tryExecFile('gnome-open', [url], env); this.log.debug('π gnome-open OK'); return; } catch {}
|
|
172
|
-
|
|
173
|
-
// Nessun metodo disponibile/riuscito
|
|
174
|
-
throw new Error('No Linux opener succeeded');
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
(async () => {
|
|
178
|
-
try {
|
|
179
|
-
switch (process.platform) {
|
|
180
|
-
case 'darwin':
|
|
181
|
-
await tryExec(`open "${url}"`, env);
|
|
182
|
-
break;
|
|
183
|
-
case 'win32':
|
|
184
|
-
await tryExec(`start "" "${url}"`, env);
|
|
185
|
-
break;
|
|
186
|
-
default:
|
|
187
|
-
await tryLinux();
|
|
188
|
-
}
|
|
189
|
-
this.log.info('β
Tentativo di apertura browser completato');
|
|
190
|
-
} catch (e: any) {
|
|
191
|
-
this.log.warn(`β οΈ Impossibile aprire automaticamente il browser (${e?.message || e}). Apri lβURL manualmente.`);
|
|
192
|
-
}
|
|
193
|
-
})();
|
|
194
|
-
}
|
|
195
118
|
**/
|
|
196
119
|
private openBrowser;
|
|
120
|
+
private tryOpenBrowserDirect;
|
|
197
121
|
private exchangeCodeForTokens;
|
|
198
122
|
refreshAccessToken(): Promise<void>;
|
|
199
123
|
private setTokens;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-manager.d.ts","sourceRoot":"","sources":["../src/auth-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,aAAa,EAAiB,MAAM,OAAO,CAAC;AAOrD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAkBD,qBAAa,WAAW;IAuBpB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAzBzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuD;IAC/E,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAG1C,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAS;IAChD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAe;IACjD,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAW;IAEpD,OAAO,CAAC,WAAW,CAAC,CAAS;IAC7B,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,cAAc,CAAC,CAAS;IAChC,OAAO,CAAC,aAAa,CAAC,CAAS;IAC/B,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,OAAO,CAAC,qBAAqB,CAAC,CAAS;IACvC,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,aAAa,CAAC,CAAS;IAC/B,OAAO,CAAC,UAAU,CAAC,CAAc;IACjC,OAAO,CAAC,WAAW,CAAC,CAAiB;IACrC,OAAO,CAAC,iBAAiB,CAAC,CAAiB;gBAGxB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,aAAa,EACzB,MAAM,EAAE,MAAM;IAajC,OAAO,CAAC,yBAAyB;IAiCjC,OAAO,CAAC,iBAAiB;IAoBzB,OAAO,CAAC,gBAAgB;IAiBxB,OAAO,CAAC,gBAAgB;IA0CxB,OAAO,CAAC,UAAU;IAkDlB,OAAO,CAAC,iBAAiB;IA8BzB,OAAO,CAAC,oBAAoB;IAgCf,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAkD5C;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,OAAO,CAAC,mBAAmB;YAuBX,eAAe;YAWf,gBAAgB;IAyC9B,OAAO,CAAC,YAAY;
|
|
1
|
+
{"version":3,"file":"auth-manager.d.ts","sourceRoot":"","sources":["../src/auth-manager.ts"],"names":[],"mappings":"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"}
|
package/dist/auth-manager.js
CHANGED
|
@@ -422,41 +422,56 @@ class AuthManager {
|
|
|
422
422
|
async performFullAuth() {
|
|
423
423
|
return new Promise((resolve, reject) => {
|
|
424
424
|
const authUrl = this.buildAuthUrl();
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
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(() =>
|
|
456
|
-
.
|
|
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
|
-
//
|
|
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
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
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
|
-
//
|
|
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
556
|
this.authServer.listen(this.config.redirectPort || 4200, '0.0.0.0', () => {
|
|
521
|
-
this.log.
|
|
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);
|
|
@@ -571,285 +607,57 @@ class AuthManager {
|
|
|
571
607
|
}
|
|
572
608
|
}
|
|
573
609
|
|
|
574
|
-
private openBrowser(url: string): void {
|
|
575
|
-
const { execFile, exec } = require('child_process');
|
|
576
610
|
|
|
577
|
-
const tryExecFile = (cmd: string, args: string[], env: NodeJS.ProcessEnv) =>
|
|
578
|
-
new Promise<void>((resolve, reject) => {
|
|
579
|
-
execFile(cmd, args, { env }, (err: any) => err ? reject(err) : resolve());
|
|
580
|
-
});
|
|
581
|
-
|
|
582
|
-
const tryExec = (command: string, env: NodeJS.ProcessEnv) =>
|
|
583
|
-
new Promise<void>((resolve, reject) => {
|
|
584
|
-
exec(command, { env }, (err: any) => err ? reject(err) : resolve());
|
|
585
|
-
});
|
|
586
|
-
|
|
587
|
-
// Copia pulita dell'ambiente
|
|
588
|
-
const env: NodeJS.ProcessEnv = { ...process.env };
|
|
589
|
-
|
|
590
|
-
// Migliora compatibilitΓ Linux (X/Wayland) senza toccare il servizio
|
|
591
|
-
if (process.platform === 'linux') {
|
|
592
|
-
if (!env.DISPLAY) {
|
|
593
|
-
// fallback tipico X11
|
|
594
|
-
env.DISPLAY = ':0';
|
|
595
|
-
}
|
|
596
|
-
if (!env.XDG_RUNTIME_DIR && typeof process.getuid === 'function') {
|
|
597
|
-
env.XDG_RUNTIME_DIR = `/run/user/${process.getuid()}`;
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
const tryLinux = async () => {
|
|
603
|
-
// 1) Standard freedesktop
|
|
604
|
-
try { await tryExecFile('xdg-open', [url], env); this.log.debug('π xdg-open OK'); return; } catch {}
|
|
605
|
-
|
|
606
|
-
// 2) Gio / GVFS
|
|
607
|
-
try { await tryExec(`gio open "${url}"`, env); this.log.debug('π gio open OK'); return; } catch {}
|
|
608
|
-
|
|
609
|
-
// 3) Debian-like helpers
|
|
610
|
-
try { await tryExecFile('sensible-browser', [url], env); this.log.debug('π sensible-browser OK'); return; } catch {}
|
|
611
|
-
try { await tryExecFile('x-www-browser', [url], env); this.log.debug('π x-www-browser OK'); return; } catch {}
|
|
612
|
-
|
|
613
|
-
// 4) xdg-desktop-portal (DBus OpenURI) β compatibile Wayland/X
|
|
614
|
-
try {
|
|
615
|
-
await tryExec(
|
|
616
|
-
`gdbus call --session ` +
|
|
617
|
-
`--dest org.freedesktop.portal.Desktop ` +
|
|
618
|
-
`--object-path /org/freedesktop/portal/desktop ` +
|
|
619
|
-
`--method org.freedesktop.portal.OpenURI.OpenURI "" "${url}" "{}"`,
|
|
620
|
-
env
|
|
621
|
-
);
|
|
622
|
-
this.log.debug('π xdg-desktop-portal OpenURI OK');
|
|
623
|
-
return;
|
|
624
|
-
} catch {}
|
|
625
|
-
|
|
626
|
-
// 5) backend specifici (best-effort, non bloccanti)
|
|
627
|
-
try { await tryExecFile('kde-open5', [url], env); this.log.debug('π kde-open5 OK'); return; } catch {}
|
|
628
|
-
try { await tryExecFile('gnome-open', [url], env); this.log.debug('π gnome-open OK'); return; } catch {}
|
|
629
|
-
|
|
630
|
-
// Nessun metodo disponibile/riuscito
|
|
631
|
-
throw new Error('No Linux opener succeeded');
|
|
632
|
-
};
|
|
633
|
-
|
|
634
|
-
(async () => {
|
|
635
|
-
try {
|
|
636
|
-
switch (process.platform) {
|
|
637
|
-
case 'darwin':
|
|
638
|
-
await tryExec(`open "${url}"`, env);
|
|
639
|
-
break;
|
|
640
|
-
case 'win32':
|
|
641
|
-
await tryExec(`start "" "${url}"`, env);
|
|
642
|
-
break;
|
|
643
|
-
default:
|
|
644
|
-
await tryLinux();
|
|
645
|
-
}
|
|
646
|
-
this.log.info('β
Tentativo di apertura browser completato');
|
|
647
|
-
} catch (e: any) {
|
|
648
|
-
this.log.warn(`β οΈ Impossibile aprire automaticamente il browser (${e?.message || e}). Apri lβURL manualmente.`);
|
|
649
|
-
}
|
|
650
|
-
})();
|
|
651
|
-
}
|
|
652
611
|
**/
|
|
653
612
|
openBrowser(url) {
|
|
654
|
-
|
|
655
|
-
//
|
|
656
|
-
const
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
const desktop = detectDesktopEnvironment();
|
|
698
|
-
this.log.debug(`π₯οΈ Desktop environment detected: ${desktop} (XDG_CURRENT_DESKTOP=${env.XDG_CURRENT_DESKTOP})`);
|
|
699
|
-
// 1. Metodo universale - xdg-open (funziona con tutti i DE moderni)
|
|
700
|
-
try {
|
|
701
|
-
await execWithTimeout('xdg-open', [url]);
|
|
702
|
-
this.log.info('β
Browser aperto con xdg-open');
|
|
703
|
-
return true;
|
|
704
|
-
}
|
|
705
|
-
catch { }
|
|
706
|
-
// 2. Metodi specifici per desktop environment
|
|
707
|
-
switch (desktop) {
|
|
708
|
-
case 'gnome':
|
|
709
|
-
try {
|
|
710
|
-
await execWithTimeout('gnome-open', [url]);
|
|
711
|
-
this.log.info('β
Browser aperto con gnome-open');
|
|
712
|
-
return true;
|
|
713
|
-
}
|
|
714
|
-
catch { }
|
|
715
|
-
try {
|
|
716
|
-
await execWithTimeout('gio', ['open', url]);
|
|
717
|
-
this.log.info('β
Browser aperto con gio open');
|
|
718
|
-
return true;
|
|
719
|
-
}
|
|
720
|
-
catch { }
|
|
721
|
-
break;
|
|
722
|
-
case 'kde':
|
|
723
|
-
try {
|
|
724
|
-
await execWithTimeout('kde-open5', [url]);
|
|
725
|
-
this.log.info('β
Browser aperto con kde-open5');
|
|
726
|
-
return true;
|
|
727
|
-
}
|
|
728
|
-
catch { }
|
|
729
|
-
try {
|
|
730
|
-
await execWithTimeout('kde-open', [url]);
|
|
731
|
-
this.log.info('β
Browser aperto con kde-open');
|
|
732
|
-
return true;
|
|
733
|
-
}
|
|
734
|
-
catch { }
|
|
735
|
-
break;
|
|
736
|
-
case 'xfce':
|
|
737
|
-
try {
|
|
738
|
-
await execWithTimeout('exo-open', [url]);
|
|
739
|
-
this.log.info('β
Browser aperto con exo-open');
|
|
740
|
-
return true;
|
|
741
|
-
}
|
|
742
|
-
catch { }
|
|
743
|
-
break;
|
|
744
|
-
case 'lxde':
|
|
745
|
-
try {
|
|
746
|
-
await execWithTimeout('pcmanfm', [url]);
|
|
747
|
-
this.log.info('β
Browser aperto con pcmanfm');
|
|
748
|
-
return true;
|
|
749
|
-
}
|
|
750
|
-
catch { }
|
|
751
|
-
break;
|
|
752
|
-
case 'mate':
|
|
753
|
-
try {
|
|
754
|
-
await execWithTimeout('mate-open', [url]);
|
|
755
|
-
this.log.info('β
Browser aperto con mate-open');
|
|
756
|
-
return true;
|
|
757
|
-
}
|
|
758
|
-
catch { }
|
|
759
|
-
break;
|
|
760
|
-
case 'cinnamon':
|
|
761
|
-
try {
|
|
762
|
-
await execWithTimeout('cinnamon-open', [url]);
|
|
763
|
-
this.log.info('β
Browser aperto con cinnamon-open');
|
|
764
|
-
return true;
|
|
765
|
-
}
|
|
766
|
-
catch { }
|
|
767
|
-
break;
|
|
768
|
-
case 'wayland':
|
|
769
|
-
// Portal DBus (metodo nativo Wayland - funziona con labwc)
|
|
770
|
-
try {
|
|
771
|
-
const escapedUrl = url.replace(/"/g, '\\"');
|
|
772
|
-
await execWithTimeout('gdbus', [
|
|
773
|
-
'call', '--session',
|
|
774
|
-
'--dest', 'org.freedesktop.portal.Desktop',
|
|
775
|
-
'--object-path', '/org/freedesktop/portal/desktop',
|
|
776
|
-
'--method', 'org.freedesktop.portal.OpenURI.OpenURI',
|
|
777
|
-
'', escapedUrl, '{}'
|
|
778
|
-
]);
|
|
779
|
-
this.log.info('β
Browser aperto con xdg-desktop-portal (Wayland)');
|
|
780
|
-
return true;
|
|
781
|
-
}
|
|
782
|
-
catch { }
|
|
783
|
-
break;
|
|
784
|
-
}
|
|
785
|
-
// 3. Fallback: Helper generici Debian/Ubuntu/Raspberry Pi OS
|
|
786
|
-
const helpers = ['sensible-browser', 'x-www-browser', 'www-browser'];
|
|
787
|
-
for (const helper of helpers) {
|
|
788
|
-
try {
|
|
789
|
-
await execWithTimeout(helper, [url]);
|
|
790
|
-
this.log.info(`β
Browser aperto con ${helper}`);
|
|
791
|
-
return true;
|
|
792
|
-
}
|
|
793
|
-
catch { }
|
|
794
|
-
}
|
|
795
|
-
// 4. Ultimo tentativo: Browser diretti
|
|
796
|
-
const browsers = [
|
|
797
|
-
'chromium-browser', // Raspberry Pi OS default
|
|
798
|
-
'chromium',
|
|
799
|
-
'firefox',
|
|
800
|
-
'firefox-esr', // Debian/Raspberry Pi OS
|
|
801
|
-
'google-chrome',
|
|
802
|
-
'microsoft-edge',
|
|
803
|
-
'brave-browser',
|
|
804
|
-
'opera'
|
|
805
|
-
];
|
|
806
|
-
for (const browser of browsers) {
|
|
807
|
-
try {
|
|
808
|
-
await execWithTimeout(browser, [url]);
|
|
809
|
-
this.log.info(`β
Browser aperto con ${browser}`);
|
|
810
|
-
return true;
|
|
811
|
-
}
|
|
812
|
-
catch { }
|
|
813
|
-
}
|
|
814
|
-
return false;
|
|
815
|
-
};
|
|
816
|
-
(async () => {
|
|
817
|
-
try {
|
|
818
|
-
let success = false;
|
|
819
|
-
switch (process.platform) {
|
|
820
|
-
case 'darwin':
|
|
821
|
-
await execWithTimeout('open', [url]);
|
|
822
|
-
success = true;
|
|
823
|
-
break;
|
|
824
|
-
case 'win32':
|
|
825
|
-
await execWithTimeout(`start "" "${url}"`);
|
|
826
|
-
success = true;
|
|
827
|
-
break;
|
|
828
|
-
default: // Linux
|
|
829
|
-
success = await tryLinuxMethods();
|
|
830
|
-
}
|
|
831
|
-
if (success) {
|
|
832
|
-
this.log.info('π Browser aperto con successo');
|
|
833
|
-
}
|
|
834
|
-
else {
|
|
835
|
-
throw new Error('Tutti i metodi di apertura browser falliti');
|
|
836
|
-
}
|
|
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;
|
|
636
|
+
}
|
|
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');
|
|
837
656
|
}
|
|
838
|
-
|
|
839
|
-
this.log.
|
|
840
|
-
this.log.warn('β οΈ IMPOSSIBILE APRIRE IL BROWSER AUTOMATICAMENTE');
|
|
841
|
-
this.log.warn('='.repeat(80));
|
|
842
|
-
this.log.warn('π± Apri manualmente questo URL da QUALSIASI dispositivo nella tua rete:');
|
|
843
|
-
this.log.warn('');
|
|
844
|
-
this.log.warn(` ${url}`);
|
|
845
|
-
this.log.warn('');
|
|
846
|
-
this.log.warn('π‘ Puoi usare:');
|
|
847
|
-
this.log.warn(' β’ Computer/laptop sulla stessa rete');
|
|
848
|
-
this.log.warn(' β’ Smartphone/tablet');
|
|
849
|
-
this.log.warn(' β’ Qualsiasi browser moderno');
|
|
850
|
-
this.log.warn('='.repeat(80));
|
|
657
|
+
else {
|
|
658
|
+
this.log.info('π Opening browser...');
|
|
851
659
|
}
|
|
852
|
-
})
|
|
660
|
+
});
|
|
853
661
|
}
|
|
854
662
|
async exchangeCodeForTokens(authCode) {
|
|
855
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.
|
|
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": {
|