homebridge-melcloud-control 4.0.0-beta.345 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "MELCloud Control",
3
3
  "name": "homebridge-melcloud-control",
4
- "version": "4.0.0-beta.345",
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 token = await melCloudHomeToken.buildAuthorizeUrl();
296
+ const data = await melCloudHomeToken.buildAuthorizeUrl();
297
297
 
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);
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;
@@ -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 this.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
- }).toString();
95
+ });
138
96
 
139
- const response = await this.axiosRequestWithRedirects(TOKEN_ENDPOINT, {
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
- }, tokenData);
146
-
102
+ });
147
103
 
148
- const tokens = response;
149
- this.emit('warn', `Token ${JSON.stringify(response)}`);
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 form = new URLSearchParams();
177
- form.append('username', this.user);
178
- form.append('password', this.passwd);
179
- form.append('cognitoAsfData', '');
180
- form.append('_csrf', csrf);
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
- 'Cookie': cookies.join('; '),
189
- 'Origin': 'https://auth.melcloudhome.com',
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 code = await this.loginToMelCloudHome(loginPage.url);
236
- const token = await this.getTokens(code, pkce.verifier);
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
  }