homebridge-nuheat2 1.2.16 → 1.2.17
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/CHANGELOG.md +7 -0
- package/homebridge-ui/public/index.js +27 -14
- package/lib/NuHeatAPI.js +5 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,13 @@ All notable changes to this project should be documented in this file
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.2.17] - 2026-04-29
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Treat the built-in Nuheat public client ID as PKCE-only even when it is explicitly saved in Advanced OAuth settings
|
|
12
|
+
- Ignore and clear stale saved client secrets when users return to the built-in PKCE public client
|
|
13
|
+
|
|
7
14
|
## [1.2.16] - 2026-04-29
|
|
8
15
|
|
|
9
16
|
### Changed
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const PLATFORM_NAME = "NuHeat";
|
|
2
|
+
const BUILT_IN_CLIENT_ID = "homebridge-nuheat2_260421";
|
|
2
3
|
|
|
3
4
|
const elements = {
|
|
4
5
|
name: document.getElementById("name"),
|
|
@@ -139,7 +140,9 @@ function renderConfig(config) {
|
|
|
139
140
|
|
|
140
141
|
elements.clientId.value = config.clientId || "";
|
|
141
142
|
elements.clientSecret.value = "";
|
|
142
|
-
state.hasClientSecret = Boolean(
|
|
143
|
+
state.hasClientSecret = Boolean(
|
|
144
|
+
config.clientSecret && config.clientId !== BUILT_IN_CLIENT_ID,
|
|
145
|
+
);
|
|
143
146
|
elements.clientSecret.placeholder = state.hasClientSecret
|
|
144
147
|
? "Saved secret (leave blank to keep)"
|
|
145
148
|
: "Optional client secret";
|
|
@@ -313,6 +316,7 @@ async function saveOauth() {
|
|
|
313
316
|
const clientId = elements.clientId.value.trim();
|
|
314
317
|
const clientSecret = elements.clientSecret.value;
|
|
315
318
|
const redirectUri = elements.redirectUri.value.trim();
|
|
319
|
+
const usesBuiltInClient = !clientId || clientId === BUILT_IN_CLIENT_ID;
|
|
316
320
|
|
|
317
321
|
if (!clientId && clientSecret) {
|
|
318
322
|
showToast("error", "A client secret requires a Nuheat client ID.");
|
|
@@ -321,24 +325,25 @@ async function saveOauth() {
|
|
|
321
325
|
}
|
|
322
326
|
|
|
323
327
|
const patch = {
|
|
324
|
-
clientId:
|
|
328
|
+
clientId: usesBuiltInClient ? undefined : clientId,
|
|
325
329
|
redirectUri: redirectUri && redirectUri !== "http://localhost" ? redirectUri : undefined,
|
|
326
330
|
};
|
|
327
331
|
|
|
328
|
-
if (clientSecret) {
|
|
332
|
+
if (clientSecret && !usesBuiltInClient) {
|
|
329
333
|
patch.clientSecret = clientSecret;
|
|
330
|
-
} else if (
|
|
334
|
+
} else if (usesBuiltInClient || clientId !== (state.config?.clientId || "")) {
|
|
331
335
|
patch.clientSecret = undefined;
|
|
332
336
|
}
|
|
333
337
|
|
|
334
338
|
await persistPatch(patch);
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
339
|
+
state.hasClientSecret = Boolean(state.config?.clientSecret);
|
|
340
|
+
elements.clientId.value = state.config?.clientId || "";
|
|
341
|
+
elements.clientSecret.value = "";
|
|
342
|
+
elements.clientSecret.placeholder = state.hasClientSecret
|
|
343
|
+
? "Saved secret (leave blank to keep)"
|
|
344
|
+
: "Optional client secret";
|
|
345
|
+
updateStatuses();
|
|
346
|
+
renderDiagnostics();
|
|
342
347
|
showToast("success", "OAuth settings saved.");
|
|
343
348
|
}
|
|
344
349
|
|
|
@@ -437,8 +442,9 @@ function updateBehaviorStatus() {
|
|
|
437
442
|
}
|
|
438
443
|
|
|
439
444
|
function updateOauthStatus() {
|
|
440
|
-
const
|
|
441
|
-
const
|
|
445
|
+
const clientId = elements.clientId.value.trim();
|
|
446
|
+
const hasClientId = clientId.length > 0 && clientId !== BUILT_IN_CLIENT_ID;
|
|
447
|
+
const hasClientSecret = hasUsableClientSecret(clientId);
|
|
442
448
|
const text = hasClientId
|
|
443
449
|
? hasClientSecret
|
|
444
450
|
? "Custom legacy OAuth"
|
|
@@ -448,6 +454,10 @@ function updateOauthStatus() {
|
|
|
448
454
|
}
|
|
449
455
|
|
|
450
456
|
function hasUsableClientSecret(clientId) {
|
|
457
|
+
if (!clientId || clientId === BUILT_IN_CLIENT_ID) {
|
|
458
|
+
return false;
|
|
459
|
+
}
|
|
460
|
+
|
|
451
461
|
if (elements.clientSecret.value) {
|
|
452
462
|
return true;
|
|
453
463
|
}
|
|
@@ -577,13 +587,16 @@ function getHoldSummary(value) {
|
|
|
577
587
|
}
|
|
578
588
|
|
|
579
589
|
function getOauthMode(config) {
|
|
590
|
+
if (!config.clientId || config.clientId === BUILT_IN_CLIENT_ID) {
|
|
591
|
+
return "built-in PKCE public client";
|
|
592
|
+
}
|
|
593
|
+
|
|
580
594
|
if (config.clientId && hasUsableClientSecret(config.clientId)) {
|
|
581
595
|
return "configured confidential client";
|
|
582
596
|
}
|
|
583
597
|
if (config.clientId) {
|
|
584
598
|
return "configured PKCE public client";
|
|
585
599
|
}
|
|
586
|
-
return "built-in PKCE public client";
|
|
587
600
|
}
|
|
588
601
|
|
|
589
602
|
function normalizeHoldLength(value) {
|
package/lib/NuHeatAPI.js
CHANGED
|
@@ -33,15 +33,16 @@ class NuHeatAPI {
|
|
|
33
33
|
this.log = log;
|
|
34
34
|
const configuredClientId = options.clientId || process.env.NUHEAT_API_CLIENT_ID || "";
|
|
35
35
|
const configuredClientSecret = options.clientSecret || process.env.NUHEAT_API_CLIENT_SECRET || "";
|
|
36
|
+
const usingBuiltInPublicClient = !configuredClientId || configuredClientId === settings_1.NUHEAT_API_CLIENT_ID;
|
|
36
37
|
this.oauthClientId = configuredClientId || settings_1.NUHEAT_API_CLIENT_ID;
|
|
37
|
-
this.oauthClientSecret =
|
|
38
|
-
?
|
|
39
|
-
:
|
|
38
|
+
this.oauthClientSecret = usingBuiltInPublicClient
|
|
39
|
+
? ""
|
|
40
|
+
: configuredClientSecret || settings_1.NUHEAT_API_CLIENT_SECRET;
|
|
40
41
|
this.oauthRedirectUri =
|
|
41
42
|
options.redirectUri ||
|
|
42
43
|
process.env.NUHEAT_API_REDIRECT_URI ||
|
|
43
44
|
settings_1.NUHEAT_API_REDIRECT_URI;
|
|
44
|
-
this.usingBuiltInClient =
|
|
45
|
+
this.usingBuiltInClient = usingBuiltInPublicClient;
|
|
45
46
|
this.usePkce = !this.oauthClientSecret;
|
|
46
47
|
this.pkceCodeVerifier = "";
|
|
47
48
|
this.headers = new HeadersCtor();
|