@mp-consulting/homebridge-lg-thinq 1.0.0
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/.claude/settings.local.json +15 -0
- package/CHANGELOG.md +98 -0
- package/LICENSE +176 -0
- package/README.md +114 -0
- package/config.schema.json +399 -0
- package/dist/__tests__/baseDevice.spec.d.ts +1 -0
- package/dist/__tests__/baseDevice.spec.js +96 -0
- package/dist/__tests__/baseDevice.spec.js.map +1 -0
- package/dist/__tests__/deviceControl.coercion.spec.d.ts +1 -0
- package/dist/__tests__/deviceControl.coercion.spec.js +53 -0
- package/dist/__tests__/deviceControl.coercion.spec.js.map +1 -0
- package/dist/__tests__/helper.spec.d.ts +1 -0
- package/dist/__tests__/helper.spec.js +74 -0
- package/dist/__tests__/helper.spec.js.map +1 -0
- package/dist/baseDevice.d.ts +40 -0
- package/dist/baseDevice.js +85 -0
- package/dist/baseDevice.js.map +1 -0
- package/dist/baseDevice.spec.d.ts +1 -0
- package/dist/baseDevice.spec.js +107 -0
- package/dist/baseDevice.spec.js.map +1 -0
- package/dist/characteristics/TotalConsumption.d.ts +2 -0
- package/dist/characteristics/TotalConsumption.js +17 -0
- package/dist/characteristics/TotalConsumption.js.map +1 -0
- package/dist/characteristics/index.d.ts +2 -0
- package/dist/characteristics/index.js +7 -0
- package/dist/characteristics/index.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +89 -0
- package/dist/cli.js.map +1 -0
- package/dist/devices/AeroTower.d.ts +24 -0
- package/dist/devices/AeroTower.js +113 -0
- package/dist/devices/AeroTower.js.map +1 -0
- package/dist/devices/AirConditioner.d.ts +425 -0
- package/dist/devices/AirConditioner.js +1253 -0
- package/dist/devices/AirConditioner.js.map +1 -0
- package/dist/devices/AirPurifier.d.ts +50 -0
- package/dist/devices/AirPurifier.js +281 -0
- package/dist/devices/AirPurifier.js.map +1 -0
- package/dist/devices/Dehumidifier.d.ts +28 -0
- package/dist/devices/Dehumidifier.js +175 -0
- package/dist/devices/Dehumidifier.js.map +1 -0
- package/dist/devices/Dishwasher.d.ts +64 -0
- package/dist/devices/Dishwasher.js +740 -0
- package/dist/devices/Dishwasher.js.map +1 -0
- package/dist/devices/Microwave.d.ts +128 -0
- package/dist/devices/Microwave.js +1939 -0
- package/dist/devices/Microwave.js.map +1 -0
- package/dist/devices/Oven.d.ts +148 -0
- package/dist/devices/Oven.js +1850 -0
- package/dist/devices/Oven.js.map +1 -0
- package/dist/devices/RangeHood.d.ts +16 -0
- package/dist/devices/RangeHood.js +99 -0
- package/dist/devices/RangeHood.js.map +1 -0
- package/dist/devices/Refrigerator.d.ts +50 -0
- package/dist/devices/Refrigerator.js +325 -0
- package/dist/devices/Refrigerator.js.map +1 -0
- package/dist/devices/Styler.d.ts +27 -0
- package/dist/devices/Styler.js +76 -0
- package/dist/devices/Styler.js.map +1 -0
- package/dist/devices/WasherDryer.d.ts +39 -0
- package/dist/devices/WasherDryer.js +170 -0
- package/dist/devices/WasherDryer.js.map +1 -0
- package/dist/devices/WasherDryer2.d.ts +9 -0
- package/dist/devices/WasherDryer2.js +16 -0
- package/dist/devices/WasherDryer2.js.map +1 -0
- package/dist/errors/AuthenticationError.d.ts +2 -0
- package/dist/errors/AuthenticationError.js +3 -0
- package/dist/errors/AuthenticationError.js.map +1 -0
- package/dist/errors/ManualProcessNeeded.d.ts +3 -0
- package/dist/errors/ManualProcessNeeded.js +4 -0
- package/dist/errors/ManualProcessNeeded.js.map +1 -0
- package/dist/errors/MonitorError.d.ts +2 -0
- package/dist/errors/MonitorError.js +3 -0
- package/dist/errors/MonitorError.js.map +1 -0
- package/dist/errors/NotConnectedError.d.ts +3 -0
- package/dist/errors/NotConnectedError.js +4 -0
- package/dist/errors/NotConnectedError.js.map +1 -0
- package/dist/errors/TokenError.d.ts +2 -0
- package/dist/errors/TokenError.js +3 -0
- package/dist/errors/TokenError.js.map +1 -0
- package/dist/errors/TokenExpiredError.d.ts +3 -0
- package/dist/errors/TokenExpiredError.js +4 -0
- package/dist/errors/TokenExpiredError.js.map +1 -0
- package/dist/errors/index.d.ts +6 -0
- package/dist/errors/index.js +7 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/helper.d.ts +24 -0
- package/dist/helper.js +66 -0
- package/dist/helper.js.map +1 -0
- package/dist/helper.spec.d.ts +1 -0
- package/dist/helper.spec.js +74 -0
- package/dist/helper.spec.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/API.d.ts +141 -0
- package/dist/lib/API.js +362 -0
- package/dist/lib/API.js.map +1 -0
- package/dist/lib/API.spec.d.ts +1 -0
- package/dist/lib/API.spec.js +55 -0
- package/dist/lib/API.spec.js.map +1 -0
- package/dist/lib/Auth.d.ts +99 -0
- package/dist/lib/Auth.js +348 -0
- package/dist/lib/Auth.js.map +1 -0
- package/dist/lib/Auth.spec.d.ts +1 -0
- package/dist/lib/Auth.spec.js +111 -0
- package/dist/lib/Auth.spec.js.map +1 -0
- package/dist/lib/Device.d.ts +88 -0
- package/dist/lib/Device.js +95 -0
- package/dist/lib/Device.js.map +1 -0
- package/dist/lib/Device.spec.d.ts +1 -0
- package/dist/lib/Device.spec.js +53 -0
- package/dist/lib/Device.spec.js.map +1 -0
- package/dist/lib/DeviceModel.d.ts +164 -0
- package/dist/lib/DeviceModel.js +321 -0
- package/dist/lib/DeviceModel.js.map +1 -0
- package/dist/lib/DeviceModel.spec.d.ts +1 -0
- package/dist/lib/DeviceModel.spec.js +90 -0
- package/dist/lib/DeviceModel.spec.js.map +1 -0
- package/dist/lib/Gateway.d.ts +18 -0
- package/dist/lib/Gateway.js +25 -0
- package/dist/lib/Gateway.js.map +1 -0
- package/dist/lib/Gateway.spec.d.ts +1 -0
- package/dist/lib/Gateway.spec.js +35 -0
- package/dist/lib/Gateway.spec.js.map +1 -0
- package/dist/lib/Persist.d.ts +101 -0
- package/dist/lib/Persist.js +245 -0
- package/dist/lib/Persist.js.map +1 -0
- package/dist/lib/Persist.spec.d.ts +1 -0
- package/dist/lib/Persist.spec.js +90 -0
- package/dist/lib/Persist.spec.js.map +1 -0
- package/dist/lib/Session.d.ts +80 -0
- package/dist/lib/Session.js +100 -0
- package/dist/lib/Session.js.map +1 -0
- package/dist/lib/Session.spec.d.ts +1 -0
- package/dist/lib/Session.spec.js +43 -0
- package/dist/lib/Session.spec.js.map +1 -0
- package/dist/lib/ThinQ.d.ts +28 -0
- package/dist/lib/ThinQ.js +373 -0
- package/dist/lib/ThinQ.js.map +1 -0
- package/dist/lib/__tests__/API.spec.d.ts +1 -0
- package/dist/lib/__tests__/API.spec.js +55 -0
- package/dist/lib/__tests__/API.spec.js.map +1 -0
- package/dist/lib/__tests__/Auth.spec.d.ts +1 -0
- package/dist/lib/__tests__/Auth.spec.js +110 -0
- package/dist/lib/__tests__/Auth.spec.js.map +1 -0
- package/dist/lib/__tests__/Device.spec.d.ts +1 -0
- package/dist/lib/__tests__/Device.spec.js +53 -0
- package/dist/lib/__tests__/Device.spec.js.map +1 -0
- package/dist/lib/__tests__/DeviceModel.spec.d.ts +1 -0
- package/dist/lib/__tests__/DeviceModel.spec.js +90 -0
- package/dist/lib/__tests__/DeviceModel.spec.js.map +1 -0
- package/dist/lib/__tests__/Gateway.spec.d.ts +1 -0
- package/dist/lib/__tests__/Gateway.spec.js +35 -0
- package/dist/lib/__tests__/Gateway.spec.js.map +1 -0
- package/dist/lib/__tests__/Persist.spec.d.ts +1 -0
- package/dist/lib/__tests__/Persist.spec.js +90 -0
- package/dist/lib/__tests__/Persist.spec.js.map +1 -0
- package/dist/lib/__tests__/Session.spec.d.ts +1 -0
- package/dist/lib/__tests__/Session.spec.js +43 -0
- package/dist/lib/__tests__/Session.spec.js.map +1 -0
- package/dist/lib/constants.d.ts +95 -0
- package/dist/lib/constants.js +106 -0
- package/dist/lib/constants.js.map +1 -0
- package/dist/lib/request.d.ts +2 -0
- package/dist/lib/request.js +66 -0
- package/dist/lib/request.js.map +1 -0
- package/dist/platform.d.ts +41 -0
- package/dist/platform.js +229 -0
- package/dist/platform.js.map +1 -0
- package/dist/settings.d.ts +8 -0
- package/dist/settings.js +9 -0
- package/dist/settings.js.map +1 -0
- package/dist/status/BaseStatus.d.ts +48 -0
- package/dist/status/BaseStatus.js +59 -0
- package/dist/status/BaseStatus.js.map +1 -0
- package/dist/types/snapshots.d.ts +142 -0
- package/dist/types/snapshots.js +6 -0
- package/dist/types/snapshots.js.map +1 -0
- package/dist/utils/__tests__/normalize.spec.d.ts +1 -0
- package/dist/utils/__tests__/normalize.spec.js +95 -0
- package/dist/utils/__tests__/normalize.spec.js.map +1 -0
- package/dist/utils/normalize.d.ts +22 -0
- package/dist/utils/normalize.js +51 -0
- package/dist/utils/normalize.js.map +1 -0
- package/dist/v1/__tests__/prepareControlData.spec.d.ts +1 -0
- package/dist/v1/__tests__/prepareControlData.spec.js +48 -0
- package/dist/v1/__tests__/prepareControlData.spec.js.map +1 -0
- package/dist/v1/devices/AC.d.ts +13 -0
- package/dist/v1/devices/AC.js +112 -0
- package/dist/v1/devices/AC.js.map +1 -0
- package/dist/v1/devices/AirPurifier.d.ts +15 -0
- package/dist/v1/devices/AirPurifier.js +57 -0
- package/dist/v1/devices/AirPurifier.js.map +1 -0
- package/dist/v1/devices/RangeHood.d.ts +6 -0
- package/dist/v1/devices/RangeHood.js +12 -0
- package/dist/v1/devices/RangeHood.js.map +1 -0
- package/dist/v1/devices/Refrigerator.d.ts +17 -0
- package/dist/v1/devices/Refrigerator.js +69 -0
- package/dist/v1/devices/Refrigerator.js.map +1 -0
- package/dist/v1/devices/Washer.d.ts +10 -0
- package/dist/v1/devices/Washer.js +23 -0
- package/dist/v1/devices/Washer.js.map +1 -0
- package/dist/v1/devices/index.d.ts +6 -0
- package/dist/v1/devices/index.js +7 -0
- package/dist/v1/devices/index.js.map +1 -0
- package/dist/v1/helper.d.ts +14 -0
- package/dist/v1/helper.js +111 -0
- package/dist/v1/helper.js.map +1 -0
- package/dist/v1/transforms/AirPurifierState.d.ts +2 -0
- package/dist/v1/transforms/AirPurifierState.js +9 -0
- package/dist/v1/transforms/AirPurifierState.js.map +1 -0
- package/dist/v1/transforms/AirState.d.ts +9 -0
- package/dist/v1/transforms/AirState.js +55 -0
- package/dist/v1/transforms/AirState.js.map +1 -0
- package/dist/v1/transforms/HoodState.d.ts +17 -0
- package/dist/v1/transforms/HoodState.js +20 -0
- package/dist/v1/transforms/HoodState.js.map +1 -0
- package/dist/v1/transforms/RefState.d.ts +6 -0
- package/dist/v1/transforms/RefState.js +29 -0
- package/dist/v1/transforms/RefState.js.map +1 -0
- package/dist/v1/transforms/WasherDryer.d.ts +49 -0
- package/dist/v1/transforms/WasherDryer.js +56 -0
- package/dist/v1/transforms/WasherDryer.js.map +1 -0
- package/docs/authorization.md +40 -0
- package/docs/device-configuration.md +68 -0
- package/homebridge-ui/public/index.html +120 -0
- package/homebridge-ui/public/js/app.js +300 -0
- package/homebridge-ui/public/js/countries.js +233 -0
- package/homebridge-ui/public/styles.css +185 -0
- package/homebridge-ui/server.js +103 -0
- package/jest.config.ts +39 -0
- package/package.json +83 -0
- package/sample/README.md +10 -0
- package/sample/airconditioner-model.json +3080 -0
- package/sample/airconditioner-snapshot.json +49 -0
- package/sample/airconditioner.json +157 -0
- package/sample/dishwasher-model.json +869 -0
- package/sample/dishwasher.json +125 -0
- package/sample/washer_dryer-model.json +1294 -0
- package/sample/washer_dryer.json +126 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Gateway } from './Gateway.js';
|
|
2
|
+
import { Session } from './Session.js';
|
|
3
|
+
import { Logger } from 'homebridge';
|
|
4
|
+
/**
|
|
5
|
+
* Handles authentication with the LG ThinQ API.
|
|
6
|
+
* This class manages login, token refresh, and user session handling.
|
|
7
|
+
*/
|
|
8
|
+
export declare class Auth {
|
|
9
|
+
protected gateway: Gateway;
|
|
10
|
+
logger: Logger;
|
|
11
|
+
/**
|
|
12
|
+
* The base URL for the LG API, determined by the user's country code.
|
|
13
|
+
*/
|
|
14
|
+
lgeapi_url: string;
|
|
15
|
+
/**
|
|
16
|
+
* Creates a new `Auth` instance.
|
|
17
|
+
*
|
|
18
|
+
* @param gateway - The `Gateway` instance containing API endpoint information.
|
|
19
|
+
* @param logger - The logger instance for logging debug and error messages.
|
|
20
|
+
*/
|
|
21
|
+
constructor(gateway: Gateway, logger: Logger);
|
|
22
|
+
/**
|
|
23
|
+
* Logs in to the LG ThinQ API using the provided username and password.
|
|
24
|
+
*
|
|
25
|
+
* @param username - The user's username.
|
|
26
|
+
* @param password - The user's password.
|
|
27
|
+
* @returns A promise that resolves with a `Session` instance.
|
|
28
|
+
*/
|
|
29
|
+
login(username: string, password: string): Promise<Session>;
|
|
30
|
+
/**
|
|
31
|
+
* Performs the second step of the login process using an encrypted password.
|
|
32
|
+
*
|
|
33
|
+
* @param username - The user's username.
|
|
34
|
+
* @param encrypted_password - The encrypted password.
|
|
35
|
+
* @param extra_headers - Optional additional headers for the request.
|
|
36
|
+
* @returns A promise that resolves with a `Session` instance.
|
|
37
|
+
*/
|
|
38
|
+
loginStep2(username: string, encrypted_password: string, extra_headers?: any): Promise<Session>;
|
|
39
|
+
/**
|
|
40
|
+
* Retrieves the default headers for EMP requests.
|
|
41
|
+
*/
|
|
42
|
+
get defaultEmpHeaders(): {
|
|
43
|
+
Accept: string;
|
|
44
|
+
'X-Application-Key': string;
|
|
45
|
+
'X-Client-App-Key': string;
|
|
46
|
+
'X-Lge-Svccode': string;
|
|
47
|
+
'X-Device-Type': string;
|
|
48
|
+
'X-Device-Platform': string;
|
|
49
|
+
'X-Device-Language-Type': string;
|
|
50
|
+
'X-Device-Publish-Flag': string;
|
|
51
|
+
'X-Device-Country': string;
|
|
52
|
+
'X-Device-Language': string;
|
|
53
|
+
'Content-Type': string;
|
|
54
|
+
'Access-Control-Allow-Origin': string;
|
|
55
|
+
'Accept-Encoding': string;
|
|
56
|
+
'Accept-Language': string;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Handles new terms and conditions that require user agreement.
|
|
60
|
+
*
|
|
61
|
+
* @param accessToken - The access token for the session.
|
|
62
|
+
*/
|
|
63
|
+
handleNewTerm(accessToken: string): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Retrieves the JSession ID for ThinQ v1 API compatibility.
|
|
66
|
+
*
|
|
67
|
+
* @param accessToken - The access token for the session.
|
|
68
|
+
* @returns A promise that resolves with the JSession ID.
|
|
69
|
+
*/
|
|
70
|
+
getJSessionId(accessToken: string): Promise<any>;
|
|
71
|
+
/**
|
|
72
|
+
* Refreshes the access token using the refresh token.
|
|
73
|
+
*
|
|
74
|
+
* @param session - The current `Session` instance.
|
|
75
|
+
* @returns A promise that resolves with the updated `Session` instance.
|
|
76
|
+
*/
|
|
77
|
+
refreshNewToken(session: Session): Promise<Session>;
|
|
78
|
+
/**
|
|
79
|
+
* Retrieves the user's unique number from the LG API.
|
|
80
|
+
*
|
|
81
|
+
* @param accessToken - The access token for the session.
|
|
82
|
+
* @returns A promise that resolves with the user's unique number.
|
|
83
|
+
*/
|
|
84
|
+
getUserNumber(accessToken: string): Promise<string>;
|
|
85
|
+
/**
|
|
86
|
+
* Constructs the login URL for the LG ThinQ API.
|
|
87
|
+
*
|
|
88
|
+
* @returns The login URL.
|
|
89
|
+
*/
|
|
90
|
+
getLoginUrl(): Promise<string>;
|
|
91
|
+
/**
|
|
92
|
+
* Generates a signature for API requests.
|
|
93
|
+
*
|
|
94
|
+
* @param message - The message to sign.
|
|
95
|
+
* @param secret - The secret key used for signing.
|
|
96
|
+
* @returns The generated signature.
|
|
97
|
+
*/
|
|
98
|
+
protected signature(message: string, secret: string): string;
|
|
99
|
+
}
|
package/dist/lib/Auth.js
ADDED
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
import { DateTime } from 'luxon';
|
|
3
|
+
import qs from 'qs';
|
|
4
|
+
import { URL } from 'url';
|
|
5
|
+
import { AuthenticationError, ManualProcessNeededErrorCode, TokenError } from '../errors/index.js';
|
|
6
|
+
import * as constants from './constants.js';
|
|
7
|
+
import { requestClient } from './request.js';
|
|
8
|
+
import { Session } from './Session.js';
|
|
9
|
+
/**
|
|
10
|
+
* Handles authentication with the LG ThinQ API.
|
|
11
|
+
* This class manages login, token refresh, and user session handling.
|
|
12
|
+
*/
|
|
13
|
+
export class Auth {
|
|
14
|
+
gateway;
|
|
15
|
+
logger;
|
|
16
|
+
/**
|
|
17
|
+
* The base URL for the LG API, determined by the user's country code.
|
|
18
|
+
*/
|
|
19
|
+
lgeapi_url;
|
|
20
|
+
/**
|
|
21
|
+
* Creates a new `Auth` instance.
|
|
22
|
+
*
|
|
23
|
+
* @param gateway - The `Gateway` instance containing API endpoint information.
|
|
24
|
+
* @param logger - The logger instance for logging debug and error messages.
|
|
25
|
+
*/
|
|
26
|
+
constructor(gateway, logger) {
|
|
27
|
+
this.gateway = gateway;
|
|
28
|
+
this.logger = logger;
|
|
29
|
+
this.lgeapi_url = `https://${this.gateway.country_code.toLowerCase()}.lgeapi.com/`;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Logs in to the LG ThinQ API using the provided username and password.
|
|
33
|
+
*
|
|
34
|
+
* @param username - The user's username.
|
|
35
|
+
* @param password - The user's password.
|
|
36
|
+
* @returns A promise that resolves with a `Session` instance.
|
|
37
|
+
*/
|
|
38
|
+
async login(username, password) {
|
|
39
|
+
// get signature and timestamp in login form
|
|
40
|
+
const hash = crypto.createHash('sha512');
|
|
41
|
+
return this.loginStep2(username, hash.update(password).digest('hex'));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Performs the second step of the login process using an encrypted password.
|
|
45
|
+
*
|
|
46
|
+
* @param username - The user's username.
|
|
47
|
+
* @param encrypted_password - The encrypted password.
|
|
48
|
+
* @param extra_headers - Optional additional headers for the request.
|
|
49
|
+
* @returns A promise that resolves with a `Session` instance.
|
|
50
|
+
*/
|
|
51
|
+
async loginStep2(username, encrypted_password, extra_headers) {
|
|
52
|
+
const headers = this.defaultEmpHeaders;
|
|
53
|
+
const preLoginData = {
|
|
54
|
+
'user_auth2': encrypted_password,
|
|
55
|
+
'log_param': 'login request / user_id : ' + username + ' / third_party : null / svc_list : SVC202,SVC710 / 3rd_service : ',
|
|
56
|
+
};
|
|
57
|
+
const preLoginResponse = await requestClient.post(this.gateway.login_base_url + 'preLogin', qs.stringify(preLoginData), { headers });
|
|
58
|
+
const preLogin = preLoginResponse.data;
|
|
59
|
+
headers['X-Signature'] = preLogin.signature;
|
|
60
|
+
headers['X-Timestamp'] = preLogin.tStamp;
|
|
61
|
+
const data = {
|
|
62
|
+
'user_auth2': preLogin.encrypted_pw,
|
|
63
|
+
'password_hash_prameter_flag': 'Y',
|
|
64
|
+
'svc_list': 'SVC202,SVC710', // SVC202=LG SmartHome, SVC710=EMP OAuth
|
|
65
|
+
...extra_headers,
|
|
66
|
+
};
|
|
67
|
+
// try login with username and hashed password
|
|
68
|
+
const loginUrl = this.gateway.emp_base_url + 'emp/v2.0/account/session/' + encodeURIComponent(username);
|
|
69
|
+
let account;
|
|
70
|
+
try {
|
|
71
|
+
const loginResponse = await requestClient.post(loginUrl, qs.stringify(data), { headers });
|
|
72
|
+
account = loginResponse.data.account;
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
if (!err.response) {
|
|
76
|
+
throw err;
|
|
77
|
+
}
|
|
78
|
+
const { code, message } = err.response.data.error;
|
|
79
|
+
if (code === 'MS.001.03') {
|
|
80
|
+
throw new AuthenticationError('Your account was already used to registered in ' + message + '.');
|
|
81
|
+
}
|
|
82
|
+
throw new AuthenticationError(message);
|
|
83
|
+
}
|
|
84
|
+
// dynamic get secret key for emp signature
|
|
85
|
+
const empSearchKeyUrl = this.gateway.login_base_url + 'searchKey?key_name=OAUTH_SECRETKEY&sever_type=OP';
|
|
86
|
+
const secretKeyResponse = await requestClient.get(empSearchKeyUrl);
|
|
87
|
+
const secretKey = secretKeyResponse.data.returnData;
|
|
88
|
+
const timestamp = DateTime.utc().toRFC2822();
|
|
89
|
+
const empData = {
|
|
90
|
+
account_type: account.userIDType,
|
|
91
|
+
client_id: constants.CLIENT_ID,
|
|
92
|
+
country_code: account.country,
|
|
93
|
+
redirect_uri: 'lgaccount.lgsmartthinq:/',
|
|
94
|
+
response_type: 'code',
|
|
95
|
+
state: '12345',
|
|
96
|
+
username: account.userID,
|
|
97
|
+
};
|
|
98
|
+
const empUrl = new URL('https://emp-oauth.lgecloud.com/emp/oauth2/authorize/empsession?' + qs.stringify(empData));
|
|
99
|
+
const signature = this.signature(`${empUrl.pathname}${empUrl.search}\n${timestamp}`, secretKey);
|
|
100
|
+
const empHeaders = {
|
|
101
|
+
'lgemp-x-app-key': constants.OAUTH_CLIENT_KEY,
|
|
102
|
+
'lgemp-x-date': timestamp,
|
|
103
|
+
'lgemp-x-session-key': account.loginSessionID,
|
|
104
|
+
'lgemp-x-signature': signature,
|
|
105
|
+
'Accept': 'application/json',
|
|
106
|
+
'X-Device-Type': 'M01',
|
|
107
|
+
'X-Device-Platform': 'ADR',
|
|
108
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
109
|
+
'Access-Control-Allow-Origin': '*',
|
|
110
|
+
'Accept-Encoding': 'gzip, deflate, br',
|
|
111
|
+
'Accept-Language': 'en-US,en;q=0.9',
|
|
112
|
+
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36 Edg/93.0.961.44',
|
|
113
|
+
};
|
|
114
|
+
// create emp session and get access token
|
|
115
|
+
let authorize;
|
|
116
|
+
try {
|
|
117
|
+
const authorizeResponse = await requestClient.get(empUrl.href, { headers: empHeaders });
|
|
118
|
+
authorize = authorizeResponse.data;
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
throw new AuthenticationError(err.response.data.error.message);
|
|
122
|
+
}
|
|
123
|
+
if (authorize.status !== 1) {
|
|
124
|
+
throw new TokenError(authorize.message || authorize);
|
|
125
|
+
}
|
|
126
|
+
const redirect_uri = new URL(authorize.redirect_uri);
|
|
127
|
+
const tokenData = {
|
|
128
|
+
code: redirect_uri.searchParams.get('code'),
|
|
129
|
+
grant_type: 'authorization_code',
|
|
130
|
+
redirect_uri: empData.redirect_uri,
|
|
131
|
+
};
|
|
132
|
+
const requestUrl = '/oauth/1.0/oauth2/token?' + qs.stringify(tokenData);
|
|
133
|
+
const res = await requestClient.post(redirect_uri.searchParams.get('oauth2_backend_url') + 'oauth/1.0/oauth2/token', qs.stringify(tokenData), {
|
|
134
|
+
headers: {
|
|
135
|
+
'x-lge-app-os': 'ADR',
|
|
136
|
+
'x-lge-appkey': constants.CLIENT_ID,
|
|
137
|
+
'x-lge-oauth-signature': this.signature(`${requestUrl}\n${timestamp}`, constants.OAUTH_SECRET_KEY),
|
|
138
|
+
'x-lge-oauth-date': timestamp,
|
|
139
|
+
'Accept': 'application/json',
|
|
140
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
const token = res.data;
|
|
144
|
+
this.lgeapi_url = token.oauth2_backend_url || this.lgeapi_url;
|
|
145
|
+
return new Session(token.access_token, token.refresh_token, token.expires_in);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Retrieves the default headers for EMP requests.
|
|
149
|
+
*/
|
|
150
|
+
get defaultEmpHeaders() {
|
|
151
|
+
return {
|
|
152
|
+
'Accept': 'application/json',
|
|
153
|
+
'X-Application-Key': constants.APPLICATION_KEY,
|
|
154
|
+
'X-Client-App-Key': constants.CLIENT_ID,
|
|
155
|
+
'X-Lge-Svccode': 'SVC709',
|
|
156
|
+
'X-Device-Type': 'M01',
|
|
157
|
+
'X-Device-Platform': 'ADR',
|
|
158
|
+
'X-Device-Language-Type': 'IETF',
|
|
159
|
+
'X-Device-Publish-Flag': 'Y',
|
|
160
|
+
'X-Device-Country': this.gateway.country_code,
|
|
161
|
+
'X-Device-Language': this.gateway.language_code,
|
|
162
|
+
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
|
|
163
|
+
'Access-Control-Allow-Origin': '*',
|
|
164
|
+
'Accept-Encoding': 'gzip, deflate, br',
|
|
165
|
+
'Accept-Language': 'en-US,en;q=0.9',
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Handles new terms and conditions that require user agreement.
|
|
170
|
+
*
|
|
171
|
+
* @param accessToken - The access token for the session.
|
|
172
|
+
*/
|
|
173
|
+
async handleNewTerm(accessToken) {
|
|
174
|
+
const showTermUrl = 'common/showTerms?callback_url=lgaccount.lgsmartthinq:/updateTerms'
|
|
175
|
+
+ '&country=VN&language=en-VN&division=ha:T20&terms_display_type=3&svc_list=SVC202';
|
|
176
|
+
const showTermResponse = await requestClient.get(this.gateway.login_base_url + showTermUrl, {
|
|
177
|
+
headers: {
|
|
178
|
+
'X-Login-Session': accessToken,
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
const showTermHtml = showTermResponse.data;
|
|
182
|
+
const headers = {
|
|
183
|
+
...this.defaultEmpHeaders,
|
|
184
|
+
'X-Login-Session': accessToken,
|
|
185
|
+
'X-Signature': showTermHtml.match(/signature[\s]+:[\s]+"([^"]+)"/)[1],
|
|
186
|
+
'X-Timestamp': showTermHtml.match(/tStamp[\s]+:[\s]+"([^"]+)"/)[1],
|
|
187
|
+
};
|
|
188
|
+
const accountTermUrl = 'emp/v2.0/account/user/terms?opt_term_cond=001&term_data=SVC202&itg_terms_use_flag=Y&dummy_terms_use_flag=Y';
|
|
189
|
+
const accountTermResponse = await requestClient.get(this.gateway.emp_base_url + accountTermUrl, { headers });
|
|
190
|
+
const accountTerms = (accountTermResponse.data.account?.terms || []).map((term) => {
|
|
191
|
+
return term.termsID;
|
|
192
|
+
});
|
|
193
|
+
const termInfoUrl = 'emp/v2.0/info/terms?opt_term_cond=001&only_service_terms_flag=&itg_terms_use_flag=Y&term_data=SVC202';
|
|
194
|
+
const termInfoResponse = await requestClient.get(this.gateway.emp_base_url + termInfoUrl, { headers });
|
|
195
|
+
const infoTerms = termInfoResponse.data.info.terms;
|
|
196
|
+
const newTermAgreeNeeded = infoTerms.filter((term) => {
|
|
197
|
+
return accountTerms.indexOf(term.termsID) === -1;
|
|
198
|
+
}).map((term) => {
|
|
199
|
+
return [term.termsType, term.termsID, term.defaultLang].join(':');
|
|
200
|
+
}).join(',');
|
|
201
|
+
if (newTermAgreeNeeded) {
|
|
202
|
+
const updateAccountTermUrl = 'emp/v2.0/account/user/terms';
|
|
203
|
+
await requestClient.post(this.gateway.emp_base_url + updateAccountTermUrl, qs.stringify({ terms: newTermAgreeNeeded }), {
|
|
204
|
+
headers,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Retrieves the JSession ID for ThinQ v1 API compatibility.
|
|
210
|
+
*
|
|
211
|
+
* @param accessToken - The access token for the session.
|
|
212
|
+
* @returns A promise that resolves with the JSession ID.
|
|
213
|
+
*/
|
|
214
|
+
async getJSessionId(accessToken) {
|
|
215
|
+
// login to old gateway also - thinq v1
|
|
216
|
+
const memberLoginUrl = this.gateway.thinq1_url + 'member/login';
|
|
217
|
+
const memberLoginHeaders = {
|
|
218
|
+
'x-thinq-application-key': 'wideq',
|
|
219
|
+
'x-thinq-security-key': 'nuts_securitykey',
|
|
220
|
+
'Accept': 'application/json',
|
|
221
|
+
'x-thinq-token': accessToken,
|
|
222
|
+
};
|
|
223
|
+
const memberLoginData = {
|
|
224
|
+
countryCode: this.gateway.country_code,
|
|
225
|
+
langCode: this.gateway.language_code,
|
|
226
|
+
loginType: 'EMP',
|
|
227
|
+
token: accessToken,
|
|
228
|
+
};
|
|
229
|
+
try {
|
|
230
|
+
const memberLoginResponse = await requestClient.post(memberLoginUrl, { lgedmRoot: memberLoginData }, {
|
|
231
|
+
headers: memberLoginHeaders,
|
|
232
|
+
});
|
|
233
|
+
return memberLoginResponse.data.lgedmRoot.jsessionId;
|
|
234
|
+
}
|
|
235
|
+
catch (err) {
|
|
236
|
+
this.logger.debug(err.message.startsWith(ManualProcessNeededErrorCode)
|
|
237
|
+
? 'Please open the native LG App and sign in to your account to see what happened,'
|
|
238
|
+
+ ' maybe new agreement need your accept. Then try restarting Homebridge.'
|
|
239
|
+
: err.message);
|
|
240
|
+
this.logger.debug(err);
|
|
241
|
+
this.logger.info('Failed to login to old thinq v1 gateway. See debug logs for more details. Continuing anyways.');
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Refreshes the access token using the refresh token.
|
|
246
|
+
*
|
|
247
|
+
* @param session - The current `Session` instance.
|
|
248
|
+
* @returns A promise that resolves with the updated `Session` instance.
|
|
249
|
+
*/
|
|
250
|
+
async refreshNewToken(session) {
|
|
251
|
+
try {
|
|
252
|
+
const gatewayResponse = await requestClient.post('https://kic.lgthinq.com:46030/api/common/gatewayUriList', {
|
|
253
|
+
lgedmRoot: {
|
|
254
|
+
countryCode: this.gateway.country_code,
|
|
255
|
+
langCode: this.gateway.language_code,
|
|
256
|
+
},
|
|
257
|
+
}, {
|
|
258
|
+
headers: {
|
|
259
|
+
'Accept': 'application/json',
|
|
260
|
+
'x-thinq-application-key': 'wideq',
|
|
261
|
+
'x-thinq-security-key': 'nuts_securitykey',
|
|
262
|
+
},
|
|
263
|
+
});
|
|
264
|
+
this.lgeapi_url = gatewayResponse.data.lgedmRoot.oauthUri + '/';
|
|
265
|
+
}
|
|
266
|
+
catch (err) {
|
|
267
|
+
// ignore this error
|
|
268
|
+
}
|
|
269
|
+
const tokenUrl = this.lgeapi_url + 'oauth/1.0/oauth2/token';
|
|
270
|
+
const data = {
|
|
271
|
+
grant_type: 'refresh_token',
|
|
272
|
+
refresh_token: session.refreshToken,
|
|
273
|
+
};
|
|
274
|
+
const timestamp = DateTime.utc().toRFC2822();
|
|
275
|
+
const requestUrl = '/oauth/1.0/oauth2/token' + qs.stringify(data, { addQueryPrefix: true });
|
|
276
|
+
const signature = this.signature(`${requestUrl}\n${timestamp}`, constants.OAUTH_SECRET_KEY);
|
|
277
|
+
const headers = {
|
|
278
|
+
'x-lge-app-os': 'ADR',
|
|
279
|
+
'x-lge-appkey': constants.CLIENT_ID,
|
|
280
|
+
'x-lge-oauth-signature': signature,
|
|
281
|
+
'x-lge-oauth-date': timestamp,
|
|
282
|
+
'Accept': 'application/json',
|
|
283
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
284
|
+
};
|
|
285
|
+
const tokenResponse = await requestClient.post(tokenUrl, qs.stringify(data), { headers });
|
|
286
|
+
session.newToken(tokenResponse.data.access_token, parseInt(tokenResponse.data.expires_in));
|
|
287
|
+
return session;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Retrieves the user's unique number from the LG API.
|
|
291
|
+
*
|
|
292
|
+
* @param accessToken - The access token for the session.
|
|
293
|
+
* @returns A promise that resolves with the user's unique number.
|
|
294
|
+
*/
|
|
295
|
+
async getUserNumber(accessToken) {
|
|
296
|
+
const profileUrl = this.lgeapi_url + 'users/profile';
|
|
297
|
+
const timestamp = DateTime.utc().toRFC2822();
|
|
298
|
+
const signature = this.signature(`/users/profile\n${timestamp}`, constants.OAUTH_SECRET_KEY);
|
|
299
|
+
const headers = {
|
|
300
|
+
'Accept': 'application/json',
|
|
301
|
+
'Authorization': 'Bearer ' + accessToken,
|
|
302
|
+
'X-Lge-Svccode': 'SVC202',
|
|
303
|
+
'X-Application-Key': constants.APPLICATION_KEY,
|
|
304
|
+
'lgemp-x-app-key': constants.CLIENT_ID,
|
|
305
|
+
'X-Device-Type': 'M01',
|
|
306
|
+
'X-Device-Platform': 'ADR',
|
|
307
|
+
'x-lge-oauth-date': timestamp,
|
|
308
|
+
'x-lge-oauth-signature': signature,
|
|
309
|
+
};
|
|
310
|
+
const profileResponse = await requestClient.get(profileUrl, { headers });
|
|
311
|
+
if (profileResponse.data.status === 2) {
|
|
312
|
+
throw new AuthenticationError(profileResponse.data.message);
|
|
313
|
+
}
|
|
314
|
+
return profileResponse.data.account.userNo;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Constructs the login URL for the LG ThinQ API.
|
|
318
|
+
*
|
|
319
|
+
* @returns The login URL.
|
|
320
|
+
*/
|
|
321
|
+
async getLoginUrl() {
|
|
322
|
+
const params = {
|
|
323
|
+
country: this.gateway.country_code,
|
|
324
|
+
language: this.gateway.language_code,
|
|
325
|
+
client_id: constants.CLIENT_ID,
|
|
326
|
+
svc_list: constants.SVC_CODE,
|
|
327
|
+
svc_integrated: 'Y',
|
|
328
|
+
redirect_uri: 'lgaccount.lgsmartthinq:/',
|
|
329
|
+
show_thirdparty_login: 'LGE,MYLG,GGL,AMZ,FBK,APPL',
|
|
330
|
+
division: 'ha:T20',
|
|
331
|
+
callback_url: 'lgaccount.lgsmartthinq:/',
|
|
332
|
+
oauth2State: '12345',
|
|
333
|
+
show_select_country: 'N',
|
|
334
|
+
};
|
|
335
|
+
return this.gateway.login_base_url + 'login/signIn' + qs.stringify(params, { addQueryPrefix: true });
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Generates a signature for API requests.
|
|
339
|
+
*
|
|
340
|
+
* @param message - The message to sign.
|
|
341
|
+
* @param secret - The secret key used for signing.
|
|
342
|
+
* @returns The generated signature.
|
|
343
|
+
*/
|
|
344
|
+
signature(message, secret) {
|
|
345
|
+
return crypto.createHmac('sha1', Buffer.from(secret)).update(message).digest('base64');
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
//# sourceMappingURL=Auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Auth.js","sourceRoot":"","sources":["../../src/lib/Auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/* eslint-disable dot-notation */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-require-imports */
|
|
3
|
+
import { Auth } from './Auth.js';
|
|
4
|
+
import { Gateway } from './Gateway.js';
|
|
5
|
+
import { Session } from './Session.js';
|
|
6
|
+
import { describe, test, beforeEach, expect, jest } from '@jest/globals';
|
|
7
|
+
import { AuthenticationError } from '../errors/index.js';
|
|
8
|
+
describe('Auth', () => {
|
|
9
|
+
let auth;
|
|
10
|
+
let mockGateway;
|
|
11
|
+
let mockLogger;
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
mockGateway = new Gateway({
|
|
14
|
+
empTermsUri: 'https://example.com/emp',
|
|
15
|
+
empSpxUri: 'https://example.com/spx',
|
|
16
|
+
thinq2Uri: 'https://example.com/thinq2',
|
|
17
|
+
thinq1Uri: 'https://example.com/thinq1',
|
|
18
|
+
countryCode: 'US',
|
|
19
|
+
languageCode: 'en-US',
|
|
20
|
+
});
|
|
21
|
+
mockLogger = {
|
|
22
|
+
debug: jest.fn(),
|
|
23
|
+
info: jest.fn(),
|
|
24
|
+
warn: jest.fn(),
|
|
25
|
+
error: jest.fn(),
|
|
26
|
+
};
|
|
27
|
+
auth = new Auth(mockGateway, mockLogger);
|
|
28
|
+
});
|
|
29
|
+
test('should initialize with correct API URL', () => {
|
|
30
|
+
expect(auth.lgeapi_url).toBe('https://us.lgeapi.com/');
|
|
31
|
+
});
|
|
32
|
+
test('should generate default EMP headers', () => {
|
|
33
|
+
const headers = auth.defaultEmpHeaders;
|
|
34
|
+
expect(headers['X-Device-Country']).toBe('US');
|
|
35
|
+
expect(headers['X-Device-Language']).toBe('en-US');
|
|
36
|
+
expect(headers['Content-Type']).toBe('application/x-www-form-urlencoded;charset=UTF-8');
|
|
37
|
+
});
|
|
38
|
+
test('should login and return a session', async () => {
|
|
39
|
+
const mockSession = new Session('accessToken', 'refreshToken', Date.now() + 3600 * 1000);
|
|
40
|
+
jest.spyOn(auth, 'loginStep2').mockResolvedValueOnce(mockSession);
|
|
41
|
+
const session = await auth.login('testUser', 'testPassword');
|
|
42
|
+
expect(session).toBe(mockSession);
|
|
43
|
+
expect(auth.loginStep2).toHaveBeenCalledWith('testUser', expect.any(String));
|
|
44
|
+
});
|
|
45
|
+
test('should handle loginStep2 and return a session', async () => {
|
|
46
|
+
const mockPreLoginResponse = {
|
|
47
|
+
signature: 'mockSignature',
|
|
48
|
+
tStamp: 'mockTimestamp',
|
|
49
|
+
encrypted_pw: 'mockEncryptedPassword',
|
|
50
|
+
};
|
|
51
|
+
const mockAccountResponse = {
|
|
52
|
+
account: {
|
|
53
|
+
userIDType: 'EMP',
|
|
54
|
+
country: 'US',
|
|
55
|
+
userID: 'testUser',
|
|
56
|
+
loginSessionID: 'session123',
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
const mockSecretKeyResponse = { returnData: 'mockSecretKey' };
|
|
60
|
+
const mockAuthorizeResponse = {
|
|
61
|
+
status: 1,
|
|
62
|
+
redirect_uri: 'https://example.com/oauth?code=mockCode',
|
|
63
|
+
};
|
|
64
|
+
const mockTokenResponse = {
|
|
65
|
+
access_token: 'accessToken',
|
|
66
|
+
refresh_token: 'refreshToken',
|
|
67
|
+
expires_in: 3600,
|
|
68
|
+
oauth2_backend_url: 'https://example.com/oauth',
|
|
69
|
+
};
|
|
70
|
+
jest.spyOn(auth['gateway'], 'emp_base_url', 'get').mockReturnValue('https://example.com/emp/');
|
|
71
|
+
jest.spyOn(auth['gateway'], 'login_base_url', 'get').mockReturnValue('https://example.com/spx/');
|
|
72
|
+
jest.spyOn(auth['gateway'], 'country_code', 'get').mockReturnValue('US');
|
|
73
|
+
jest.spyOn(auth['gateway'], 'language_code', 'get').mockReturnValue('en-US');
|
|
74
|
+
// jest.spyOn(auth['defaultEmpHeaders'], 'toString').mockReturnValueOnce('');
|
|
75
|
+
const requestClient = require('./request').requestClient;
|
|
76
|
+
jest.spyOn(requestClient, 'post')
|
|
77
|
+
.mockResolvedValueOnce({ data: mockPreLoginResponse }) // Mock preLogin response
|
|
78
|
+
.mockResolvedValueOnce({ data: mockAccountResponse }) // Mock account response
|
|
79
|
+
.mockResolvedValueOnce({ data: mockTokenResponse }); // Mock token response
|
|
80
|
+
jest.spyOn(requestClient, 'get')
|
|
81
|
+
.mockResolvedValueOnce({ data: mockSecretKeyResponse }) // Mock secret key response
|
|
82
|
+
.mockResolvedValueOnce({ data: mockAuthorizeResponse }); // Mock authorize response
|
|
83
|
+
const session = await auth.loginStep2('testUser', 'mockEncryptedPassword');
|
|
84
|
+
expect(session).toBeInstanceOf(Session);
|
|
85
|
+
expect(session.accessToken).toBe('accessToken');
|
|
86
|
+
expect(session.refreshToken).toBe('refreshToken');
|
|
87
|
+
});
|
|
88
|
+
test('should throw AuthenticationError for invalid login', async () => {
|
|
89
|
+
const mockErrorResponse = {
|
|
90
|
+
response: {
|
|
91
|
+
data: {
|
|
92
|
+
error: {
|
|
93
|
+
code: 'MS.001.03',
|
|
94
|
+
message: 'Account already registered.',
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
const mockPreLoginResponse = {
|
|
100
|
+
signature: 'mockSignature',
|
|
101
|
+
tStamp: 'mockTimestamp',
|
|
102
|
+
encrypted_pw: 'mockEncryptedPassword',
|
|
103
|
+
};
|
|
104
|
+
const requestClient = require('./request').requestClient;
|
|
105
|
+
jest.spyOn(requestClient, 'post')
|
|
106
|
+
.mockResolvedValueOnce({ data: mockPreLoginResponse }) // Mock preLogin response
|
|
107
|
+
.mockRejectedValueOnce(mockErrorResponse);
|
|
108
|
+
await expect(auth.loginStep2('testUser', 'mockEncryptedPassword')).rejects.toThrow(AuthenticationError);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
//# sourceMappingURL=Auth.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Auth.spec.js","sourceRoot":"","sources":["../../src/lib/Auth.spec.ts"],"names":[],"mappings":"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"}
|