homebridge-melcloud-control 4.0.0-beta.342 → 4.0.0-beta.346
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/package.json +1 -1
- package/src/melcloud.js +5 -5
- package/src/melcloudhometoken.js +19 -61
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"displayName": "MELCloud Control",
|
|
3
3
|
"name": "homebridge-melcloud-control",
|
|
4
|
-
"version": "4.0.0-beta.
|
|
4
|
+
"version": "4.0.0-beta.346",
|
|
5
5
|
"description": "Homebridge plugin to control Mitsubishi Air Conditioner, Heat Pump and Energy Recovery Ventilation.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "grzegorz914",
|
package/src/melcloud.js
CHANGED
|
@@ -293,12 +293,12 @@ class MelCloud extends EventEmitter {
|
|
|
293
293
|
.on('warn', warn => this.emit('warn', warn))
|
|
294
294
|
.on('error', error => this.emit('error', error));
|
|
295
295
|
|
|
296
|
-
const
|
|
296
|
+
const data = await melCloudHomeToken.buildAuthorizeUrl();
|
|
297
297
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
298
|
+
const url = data.url;
|
|
299
|
+
const codeVerifier = data.codeVerifier;
|
|
300
|
+
const code = await melCloudHomeToken.loginToMelCloudHome(url);
|
|
301
|
+
const token = await melCloudHomeToken.getTokens(code, codeVerifier);
|
|
302
302
|
|
|
303
303
|
const accountInfo = { ContextKey: token, UseFahrenheit: false };
|
|
304
304
|
this.contextKey = cookies;
|
package/src/melcloudhometoken.js
CHANGED
|
@@ -84,72 +84,28 @@ class MelCloudHomeToken extends EventEmitter {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
async axiosRequestWithRedirects(url, options = {}, body, redirectCount = 0) {
|
|
88
|
-
if (redirectCount > 10) {
|
|
89
|
-
throw new Error('Too many redirects');
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
try {
|
|
93
|
-
const method = (options.method || 'GET').toUpperCase();
|
|
94
|
-
const headers = options.headers || {};
|
|
95
|
-
|
|
96
|
-
const response = await axios({
|
|
97
|
-
url,
|
|
98
|
-
method,
|
|
99
|
-
headers,
|
|
100
|
-
data: body,
|
|
101
|
-
maxRedirects: 0, // wyłączamy automatyczne redirecty
|
|
102
|
-
validateStatus: status => status >= 200 && status < 400,
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
// Ręczne follow dla 301/302
|
|
106
|
-
if ([301, 302].includes(response.status)) {
|
|
107
|
-
const location = response.headers.location;
|
|
108
|
-
if (!location) throw new Error('Redirect status without Location header');
|
|
109
|
-
|
|
110
|
-
const redirectUrl = location.startsWith('http') ? location : new URL(location, url).toString();
|
|
111
|
-
|
|
112
|
-
// Przy POST zachowujemy body i headers
|
|
113
|
-
return axiosRequestWithRedirects(redirectUrl, options, body, redirectCount + 1);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Zwracamy odpowiedź jako string
|
|
117
|
-
if (typeof response.data === 'string') {
|
|
118
|
-
return response.data;
|
|
119
|
-
} else {
|
|
120
|
-
return JSON.stringify(response.data);
|
|
121
|
-
}
|
|
122
|
-
} catch (err) {
|
|
123
|
-
throw new Error(`Axios request failed: ${err.message || err}`);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
|
|
128
87
|
async getTokens(code, codeVerifier) {
|
|
129
88
|
try {
|
|
130
|
-
|
|
131
89
|
const tokenData = new URLSearchParams({
|
|
132
90
|
grant_type: 'authorization_code',
|
|
133
91
|
code: code,
|
|
134
92
|
redirect_uri: REDIRECT_URI,
|
|
135
93
|
client_id: CLIENT_ID,
|
|
136
94
|
code_verifier: codeVerifier,
|
|
137
|
-
})
|
|
95
|
+
});
|
|
138
96
|
|
|
139
|
-
const
|
|
140
|
-
method: 'POST',
|
|
97
|
+
const tokenResponse = await axios.post(TOKEN_ENDPOINT, tokenData.toString(), {
|
|
141
98
|
headers: {
|
|
142
99
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
143
100
|
'Authorization': 'Basic aG9tZW1vYmlsZTo=',
|
|
144
101
|
},
|
|
145
|
-
}
|
|
146
|
-
|
|
102
|
+
});
|
|
147
103
|
|
|
148
|
-
const tokens =
|
|
149
|
-
this.emit('warn', `Token ${JSON.stringify(
|
|
104
|
+
const tokens = tokenResponse.data;
|
|
105
|
+
this.emit('warn', `Token ${JSON.stringify(tokens)}`);
|
|
150
106
|
return tokens;
|
|
151
107
|
} catch (error) {
|
|
152
|
-
throw new Error(`Failed to obtain OAuth token: ${error}`);
|
|
108
|
+
throw new Error(`Failed to obtain OAuth token: ${error.response?.data || error}`);
|
|
153
109
|
}
|
|
154
110
|
}
|
|
155
111
|
|
|
@@ -173,22 +129,25 @@ class MelCloudHomeToken extends EventEmitter {
|
|
|
173
129
|
}
|
|
174
130
|
|
|
175
131
|
// Step 2: Przygotuj dane logowania
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
132
|
+
const formData = new URLSearchParams({
|
|
133
|
+
_csrf: csrf,
|
|
134
|
+
username: this.user,
|
|
135
|
+
password: this.passwd,
|
|
136
|
+
});
|
|
181
137
|
|
|
182
138
|
if (this.logWarn) this.emit('warn', `Redirect URL: ${url}`);
|
|
183
139
|
|
|
184
140
|
// Step 3: Wyślij POST z danymi logowania
|
|
185
141
|
const response = await axios.post(url, form.toString(), {
|
|
186
142
|
headers: {
|
|
143
|
+
'User-Agent': MOBILE_USER_AGENT,
|
|
144
|
+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
145
|
+
'Accept-Language': 'en-US,en;q=0.9',
|
|
187
146
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
188
|
-
'
|
|
189
|
-
'
|
|
147
|
+
'Content-Length': formData.toString().length,
|
|
148
|
+
'Cookie': cookies,
|
|
149
|
+
'Origin': 'https://live-melcloudhome.auth.eu-west-1.amazoncognito.com',
|
|
190
150
|
'Referer': url,
|
|
191
|
-
'User-Agent': MOBILE_USER_AGENT
|
|
192
151
|
},
|
|
193
152
|
maxRedirects: 0,
|
|
194
153
|
validateStatus: status => [200, 302, 400].includes(status),
|
|
@@ -232,9 +191,8 @@ class MelCloudHomeToken extends EventEmitter {
|
|
|
232
191
|
authUrl.searchParams.set('state', state);
|
|
233
192
|
|
|
234
193
|
const loginPage = await this.getLoginPage(authUrl.toString());
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
return token;
|
|
194
|
+
const data = { codeVerifier: pkce.verifier, url: loginPage.url }
|
|
195
|
+
return data;
|
|
238
196
|
} catch (error) {
|
|
239
197
|
throw new Error(`Failed to obtain OAuth link: ${error}`);
|
|
240
198
|
}
|