homebridge-melcloud-control 4.3.11-beta.21 → 4.3.11-beta.22
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/melcloudhomeauth.js +93 -92
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"displayName": "MELCloud Control",
|
|
3
3
|
"name": "homebridge-melcloud-control",
|
|
4
|
-
"version": "4.3.11-beta.
|
|
4
|
+
"version": "4.3.11-beta.22",
|
|
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/melcloudhomeauth.js
CHANGED
|
@@ -6,103 +6,104 @@ import qs from 'qs';
|
|
|
6
6
|
|
|
7
7
|
const BASE_URL = 'https://melcloudhome.com'; // lub właściwe dla Home
|
|
8
8
|
const USER_AGENT =
|
|
9
|
-
|
|
9
|
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36';
|
|
10
10
|
|
|
11
11
|
export class MELCloudHomeAuth {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async login(username, password) {
|
|
32
|
-
try {
|
|
33
|
-
// 1. GET login page to get CSRF token
|
|
34
|
-
let resp = await this.client.get(`${BASE_URL}/bff/login`, {
|
|
35
|
-
params: { returnUrl: '/dashboard' },
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
// Follow redirect to Cognito
|
|
39
|
-
let finalUrl = resp.request.res.responseUrl;
|
|
40
|
-
if (!finalUrl.includes('.amazoncognito.com')) {
|
|
41
|
-
throw new Error('Unexpected redirect URL: ' + finalUrl);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Extract CSRF token from HTML
|
|
45
|
-
const csrfToken = this.extractCsrfToken(resp.data);
|
|
46
|
-
if (!csrfToken) throw new Error('CSRF token not found');
|
|
47
|
-
|
|
48
|
-
// 2. POST credentials to Cognito
|
|
49
|
-
const loginData = qs.stringify({
|
|
50
|
-
_csrf: csrfToken,
|
|
51
|
-
username,
|
|
52
|
-
password,
|
|
53
|
-
cognitoAsfData: '', // minimal value, może być potrzebne pełne ASF
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
resp = await this.client.post(finalUrl, loginData, {
|
|
57
|
-
headers: {
|
|
58
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
59
|
-
Origin: 'https://live-melcloudhome.auth.eu-west-1.amazoncognito.com',
|
|
60
|
-
Referer: finalUrl,
|
|
61
|
-
},
|
|
62
|
-
maxRedirects: 5,
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
finalUrl = resp.request.res.responseUrl;
|
|
66
|
-
|
|
67
|
-
// Sprawdzenie czy udało się zalogować
|
|
68
|
-
if (
|
|
69
|
-
finalUrl.includes('melcloudhome.com/dashboard') &&
|
|
70
|
-
resp.status < 400
|
|
71
|
-
) {
|
|
72
|
-
console.log('Authentication successful');
|
|
73
|
-
this.authenticated = true;
|
|
74
|
-
return true;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
throw new Error('Authentication failed, final URL: ' + finalUrl);
|
|
78
|
-
} catch (err) {
|
|
79
|
-
throw new Error('Login error: ' + err.message);
|
|
12
|
+
constructor() {
|
|
13
|
+
this.jar = new CookieJar();
|
|
14
|
+
this.client = wrapper(
|
|
15
|
+
axios.create({
|
|
16
|
+
jar: this.jar,
|
|
17
|
+
withCredentials: true,
|
|
18
|
+
headers: {
|
|
19
|
+
'User-Agent': USER_AGENT,
|
|
20
|
+
Accept:
|
|
21
|
+
'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
|
|
22
|
+
'Accept-Language': 'en-US,en;q=0.9',
|
|
23
|
+
},
|
|
24
|
+
maxRedirects: 0,
|
|
25
|
+
validateStatus: (status) => status >= 200 && status < 400,
|
|
26
|
+
})
|
|
27
|
+
);
|
|
28
|
+
this.authenticated = false;
|
|
80
29
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
30
|
+
|
|
31
|
+
async login(username, password) {
|
|
32
|
+
try {
|
|
33
|
+
// 1. GET login page to get CSRF token
|
|
34
|
+
let resp = await this.client.get(`${BASE_URL}/bff/login`, {
|
|
35
|
+
params: { returnUrl: '/dashboard' },
|
|
36
|
+
maxRedirects: 5, // pozwala axios śledzić redirecty
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// finalny URL po redirectach
|
|
40
|
+
let finalUrl = resp.request?.res?.responseUrl || resp.request?.path || '';
|
|
41
|
+
if (!finalUrl.includes('.amazoncognito.com')) {
|
|
42
|
+
throw new Error('Unexpected redirect URL: ' + finalUrl);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Extract CSRF token from HTML
|
|
46
|
+
const csrfToken = this.extractCsrfToken(resp.data);
|
|
47
|
+
if (!csrfToken) throw new Error('CSRF token not found');
|
|
48
|
+
|
|
49
|
+
// 2. POST credentials to Cognito
|
|
50
|
+
const loginData = qs.stringify({
|
|
51
|
+
_csrf: csrfToken,
|
|
52
|
+
username,
|
|
53
|
+
password,
|
|
54
|
+
cognitoAsfData: '', // minimal value, może być potrzebne pełne ASF
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
resp = await this.client.post(finalUrl, loginData, {
|
|
58
|
+
headers: {
|
|
59
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
60
|
+
Origin: 'https://live-melcloudhome.auth.eu-west-1.amazoncognito.com',
|
|
61
|
+
Referer: finalUrl,
|
|
62
|
+
},
|
|
63
|
+
maxRedirects: 5,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
finalUrl = resp.request.res.responseUrl;
|
|
67
|
+
|
|
68
|
+
// Sprawdzenie czy udało się zalogować
|
|
69
|
+
if (
|
|
70
|
+
finalUrl.includes('melcloudhome.com/dashboard') &&
|
|
71
|
+
resp.status < 400
|
|
72
|
+
) {
|
|
73
|
+
console.log('Authentication successful');
|
|
74
|
+
this.authenticated = true;
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
throw new Error('Authentication failed, final URL: ' + finalUrl);
|
|
79
|
+
} catch (err) {
|
|
80
|
+
throw new Error('Login error: ' + err.message);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
extractCsrfToken(html) {
|
|
85
|
+
const dom = new JSDOM(html);
|
|
86
|
+
const input = dom.window.document.querySelector('input[name="_csrf"]');
|
|
87
|
+
return input?.value || null;
|
|
100
88
|
}
|
|
101
|
-
}
|
|
102
89
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
90
|
+
async checkSession() {
|
|
91
|
+
if (!this.authenticated) return false;
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
const resp = await this.client.get(`${BASE_URL}/api/user/context`, {
|
|
95
|
+
headers: { 'x-csrf': '1', Referer: `${BASE_URL}/dashboard` },
|
|
96
|
+
});
|
|
97
|
+
return resp.status === 200;
|
|
98
|
+
} catch {
|
|
99
|
+
this.authenticated = false;
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
getCookies() {
|
|
105
|
+
return this.jar.toJSON();
|
|
106
|
+
}
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
|