@gooin/garmin-connect 1.7.5 → 1.8.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/dist/common/FileMFASessionStorage.js +1 -247
- package/dist/common/HttpClient copy.js +1 -361
- package/dist/common/HttpClient.d.ts +1 -0
- package/dist/common/HttpClient.js +1 -613
- package/dist/common/HttpClient.js.map +1 -1
- package/dist/common/HttpClientOLD.js +1 -361
- package/dist/common/HttpClientOLDV1.js +1 -361
- package/dist/common/HttpClientV1.js +1 -577
- package/dist/common/MFAManager.js +1 -126
- package/dist/common/MFASessionStorage.js +1 -3
- package/dist/common/RedisMFASessionStorage.js +1 -281
- package/dist/common/RedisMFASessionStorage.js.map +1 -1
- package/dist/garmin/GarminConnect.d.ts +15 -69
- package/dist/garmin/GarminConnect.js +1 -509
- package/dist/garmin/GarminConnect.js.map +1 -1
- package/dist/garmin/UrlClass.d.ts +28 -0
- package/dist/garmin/UrlClass.js +1 -128
- package/dist/garmin/UrlClass.js.map +1 -1
- package/dist/garmin/common/DateUtils.d.ts +1 -0
- package/dist/garmin/common/DateUtils.js +1 -38
- package/dist/garmin/common/DateUtils.js.map +1 -1
- package/dist/garmin/common/HydrationUtils.js +1 -16
- package/dist/garmin/common/WeightUtils.js +1 -9
- package/dist/garmin/modules/activity/base.d.ts +39 -0
- package/dist/garmin/modules/activity/base.js +1 -0
- package/dist/garmin/modules/activity/base.js.map +1 -0
- package/dist/garmin/modules/activity/cycling.d.ts +16 -0
- package/dist/garmin/modules/activity/cycling.js +1 -0
- package/dist/garmin/modules/activity/cycling.js.map +1 -0
- package/dist/garmin/modules/activity/running.d.ts +15 -0
- package/dist/garmin/modules/activity/running.js +1 -0
- package/dist/garmin/modules/activity/running.js.map +1 -0
- package/dist/garmin/modules/activity/training-status.d.ts +13 -0
- package/dist/garmin/modules/activity/training-status.js +1 -0
- package/dist/garmin/modules/activity/training-status.js.map +1 -0
- package/dist/garmin/modules/coach/activity-summary.d.ts +20 -0
- package/dist/garmin/modules/coach/activity-summary.js +1 -0
- package/dist/garmin/modules/coach/activity-summary.js.map +1 -0
- package/dist/garmin/modules/coach/helpers.d.ts +157 -0
- package/dist/garmin/modules/coach/helpers.js +1 -0
- package/dist/garmin/modules/coach/helpers.js.map +1 -0
- package/dist/garmin/modules/coach/training-overview.d.ts +5 -0
- package/dist/garmin/modules/coach/training-overview.js +1 -0
- package/dist/garmin/modules/coach/training-overview.js.map +1 -0
- package/dist/garmin/modules/coach/wellness-overview.d.ts +5 -0
- package/dist/garmin/modules/coach/wellness-overview.js +1 -0
- package/dist/garmin/modules/coach/wellness-overview.js.map +1 -0
- package/dist/garmin/modules/coach/wellness-summary.d.ts +4 -0
- package/dist/garmin/modules/coach/wellness-summary.js +1 -0
- package/dist/garmin/modules/coach/wellness-summary.js.map +1 -0
- package/dist/garmin/modules/coach.d.ts +60 -0
- package/dist/garmin/modules/coach.js +1 -0
- package/dist/garmin/modules/coach.js.map +1 -0
- package/dist/garmin/modules/course.d.ts +27 -0
- package/dist/garmin/modules/course.js +1 -0
- package/dist/garmin/modules/course.js.map +1 -0
- package/dist/garmin/modules/device.d.ts +11 -0
- package/dist/garmin/modules/device.js +1 -0
- package/dist/garmin/modules/device.js.map +1 -0
- package/dist/garmin/modules/misc.d.ts +18 -0
- package/dist/garmin/modules/misc.js +1 -0
- package/dist/garmin/modules/misc.js.map +1 -0
- package/dist/garmin/modules/types.d.ts +10 -0
- package/dist/garmin/modules/types.js +1 -0
- package/dist/garmin/modules/types.js.map +1 -0
- package/dist/garmin/modules/user.d.ts +18 -0
- package/dist/garmin/modules/user.js +1 -0
- package/dist/garmin/modules/user.js.map +1 -0
- package/dist/garmin/modules/wellness/body-battery.d.ts +11 -0
- package/dist/garmin/modules/wellness/body-battery.js +1 -0
- package/dist/garmin/modules/wellness/body-battery.js.map +1 -0
- package/dist/garmin/modules/wellness/heart-rate.d.ts +11 -0
- package/dist/garmin/modules/wellness/heart-rate.js +1 -0
- package/dist/garmin/modules/wellness/heart-rate.js.map +1 -0
- package/dist/garmin/modules/wellness/hrv.d.ts +12 -0
- package/dist/garmin/modules/wellness/hrv.js +1 -0
- package/dist/garmin/modules/wellness/hrv.js.map +1 -0
- package/dist/garmin/modules/wellness/hydration.d.ts +12 -0
- package/dist/garmin/modules/wellness/hydration.js +1 -0
- package/dist/garmin/modules/wellness/hydration.js.map +1 -0
- package/dist/garmin/modules/wellness/sleep.d.ts +16 -0
- package/dist/garmin/modules/wellness/sleep.js +1 -0
- package/dist/garmin/modules/wellness/sleep.js.map +1 -0
- package/dist/garmin/modules/wellness/weight.d.ts +20 -0
- package/dist/garmin/modules/wellness/weight.js +1 -0
- package/dist/garmin/modules/wellness/weight.js.map +1 -0
- package/dist/garmin/modules/workout.d.ts +23 -0
- package/dist/garmin/modules/workout.js +1 -0
- package/dist/garmin/modules/workout.js.map +1 -0
- package/dist/garmin/types/activity-stats.d.ts +21 -0
- package/dist/garmin/types/activity-stats.js +1 -0
- package/dist/garmin/types/activity-stats.js.map +1 -0
- package/dist/garmin/types/activity.js +1 -27
- package/dist/garmin/types/body-battery.d.ts +7 -0
- package/dist/garmin/types/body-battery.js +1 -0
- package/dist/garmin/types/body-battery.js.map +1 -0
- package/dist/garmin/types/coach.d.ts +533 -0
- package/dist/garmin/types/coach.js +1 -0
- package/dist/garmin/types/coach.js.map +1 -0
- package/dist/garmin/types/course.d.ts +3 -11
- package/dist/garmin/types/course.js +1 -3
- package/dist/garmin/types/cycling.d.ts +70 -0
- package/dist/garmin/types/cycling.js +1 -0
- package/dist/garmin/types/cycling.js.map +1 -0
- package/dist/garmin/types/device.d.ts +32 -0
- package/dist/garmin/types/device.js +1 -0
- package/dist/garmin/types/device.js.map +1 -0
- package/dist/garmin/types/golf.d.ts +4 -4
- package/dist/garmin/types/golf.js +1 -3
- package/dist/garmin/types/golf.js.map +1 -1
- package/dist/garmin/types/heartrate.d.ts +3 -3
- package/dist/garmin/types/heartrate.js +1 -2
- package/dist/garmin/types/hrv.d.ts +47 -0
- package/dist/garmin/types/hrv.js +1 -0
- package/dist/garmin/types/hrv.js.map +1 -0
- package/dist/garmin/types/hydration.d.ts +3 -3
- package/dist/garmin/types/hydration.js +1 -2
- package/dist/garmin/types/index.d.ts +15 -0
- package/dist/garmin/types/index.js +1 -36
- package/dist/garmin/types/index.js.map +1 -1
- package/dist/garmin/types/personal-info.d.ts +29 -0
- package/dist/garmin/types/personal-info.js +1 -0
- package/dist/garmin/types/personal-info.js.map +1 -0
- package/dist/garmin/types/race-prediction.d.ts +50 -0
- package/dist/garmin/types/race-prediction.js +1 -0
- package/dist/garmin/types/race-prediction.js.map +1 -0
- package/dist/garmin/types/sleep.d.ts +46 -0
- package/dist/garmin/types/sleep.js +1 -3
- package/dist/garmin/types/training-status.d.ts +70 -0
- package/dist/garmin/types/training-status.js +1 -0
- package/dist/garmin/types/training-status.js.map +1 -0
- package/dist/garmin/types/weight.d.ts +46 -4
- package/dist/garmin/types/weight.js +1 -3
- package/dist/garmin/workouts/Running.js +1 -47
- package/dist/garmin/workouts/templates/RunningTemplate.js +1 -78
- package/dist/index.js +1 -11
- package/dist/utils.js +1 -37
- package/package.json +4 -3
|
@@ -1,247 +1 @@
|
|
|
1
|
-
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.FileMFASessionStorage = void 0;
|
|
7
|
-
const fs_1 = require("fs");
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
9
|
-
/**
|
|
10
|
-
* 文件系统实现的MFA会话存储
|
|
11
|
-
*/
|
|
12
|
-
class FileMFASessionStorage {
|
|
13
|
-
constructor(storageDir) {
|
|
14
|
-
this.DEFAULT_TIMEOUT = 5 * 60 * 1000; // 5分钟
|
|
15
|
-
this.storageDir = storageDir;
|
|
16
|
-
this.ensureStorageDir();
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* 确保存储目录存在
|
|
20
|
-
*/
|
|
21
|
-
async ensureStorageDir() {
|
|
22
|
-
try {
|
|
23
|
-
await fs_1.promises.mkdir(this.storageDir, { recursive: true });
|
|
24
|
-
}
|
|
25
|
-
catch (error) {
|
|
26
|
-
console.error('创建MFA存储目录失败:', error);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* 获取会话文件路径
|
|
31
|
-
*/
|
|
32
|
-
getSessionFilePath(sessionId) {
|
|
33
|
-
return path_1.default.join(this.storageDir, `${sessionId}.json`);
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* 创建一个等待MFA验证码的Promise
|
|
37
|
-
* @param sessionId 会话ID
|
|
38
|
-
* @param timeout 超时时间(毫秒)
|
|
39
|
-
* @returns Promise<string> 返回验证码
|
|
40
|
-
*/
|
|
41
|
-
async waitForMFACode(sessionId, timeout = this.DEFAULT_TIMEOUT) {
|
|
42
|
-
// 确保存储目录存在
|
|
43
|
-
await this.ensureStorageDir();
|
|
44
|
-
// 清理可能存在的旧会话
|
|
45
|
-
await this.cleanupRequest(sessionId);
|
|
46
|
-
// 创建会话文件
|
|
47
|
-
const sessionData = {
|
|
48
|
-
sessionId,
|
|
49
|
-
status: 'waiting',
|
|
50
|
-
createdAt: new Date().toISOString(),
|
|
51
|
-
timeout: timeout
|
|
52
|
-
};
|
|
53
|
-
const sessionFilePath = this.getSessionFilePath(sessionId);
|
|
54
|
-
await fs_1.promises.writeFile(sessionFilePath, JSON.stringify(sessionData), 'utf8');
|
|
55
|
-
console.log(`MFA验证会话已创建: ${sessionId}`);
|
|
56
|
-
// 轮询检查验证码是否已提交
|
|
57
|
-
return new Promise((resolve, reject) => {
|
|
58
|
-
const startTime = Date.now();
|
|
59
|
-
const checkInterval = setInterval(async () => {
|
|
60
|
-
try {
|
|
61
|
-
// 检查是否超时
|
|
62
|
-
if (Date.now() - startTime > timeout) {
|
|
63
|
-
clearInterval(checkInterval);
|
|
64
|
-
await this.cleanupRequest(sessionId);
|
|
65
|
-
reject(new Error('MFA验证超时,请重新登录'));
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
// 检查会话文件是否存在
|
|
69
|
-
try {
|
|
70
|
-
const data = await fs_1.promises.readFile(sessionFilePath, 'utf8');
|
|
71
|
-
const session = JSON.parse(data);
|
|
72
|
-
// 如果状态已更新为resolved,则返回验证码
|
|
73
|
-
if (session.status === 'resolved' && session.code) {
|
|
74
|
-
clearInterval(checkInterval);
|
|
75
|
-
await this.cleanupRequest(sessionId);
|
|
76
|
-
resolve(session.code);
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
// 如果状态已更新为rejected,则抛出错误
|
|
80
|
-
if (session.status === 'rejected' && session.error) {
|
|
81
|
-
clearInterval(checkInterval);
|
|
82
|
-
await this.cleanupRequest(sessionId);
|
|
83
|
-
reject(new Error(session.error));
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
catch (error) {
|
|
88
|
-
// 文件不存在或其他错误,继续等待
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
catch (error) {
|
|
92
|
-
clearInterval(checkInterval);
|
|
93
|
-
await this.cleanupRequest(sessionId);
|
|
94
|
-
reject(error instanceof Error
|
|
95
|
-
? error
|
|
96
|
-
: new Error(String(error)));
|
|
97
|
-
}
|
|
98
|
-
}, 1000); // 每秒检查一次
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* 提交MFA验证码
|
|
103
|
-
* @param sessionId 会话ID
|
|
104
|
-
* @param code 验证码
|
|
105
|
-
* @returns 是否成功提交
|
|
106
|
-
*/
|
|
107
|
-
async submitMFACode(sessionId, code) {
|
|
108
|
-
const sessionFilePath = this.getSessionFilePath(sessionId);
|
|
109
|
-
try {
|
|
110
|
-
// 检查会话文件是否存在
|
|
111
|
-
const data = await fs_1.promises.readFile(sessionFilePath, 'utf8');
|
|
112
|
-
const session = JSON.parse(data);
|
|
113
|
-
if (session.status !== 'waiting') {
|
|
114
|
-
console.log(`MFA验证会话状态不正确: ${sessionId}, 状态: ${session.status}`);
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
// 更新会话状态为已解决
|
|
118
|
-
session.status = 'resolved';
|
|
119
|
-
session.code = code;
|
|
120
|
-
session.resolvedAt = new Date().toISOString();
|
|
121
|
-
await fs_1.promises.writeFile(sessionFilePath, JSON.stringify(session), 'utf8');
|
|
122
|
-
console.log(`MFA验证码已提交: code ${code}, sessionId ${sessionId}`);
|
|
123
|
-
return true;
|
|
124
|
-
}
|
|
125
|
-
catch (error) {
|
|
126
|
-
console.log(`未找到MFA验证会话: ${sessionId}, 错误: ${error instanceof Error ? error.message : String(error)}`);
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* 取消MFA验证
|
|
132
|
-
* @param sessionId 会话ID
|
|
133
|
-
* @param reason 取消原因
|
|
134
|
-
* @returns 是否成功取消
|
|
135
|
-
*/
|
|
136
|
-
async cancelMFARequest(sessionId, reason = 'MFA验证已取消') {
|
|
137
|
-
const sessionFilePath = this.getSessionFilePath(sessionId);
|
|
138
|
-
try {
|
|
139
|
-
// 检查会话文件是否存在
|
|
140
|
-
const data = await fs_1.promises.readFile(sessionFilePath, 'utf8');
|
|
141
|
-
const session = JSON.parse(data);
|
|
142
|
-
// 更新会话状态为已拒绝
|
|
143
|
-
session.status = 'rejected';
|
|
144
|
-
session.error = reason;
|
|
145
|
-
session.rejectedAt = new Date().toISOString();
|
|
146
|
-
await fs_1.promises.writeFile(sessionFilePath, JSON.stringify(session), 'utf8');
|
|
147
|
-
console.log(`MFA验证已取消: ${sessionId}, 原因: ${reason}`);
|
|
148
|
-
return true;
|
|
149
|
-
}
|
|
150
|
-
catch (error) {
|
|
151
|
-
console.log(`未找到MFA验证会话: ${sessionId}, 错误: ${error instanceof Error ? error.message : String(error)}`);
|
|
152
|
-
return false;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* 检查会话是否存在
|
|
157
|
-
* @param sessionId 会话ID
|
|
158
|
-
* @returns 是否存在
|
|
159
|
-
*/
|
|
160
|
-
async hasSession(sessionId) {
|
|
161
|
-
const sessionFilePath = this.getSessionFilePath(sessionId);
|
|
162
|
-
try {
|
|
163
|
-
await fs_1.promises.access(sessionFilePath);
|
|
164
|
-
return true;
|
|
165
|
-
}
|
|
166
|
-
catch (_a) {
|
|
167
|
-
return false;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* 获取所有活跃的会话ID
|
|
172
|
-
* @returns 会话ID列表
|
|
173
|
-
*/
|
|
174
|
-
async getActiveSessions() {
|
|
175
|
-
try {
|
|
176
|
-
await this.ensureStorageDir();
|
|
177
|
-
const files = await fs_1.promises.readdir(this.storageDir);
|
|
178
|
-
return files
|
|
179
|
-
.filter((file) => file.endsWith('.json'))
|
|
180
|
-
.map((file) => file.replace('.json', ''));
|
|
181
|
-
}
|
|
182
|
-
catch (error) {
|
|
183
|
-
console.error('获取活跃会话失败:', error instanceof Error ? error : String(error));
|
|
184
|
-
return [];
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
/**
|
|
188
|
-
* 清理过期的请求
|
|
189
|
-
* @param maxAge 最大存活时间(毫秒)
|
|
190
|
-
*/
|
|
191
|
-
async cleanupExpiredRequests(maxAge = this.DEFAULT_TIMEOUT) {
|
|
192
|
-
try {
|
|
193
|
-
await this.ensureStorageDir();
|
|
194
|
-
const files = await fs_1.promises.readdir(this.storageDir);
|
|
195
|
-
const now = new Date();
|
|
196
|
-
let cleanedCount = 0;
|
|
197
|
-
for (const file of files) {
|
|
198
|
-
if (!file.endsWith('.json'))
|
|
199
|
-
continue;
|
|
200
|
-
try {
|
|
201
|
-
const filePath = path_1.default.join(this.storageDir, file);
|
|
202
|
-
const data = await fs_1.promises.readFile(filePath, 'utf8');
|
|
203
|
-
const session = JSON.parse(data);
|
|
204
|
-
const createdAt = new Date(session.createdAt);
|
|
205
|
-
// 检查是否过期
|
|
206
|
-
if (now.getTime() - createdAt.getTime() > maxAge) {
|
|
207
|
-
await fs_1.promises.unlink(filePath);
|
|
208
|
-
cleanedCount++;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
catch (error) {
|
|
212
|
-
// 如果文件读取失败,直接删除
|
|
213
|
-
try {
|
|
214
|
-
await fs_1.promises.unlink(path_1.default.join(this.storageDir, file));
|
|
215
|
-
cleanedCount++;
|
|
216
|
-
}
|
|
217
|
-
catch (unlinkError) {
|
|
218
|
-
console.error(`删除过期会话文件失败: ${file}`, unlinkError instanceof Error
|
|
219
|
-
? unlinkError
|
|
220
|
-
: String(unlinkError));
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
if (cleanedCount > 0) {
|
|
225
|
-
console.log(`清理了 ${cleanedCount} 个过期的MFA验证会话`);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
catch (error) {
|
|
229
|
-
console.error('清理过期请求失败:', error instanceof Error ? error : String(error));
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
/**
|
|
233
|
-
* 清理指定会话的资源
|
|
234
|
-
* @param sessionId 会话ID
|
|
235
|
-
*/
|
|
236
|
-
async cleanupRequest(sessionId) {
|
|
237
|
-
const sessionFilePath = this.getSessionFilePath(sessionId);
|
|
238
|
-
try {
|
|
239
|
-
await fs_1.promises.unlink(sessionFilePath);
|
|
240
|
-
}
|
|
241
|
-
catch (error) {
|
|
242
|
-
// 文件不存在,忽略错误
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
exports.FileMFASessionStorage = FileMFASessionStorage;
|
|
247
|
-
//# sourceMappingURL=FileMFASessionStorage.js.map
|
|
1
|
+
'use strict';function a0_0x5e89(){const _0xbac298=['path','promises','readdir','stringify','replace','MFA验证会话状态不正确:\x20','cancelMFARequest','readFile','utf8',',\x20错误:\x20','1841502jIyQQU','1140671hfoRwN','waitForMFACode','status','6379210PKaiys','DEFAULT_TIMEOUT','删除过期会话文件失败:\x20','3826110MGIOYX','清理过期请求失败:','map','filter','__importDefault','log','9792888EleWGa','cleanupExpiredRequests','__esModule','parse','55exXMeN','access','4QzmtVb','code','default','getTime','error','2yHjpdI','cleanupRequest','获取活跃会话失败:','1906225afVcxp','ensureStorageDir','.json','now','清理了\x20','resolved','MFA验证已取消','join','rejected','endsWith','MFA验证超时,请重新登录','getSessionFilePath','storageDir','7ZOGBHG',',\x20状态:\x20','unlink','872jNUmLg','toISOString',',\x20原因:\x20','mkdir','未找到MFA验证会话:\x20',',\x20sessionId\x20','createdAt','77949okprIL','waiting'];a0_0x5e89=function(){return _0xbac298;};return a0_0x5e89();}const a0_0xa9afdc=a0_0x397f;(function(_0x520b13,_0x4abc41){const _0x2a4061=a0_0x397f,_0x533e05=_0x520b13();while(!![]){try{const _0x42b763=-parseInt(_0x2a4061(0x144))/0x1*(parseInt(_0x2a4061(0x15b))/0x2)+-parseInt(_0x2a4061(0x14a))/0x3+-parseInt(_0x2a4061(0x156))/0x4*(-parseInt(_0x2a4061(0x15e))/0x5)+parseInt(_0x2a4061(0x143))/0x6*(parseInt(_0x2a4061(0x16b))/0x7)+-parseInt(_0x2a4061(0x130))/0x8*(parseInt(_0x2a4061(0x137))/0x9)+-parseInt(_0x2a4061(0x147))/0xa+-parseInt(_0x2a4061(0x154))/0xb*(-parseInt(_0x2a4061(0x150))/0xc);if(_0x42b763===_0x4abc41)break;else _0x533e05['push'](_0x533e05['shift']());}catch(_0x570c27){_0x533e05['push'](_0x533e05['shift']());}}}(a0_0x5e89,0xbc1d9));var __importDefault=this&&this[a0_0xa9afdc(0x14e)]||function(_0x2fd6fc){const _0x16d7bb=a0_0xa9afdc;return _0x2fd6fc&&_0x2fd6fc[_0x16d7bb(0x152)]?_0x2fd6fc:{'default':_0x2fd6fc};};function a0_0x397f(_0x93940c,_0x50b5f4){_0x93940c=_0x93940c-0x130;const _0x5e8985=a0_0x5e89();let _0x397f08=_0x5e8985[_0x93940c];return _0x397f08;}Object['defineProperty'](exports,a0_0xa9afdc(0x152),{'value':!![]}),exports['FileMFASessionStorage']=void 0x0;const fs_1=require('fs'),path_1=__importDefault(require(a0_0xa9afdc(0x139)));class FileMFASessionStorage{constructor(_0x1448aa){const _0x4ebf1f=a0_0xa9afdc;this[_0x4ebf1f(0x148)]=0x5*0x3c*0x3e8,this[_0x4ebf1f(0x16a)]=_0x1448aa,this[_0x4ebf1f(0x15f)]();}async[a0_0xa9afdc(0x15f)](){const _0x46f106=a0_0xa9afdc;try{await fs_1[_0x46f106(0x13a)][_0x46f106(0x133)](this['storageDir'],{'recursive':!![]});}catch(_0x34eb43){console['error']('创建MFA存储目录失败:',_0x34eb43);}}[a0_0xa9afdc(0x169)](_0x37e127){const _0x208894=a0_0xa9afdc;return path_1[_0x208894(0x158)][_0x208894(0x165)](this[_0x208894(0x16a)],_0x37e127+_0x208894(0x160));}async[a0_0xa9afdc(0x145)](_0x1580f3,_0x32099d=this['DEFAULT_TIMEOUT']){const _0x228dd3=a0_0xa9afdc;await this[_0x228dd3(0x15f)](),await this[_0x228dd3(0x15c)](_0x1580f3);const _0x50edbe={'sessionId':_0x1580f3,'status':'waiting','createdAt':new Date()[_0x228dd3(0x131)](),'timeout':_0x32099d},_0x409312=this[_0x228dd3(0x169)](_0x1580f3);return await fs_1['promises']['writeFile'](_0x409312,JSON['stringify'](_0x50edbe),_0x228dd3(0x141)),console['log']('MFA验证会话已创建:\x20'+_0x1580f3),new Promise((_0x4999ac,_0x97c5)=>{const _0x1fda11=_0x228dd3,_0x29fac5=Date[_0x1fda11(0x161)](),_0x3288b6=setInterval(async()=>{const _0x87fef9=_0x1fda11;try{if(Date[_0x87fef9(0x161)]()-_0x29fac5>_0x32099d){clearInterval(_0x3288b6),await this[_0x87fef9(0x15c)](_0x1580f3),_0x97c5(new Error(_0x87fef9(0x168)));return;}try{const _0x94b352=await fs_1[_0x87fef9(0x13a)][_0x87fef9(0x140)](_0x409312,'utf8'),_0x383534=JSON[_0x87fef9(0x153)](_0x94b352);if(_0x383534['status']===_0x87fef9(0x163)&&_0x383534[_0x87fef9(0x157)]){clearInterval(_0x3288b6),await this[_0x87fef9(0x15c)](_0x1580f3),_0x4999ac(_0x383534['code']);return;}if(_0x383534['status']===_0x87fef9(0x166)&&_0x383534[_0x87fef9(0x15a)]){clearInterval(_0x3288b6),await this[_0x87fef9(0x15c)](_0x1580f3),_0x97c5(new Error(_0x383534['error']));return;}}catch(_0x263a40){}}catch(_0x3a3bd2){clearInterval(_0x3288b6),await this[_0x87fef9(0x15c)](_0x1580f3),_0x97c5(_0x3a3bd2 instanceof Error?_0x3a3bd2:new Error(String(_0x3a3bd2)));}},0x3e8);});}async['submitMFACode'](_0x3079ca,_0x41d94e){const _0x12fcfb=a0_0xa9afdc,_0x38a97d=this[_0x12fcfb(0x169)](_0x3079ca);try{const _0x183e68=await fs_1[_0x12fcfb(0x13a)]['readFile'](_0x38a97d,_0x12fcfb(0x141)),_0x5200b4=JSON[_0x12fcfb(0x153)](_0x183e68);if(_0x5200b4[_0x12fcfb(0x146)]!==_0x12fcfb(0x138))return console[_0x12fcfb(0x14f)](_0x12fcfb(0x13e)+_0x3079ca+_0x12fcfb(0x16c)+_0x5200b4[_0x12fcfb(0x146)]),![];return _0x5200b4['status']=_0x12fcfb(0x163),_0x5200b4[_0x12fcfb(0x157)]=_0x41d94e,_0x5200b4['resolvedAt']=new Date()[_0x12fcfb(0x131)](),await fs_1[_0x12fcfb(0x13a)]['writeFile'](_0x38a97d,JSON['stringify'](_0x5200b4),_0x12fcfb(0x141)),console[_0x12fcfb(0x14f)]('MFA验证码已提交:\x20code\x20'+_0x41d94e+_0x12fcfb(0x135)+_0x3079ca),!![];}catch(_0x46f0e8){return console[_0x12fcfb(0x14f)](_0x12fcfb(0x134)+_0x3079ca+_0x12fcfb(0x142)+(_0x46f0e8 instanceof Error?_0x46f0e8['message']:String(_0x46f0e8))),![];}}async[a0_0xa9afdc(0x13f)](_0x44818c,_0x133013=a0_0xa9afdc(0x164)){const _0xb7d2af=a0_0xa9afdc,_0xf1e5c1=this[_0xb7d2af(0x169)](_0x44818c);try{const _0x1d6085=await fs_1[_0xb7d2af(0x13a)][_0xb7d2af(0x140)](_0xf1e5c1,_0xb7d2af(0x141)),_0x3068aa=JSON[_0xb7d2af(0x153)](_0x1d6085);return _0x3068aa[_0xb7d2af(0x146)]='rejected',_0x3068aa[_0xb7d2af(0x15a)]=_0x133013,_0x3068aa['rejectedAt']=new Date()[_0xb7d2af(0x131)](),await fs_1[_0xb7d2af(0x13a)]['writeFile'](_0xf1e5c1,JSON[_0xb7d2af(0x13c)](_0x3068aa),'utf8'),console['log']('MFA验证已取消:\x20'+_0x44818c+_0xb7d2af(0x132)+_0x133013),!![];}catch(_0x29e000){return console[_0xb7d2af(0x14f)](_0xb7d2af(0x134)+_0x44818c+_0xb7d2af(0x142)+(_0x29e000 instanceof Error?_0x29e000['message']:String(_0x29e000))),![];}}async['hasSession'](_0xc72784){const _0x4d220f=a0_0xa9afdc,_0x7f750d=this[_0x4d220f(0x169)](_0xc72784);try{return await fs_1[_0x4d220f(0x13a)][_0x4d220f(0x155)](_0x7f750d),!![];}catch(_0x44b032){return![];}}async['getActiveSessions'](){const _0x56e989=a0_0xa9afdc;try{await this[_0x56e989(0x15f)]();const _0x4e176a=await fs_1[_0x56e989(0x13a)][_0x56e989(0x13b)](this['storageDir']);return _0x4e176a[_0x56e989(0x14d)](_0x29105d=>_0x29105d[_0x56e989(0x167)]('.json'))[_0x56e989(0x14c)](_0x503abd=>_0x503abd[_0x56e989(0x13d)](_0x56e989(0x160),''));}catch(_0x86619){return console[_0x56e989(0x15a)](_0x56e989(0x15d),_0x86619 instanceof Error?_0x86619:String(_0x86619)),[];}}async[a0_0xa9afdc(0x151)](_0x2c99b0=this[a0_0xa9afdc(0x148)]){const _0x2c4577=a0_0xa9afdc;try{await this[_0x2c4577(0x15f)]();const _0x309be0=await fs_1['promises'][_0x2c4577(0x13b)](this[_0x2c4577(0x16a)]),_0x530621=new Date();let _0x3fdb94=0x0;for(const _0x3ad317 of _0x309be0){if(!_0x3ad317[_0x2c4577(0x167)](_0x2c4577(0x160)))continue;try{const _0x49e896=path_1[_0x2c4577(0x158)][_0x2c4577(0x165)](this['storageDir'],_0x3ad317),_0xe58f68=await fs_1[_0x2c4577(0x13a)][_0x2c4577(0x140)](_0x49e896,'utf8'),_0x537ec5=JSON[_0x2c4577(0x153)](_0xe58f68),_0x436cac=new Date(_0x537ec5[_0x2c4577(0x136)]);_0x530621[_0x2c4577(0x159)]()-_0x436cac['getTime']()>_0x2c99b0&&(await fs_1[_0x2c4577(0x13a)][_0x2c4577(0x16d)](_0x49e896),_0x3fdb94++);}catch(_0x5b295a){try{await fs_1['promises'][_0x2c4577(0x16d)](path_1[_0x2c4577(0x158)]['join'](this['storageDir'],_0x3ad317)),_0x3fdb94++;}catch(_0x575c31){console[_0x2c4577(0x15a)](_0x2c4577(0x149)+_0x3ad317,_0x575c31 instanceof Error?_0x575c31:String(_0x575c31));}}}_0x3fdb94>0x0&&console[_0x2c4577(0x14f)](_0x2c4577(0x162)+_0x3fdb94+'\x20个过期的MFA验证会话');}catch(_0x4805d8){console['error'](_0x2c4577(0x14b),_0x4805d8 instanceof Error?_0x4805d8:String(_0x4805d8));}}async['cleanupRequest'](_0x541d3f){const _0x24bae9=a0_0xa9afdc,_0x3a0f34=this['getSessionFilePath'](_0x541d3f);try{await fs_1[_0x24bae9(0x13a)][_0x24bae9(0x16d)](_0x3a0f34);}catch(_0x19ce4d){}}}exports['FileMFASessionStorage']=FileMFASessionStorage;
|
|
@@ -1,361 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.HttpClient = void 0;
|
|
7
|
-
const axios_1 = __importDefault(require("axios"));
|
|
8
|
-
const form_data_1 = __importDefault(require("form-data"));
|
|
9
|
-
const lodash_1 = __importDefault(require("lodash"));
|
|
10
|
-
const luxon_1 = require("luxon");
|
|
11
|
-
const oauth_1_0a_1 = __importDefault(require("oauth-1.0a"));
|
|
12
|
-
const qs_1 = __importDefault(require("qs"));
|
|
13
|
-
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
14
|
-
const CSRF_RE = new RegExp('name="_csrf"\\s+value="(.+?)"');
|
|
15
|
-
const TICKET_RE = new RegExp('ticket=([^"]+)"');
|
|
16
|
-
const ACCOUNT_LOCKED_RE = new RegExp('var statuss*=s*"([^"]*)"');
|
|
17
|
-
const PAGE_TITLE_RE = new RegExp('<title>([^<]*)</title>');
|
|
18
|
-
const USER_AGENT_CONNECTMOBILE = 'com.garmin.android.apps.connectmobile';
|
|
19
|
-
const USER_AGENT_BROWSER = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36';
|
|
20
|
-
const USER_AGENT_BROWSER_MAC = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36';
|
|
21
|
-
const OAUTH_CONSUMER_URL = 'https://thegarth.s3.amazonaws.com/oauth_consumer.json';
|
|
22
|
-
const HTTP_STATUS = {
|
|
23
|
-
UNAUTHORIZED: 401
|
|
24
|
-
};
|
|
25
|
-
let tokenRefreshPromise = null;
|
|
26
|
-
let refreshSubscribers = [];
|
|
27
|
-
class HttpClient {
|
|
28
|
-
constructor(url, config) {
|
|
29
|
-
var _a, _b;
|
|
30
|
-
this.url = url;
|
|
31
|
-
this.client = axios_1.default.create({
|
|
32
|
-
timeout: (_a = config === null || config === void 0 ? void 0 : config.timeout) !== null && _a !== void 0 ? _a : 5000,
|
|
33
|
-
timeoutErrorMessage: `Request Timeout: > ${(_b = config === null || config === void 0 ? void 0 : config.timeout) !== null && _b !== void 0 ? _b : 5000} ms`
|
|
34
|
-
/**
|
|
35
|
-
* Charles debugger: uncomment `proxy` and `httpsAgent`, then run bellow command.
|
|
36
|
-
* NODE_TLS_REJECT_UNAUTHORIZED=0 node test/sync.js
|
|
37
|
-
*/
|
|
38
|
-
// proxy: {
|
|
39
|
-
// host: '127.0.0.1',
|
|
40
|
-
// port: 8888,
|
|
41
|
-
// protocol: 'http'
|
|
42
|
-
// },
|
|
43
|
-
// httpsAgent: new (require('https').Agent)({
|
|
44
|
-
// rejectUnauthorized: false
|
|
45
|
-
// })
|
|
46
|
-
});
|
|
47
|
-
this.config = config;
|
|
48
|
-
this.client.interceptors.response.use((response) => response, async (error) => {
|
|
49
|
-
var _a;
|
|
50
|
-
if (axios_1.default.isAxiosError(error) &&
|
|
51
|
-
error.code === 'ECONNABORTED') {
|
|
52
|
-
throw new Error(error.message || 'Request Timeout');
|
|
53
|
-
}
|
|
54
|
-
const originalRequest = error.config;
|
|
55
|
-
if (((_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.status) === HTTP_STATUS.UNAUTHORIZED &&
|
|
56
|
-
!(originalRequest === null || originalRequest === void 0 ? void 0 : originalRequest._retry)) {
|
|
57
|
-
if (!this.oauth2Token) {
|
|
58
|
-
throw new Error('No OAuth2 token available');
|
|
59
|
-
}
|
|
60
|
-
originalRequest._retry = true;
|
|
61
|
-
try {
|
|
62
|
-
if (!tokenRefreshPromise) {
|
|
63
|
-
tokenRefreshPromise =
|
|
64
|
-
this.refreshOauth2Token().finally(() => {
|
|
65
|
-
tokenRefreshPromise = null;
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
await tokenRefreshPromise;
|
|
69
|
-
originalRequest.headers.Authorization = `Bearer ${this.oauth2Token.access_token}`;
|
|
70
|
-
return this.client(originalRequest);
|
|
71
|
-
}
|
|
72
|
-
catch (err) {
|
|
73
|
-
console.error('Token refresh failed:', err);
|
|
74
|
-
throw err;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
if (axios_1.default.isAxiosError(error) && error.response) {
|
|
78
|
-
this.handleError(error.response);
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
// 处理没有response的情况
|
|
82
|
-
throw new Error('Network error or unknown error occurred');
|
|
83
|
-
}
|
|
84
|
-
throw error;
|
|
85
|
-
});
|
|
86
|
-
this.client.interceptors.request.use(async (config) => {
|
|
87
|
-
if (this.oauth2Token) {
|
|
88
|
-
config.headers.Authorization =
|
|
89
|
-
'Bearer ' + this.oauth2Token.access_token;
|
|
90
|
-
}
|
|
91
|
-
return config;
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
async fetchOauthConsumer() {
|
|
95
|
-
const response = await axios_1.default.get(OAUTH_CONSUMER_URL);
|
|
96
|
-
this.OAUTH_CONSUMER = {
|
|
97
|
-
key: response.data.consumer_key,
|
|
98
|
-
secret: response.data.consumer_secret
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
async checkTokenVaild() {
|
|
102
|
-
if (this.oauth2Token) {
|
|
103
|
-
if (this.oauth2Token.expires_at < luxon_1.DateTime.now().toSeconds()) {
|
|
104
|
-
console.error('Token expired!');
|
|
105
|
-
await this.refreshOauth2Token();
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
async get(url, config) {
|
|
110
|
-
const response = await this.client.get(url, config);
|
|
111
|
-
return response === null || response === void 0 ? void 0 : response.data;
|
|
112
|
-
}
|
|
113
|
-
async post(url, data, config) {
|
|
114
|
-
const response = await this.client.post(url, data, config);
|
|
115
|
-
return response === null || response === void 0 ? void 0 : response.data;
|
|
116
|
-
}
|
|
117
|
-
async put(url, data, config) {
|
|
118
|
-
const response = await this.client.put(url, data, config);
|
|
119
|
-
return response === null || response === void 0 ? void 0 : response.data;
|
|
120
|
-
}
|
|
121
|
-
async delete(url, config) {
|
|
122
|
-
const response = await this.client.post(url, null, {
|
|
123
|
-
...config,
|
|
124
|
-
headers: {
|
|
125
|
-
...config === null || config === void 0 ? void 0 : config.headers,
|
|
126
|
-
'X-Http-Method-Override': 'DELETE'
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
return response === null || response === void 0 ? void 0 : response.data;
|
|
130
|
-
}
|
|
131
|
-
setCommonHeader(headers) {
|
|
132
|
-
lodash_1.default.each(headers, (headerValue, key) => {
|
|
133
|
-
this.client.defaults.headers.common[key] = headerValue;
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
handleError(response) {
|
|
137
|
-
this.handleHttpError(response);
|
|
138
|
-
}
|
|
139
|
-
handleHttpError(response) {
|
|
140
|
-
const { status, statusText, data } = response;
|
|
141
|
-
const errorMessage = {
|
|
142
|
-
status,
|
|
143
|
-
statusText,
|
|
144
|
-
data: typeof data === 'object' ? JSON.stringify(data) : data
|
|
145
|
-
};
|
|
146
|
-
console.error('HTTP Error:', errorMessage);
|
|
147
|
-
throw new Error(`HTTP Error (${status}): ${statusText}`);
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Login to Garmin Connect
|
|
151
|
-
* @param username
|
|
152
|
-
* @param password
|
|
153
|
-
* @returns {Promise<HttpClient>}
|
|
154
|
-
*/
|
|
155
|
-
async login(username, password, mfaCallback) {
|
|
156
|
-
await this.fetchOauthConsumer();
|
|
157
|
-
// Step1-3: Get ticket from page.
|
|
158
|
-
const ticket = await this.getLoginTicket(username, password);
|
|
159
|
-
// Step4: Oauth1
|
|
160
|
-
const oauth1 = await this.getOauth1Token(ticket);
|
|
161
|
-
// TODO: Handle MFA
|
|
162
|
-
// Step 5: Oauth2
|
|
163
|
-
await this.exchange(oauth1);
|
|
164
|
-
return this;
|
|
165
|
-
}
|
|
166
|
-
async getLoginTicket(username, password) {
|
|
167
|
-
// Step1: Set cookie
|
|
168
|
-
const step1Params = {
|
|
169
|
-
clientId: 'GarminConnect',
|
|
170
|
-
locale: 'en',
|
|
171
|
-
service: this.url.GC_MODERN
|
|
172
|
-
};
|
|
173
|
-
const step1Url = `${this.url.GARMIN_SSO_EMBED}?${qs_1.default.stringify(step1Params)}`;
|
|
174
|
-
// console.log('login - step1Url:', step1Url);
|
|
175
|
-
await this.client.get(step1Url);
|
|
176
|
-
// Step2 Get _csrf
|
|
177
|
-
const step2Params = {
|
|
178
|
-
id: 'gauth-widget',
|
|
179
|
-
embedWidget: true,
|
|
180
|
-
locale: 'en',
|
|
181
|
-
gauthHost: this.url.GARMIN_SSO_EMBED
|
|
182
|
-
};
|
|
183
|
-
const step2Url = `${this.url.SIGNIN_URL}?${qs_1.default.stringify(step2Params)}`;
|
|
184
|
-
// console.log('login - step2Url:', step2Url);
|
|
185
|
-
const step2Result = await this.get(step2Url);
|
|
186
|
-
// console.log('login - step2Result:', step2Result)
|
|
187
|
-
const csrfRegResult = CSRF_RE.exec(step2Result);
|
|
188
|
-
if (!csrfRegResult) {
|
|
189
|
-
throw new Error('login - csrf not found');
|
|
190
|
-
}
|
|
191
|
-
const csrf_token = csrfRegResult[1];
|
|
192
|
-
// console.log('login - csrf:', csrf_token);
|
|
193
|
-
// Step3 Get ticket
|
|
194
|
-
const signinParams = {
|
|
195
|
-
id: 'gauth-widget',
|
|
196
|
-
embedWidget: true,
|
|
197
|
-
clientId: 'GarminConnect',
|
|
198
|
-
locale: 'en',
|
|
199
|
-
gauthHost: this.url.GARMIN_SSO_EMBED,
|
|
200
|
-
service: this.url.GARMIN_SSO_EMBED,
|
|
201
|
-
source: this.url.GARMIN_SSO_EMBED,
|
|
202
|
-
redirectAfterAccountLoginUrl: this.url.GARMIN_SSO_EMBED,
|
|
203
|
-
redirectAfterAccountCreationUrl: this.url.GARMIN_SSO_EMBED
|
|
204
|
-
};
|
|
205
|
-
const step3Url = `${this.url.SIGNIN_URL}?${qs_1.default.stringify(signinParams)}`;
|
|
206
|
-
// console.log('login - step3Url:', step3Url);
|
|
207
|
-
const step3Form = new form_data_1.default();
|
|
208
|
-
step3Form.append('username', username);
|
|
209
|
-
step3Form.append('password', password);
|
|
210
|
-
step3Form.append('embed', 'true');
|
|
211
|
-
step3Form.append('_csrf', csrf_token);
|
|
212
|
-
const step3Result = await this.post(step3Url, step3Form, {
|
|
213
|
-
headers: {
|
|
214
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
215
|
-
Dnt: 1,
|
|
216
|
-
Origin: this.url.GARMIN_SSO_ORIGIN,
|
|
217
|
-
Referer: this.url.SIGNIN_URL,
|
|
218
|
-
'User-Agent': USER_AGENT_BROWSER
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
|
-
console.log('step3Result:', step3Result);
|
|
222
|
-
this.handleAccountLocked(step3Result);
|
|
223
|
-
this.handlePageTitle(step3Result);
|
|
224
|
-
this.handleMFA(step3Result);
|
|
225
|
-
const ticketRegResult = TICKET_RE.exec(step3Result);
|
|
226
|
-
if (!ticketRegResult) {
|
|
227
|
-
throw new Error('login failed (Ticket not found or MFA), please check username and password');
|
|
228
|
-
}
|
|
229
|
-
const ticket = ticketRegResult[1];
|
|
230
|
-
return ticket;
|
|
231
|
-
}
|
|
232
|
-
// TODO: Handle MFA
|
|
233
|
-
handleMFA(htmlStr) { }
|
|
234
|
-
// TODO: Handle Phone number
|
|
235
|
-
handlePageTitle(htmlStr) {
|
|
236
|
-
const pageTitileRegResult = PAGE_TITLE_RE.exec(htmlStr);
|
|
237
|
-
if (pageTitileRegResult) {
|
|
238
|
-
const title = pageTitileRegResult[1];
|
|
239
|
-
console.log('login page title:', title);
|
|
240
|
-
if (lodash_1.default.includes(title, 'Update Phone Number')) {
|
|
241
|
-
// current I don't know where to update it
|
|
242
|
-
// See: https://github.com/matin/garth/issues/19
|
|
243
|
-
throw new Error('login failed (Update Phone number), please update your phone number, See: https://github.com/matin/garth/issues/19');
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
handleAccountLocked(htmlStr) {
|
|
248
|
-
const accountLockedRegResult = ACCOUNT_LOCKED_RE.exec(htmlStr);
|
|
249
|
-
if (accountLockedRegResult) {
|
|
250
|
-
const msg = accountLockedRegResult[1];
|
|
251
|
-
console.error(msg);
|
|
252
|
-
throw new Error('login failed (AccountLocked), please open connect web page to unlock your account');
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
async refreshOauth2Token() {
|
|
256
|
-
try {
|
|
257
|
-
if (!this.OAUTH_CONSUMER) {
|
|
258
|
-
await this.fetchOauthConsumer();
|
|
259
|
-
}
|
|
260
|
-
if (!this.oauth2Token || !this.oauth1Token) {
|
|
261
|
-
throw new Error('Missing required tokens for refresh');
|
|
262
|
-
}
|
|
263
|
-
const oauth1 = {
|
|
264
|
-
oauth: this.getOauthClient(this.OAUTH_CONSUMER),
|
|
265
|
-
token: this.oauth1Token
|
|
266
|
-
};
|
|
267
|
-
await this.exchange(oauth1);
|
|
268
|
-
console.log(`「${this.config.username}」in「${this.url.domain}」 OAuth2 token refreshed successfully`);
|
|
269
|
-
}
|
|
270
|
-
catch (error) {
|
|
271
|
-
console.error('Failed to refresh OAuth2 token:', error);
|
|
272
|
-
throw error;
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
async getOauth1Token(ticket) {
|
|
276
|
-
if (!this.OAUTH_CONSUMER) {
|
|
277
|
-
throw new Error('No OAUTH_CONSUMER');
|
|
278
|
-
}
|
|
279
|
-
const params = {
|
|
280
|
-
ticket,
|
|
281
|
-
'login-url': this.url.GARMIN_SSO_EMBED,
|
|
282
|
-
'accepts-mfa-tokens': true
|
|
283
|
-
};
|
|
284
|
-
const url = `${this.url.OAUTH_URL}/preauthorized?${qs_1.default.stringify(params)}`;
|
|
285
|
-
const oauth = this.getOauthClient(this.OAUTH_CONSUMER);
|
|
286
|
-
const step4RequestData = {
|
|
287
|
-
url: url,
|
|
288
|
-
method: 'GET'
|
|
289
|
-
};
|
|
290
|
-
const headers = oauth.toHeader(oauth.authorize(step4RequestData));
|
|
291
|
-
// console.log('getOauth1Token - headers:', headers);
|
|
292
|
-
const response = await this.get(url, {
|
|
293
|
-
headers: {
|
|
294
|
-
...headers,
|
|
295
|
-
'User-Agent': USER_AGENT_CONNECTMOBILE
|
|
296
|
-
}
|
|
297
|
-
});
|
|
298
|
-
// console.log('getOauth1Token - response:', response);
|
|
299
|
-
const token = qs_1.default.parse(response);
|
|
300
|
-
// console.log('getOauth1Token - token:', token);
|
|
301
|
-
this.oauth1Token = token;
|
|
302
|
-
return { token, oauth };
|
|
303
|
-
}
|
|
304
|
-
getOauthClient(consumer) {
|
|
305
|
-
const oauth = new oauth_1_0a_1.default({
|
|
306
|
-
consumer: consumer,
|
|
307
|
-
signature_method: 'HMAC-SHA1',
|
|
308
|
-
hash_function(base_string, key) {
|
|
309
|
-
return node_crypto_1.default
|
|
310
|
-
.createHmac('sha1', key)
|
|
311
|
-
.update(base_string)
|
|
312
|
-
.digest('base64');
|
|
313
|
-
}
|
|
314
|
-
});
|
|
315
|
-
return oauth;
|
|
316
|
-
}
|
|
317
|
-
//
|
|
318
|
-
async exchange(oauth1) {
|
|
319
|
-
const token = {
|
|
320
|
-
key: oauth1.token.oauth_token,
|
|
321
|
-
secret: oauth1.token.oauth_token_secret
|
|
322
|
-
};
|
|
323
|
-
// console.log('exchange - token:', token);
|
|
324
|
-
const baseUrl = `${this.url.OAUTH_URL}/exchange/user/2.0`;
|
|
325
|
-
const requestData = {
|
|
326
|
-
url: baseUrl,
|
|
327
|
-
method: 'POST',
|
|
328
|
-
data: null
|
|
329
|
-
};
|
|
330
|
-
const step5AuthData = oauth1.oauth.authorize(requestData, token);
|
|
331
|
-
// console.log('login - step5AuthData:', step5AuthData);
|
|
332
|
-
const url = `${baseUrl}?${qs_1.default.stringify(step5AuthData)}`;
|
|
333
|
-
// console.log('exchange - url:', url);
|
|
334
|
-
this.oauth2Token = undefined;
|
|
335
|
-
const response = await this.post(url, null, {
|
|
336
|
-
headers: {
|
|
337
|
-
'User-Agent': USER_AGENT_CONNECTMOBILE,
|
|
338
|
-
'Content-Type': 'application/x-www-form-urlencoded'
|
|
339
|
-
}
|
|
340
|
-
});
|
|
341
|
-
// console.log('exchange - response:', response);
|
|
342
|
-
this.oauth2Token = this.setOauth2TokenExpiresAt(response);
|
|
343
|
-
// console.log('exchange - oauth2Token:', this.oauth2Token);
|
|
344
|
-
}
|
|
345
|
-
setOauth2TokenExpiresAt(token) {
|
|
346
|
-
const now = luxon_1.DateTime.now();
|
|
347
|
-
const expiresAt = now.plus({ seconds: token.expires_in });
|
|
348
|
-
const refreshTokenExpiresAt = now.plus({
|
|
349
|
-
seconds: token.refresh_token_expires_in
|
|
350
|
-
});
|
|
351
|
-
return {
|
|
352
|
-
...token,
|
|
353
|
-
last_update_date: now.toLocal().toString(),
|
|
354
|
-
expires_date: expiresAt.toLocal().toString(),
|
|
355
|
-
expires_at: expiresAt.toSeconds(),
|
|
356
|
-
refresh_token_expires_at: refreshTokenExpiresAt.toSeconds()
|
|
357
|
-
};
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
exports.HttpClient = HttpClient;
|
|
361
|
-
//# sourceMappingURL=HttpClient%20copy.js.map
|
|
1
|
+
'use strict';const a1_0x59d6ab=a1_0x6651;(function(_0x794094,_0x1f2a88){const _0x3d2c3d=a1_0x6651,_0x5d59ce=_0x794094();while(!![]){try{const _0x1aa221=parseInt(_0x3d2c3d(0x147))/0x1*(-parseInt(_0x3d2c3d(0x11e))/0x2)+parseInt(_0x3d2c3d(0x15d))/0x3+parseInt(_0x3d2c3d(0x118))/0x4*(-parseInt(_0x3d2c3d(0x114))/0x5)+-parseInt(_0x3d2c3d(0x107))/0x6+-parseInt(_0x3d2c3d(0x14f))/0x7*(-parseInt(_0x3d2c3d(0x140))/0x8)+-parseInt(_0x3d2c3d(0xf1))/0x9+-parseInt(_0x3d2c3d(0x163))/0xa*(-parseInt(_0x3d2c3d(0x150))/0xb);if(_0x1aa221===_0x1f2a88)break;else _0x5d59ce['push'](_0x5d59ce['shift']());}catch(_0x3e9439){_0x5d59ce['push'](_0x5d59ce['shift']());}}}(a1_0x1ac8,0xb0146));function a1_0x1ac8(){const _0x3486b5=['object','554091MUlXYh','oauth-1.0a','_csrf','No\x20OAUTH_CONSUMER','stringify','parse','GET','__importDefault','refreshOauth2Token','ticket=([^\x22]+)\x22','shift','consumer_key','UNAUTHORIZED','oauth_token_secret','HttpClient','toHeader','password','put','gauth-widget','GARMIN_SSO_EMBED','OAUTH_CONSUMER','request','response','node:crypto','config','get','DateTime','application/x-www-form-urlencoded','lodash','4856680hCtNoe','isAxiosError','104QVmwZw','createHmac','interceptors','oauth1Token','headers','No\x20OAuth2\x20token\x20available','/exchange/user/2.0','82RmrHHk','2681vFNlod','HTTP\x20Error\x20(','login\x20page\x20title:','GC_MODERN','/preauthorized?','9564XYsdhb','1283967mzTEjS','713769tBezOI','143QOGbRx','Token\x20refresh\x20failed:','url','finally','base64','login\x20failed\x20(Update\x20Phone\x20number),\x20please\x20update\x20your\x20phone\x20number,\x20See:\x20\x20https://github.com/matin/garth/issues/19','axios','Request\x20Timeout','3481709bTrOcA','HMAC-SHA1','consumer_secret','code','delete','2315166VxgDOR','handleError','defineProperty','fetchOauthConsumer','plus','Bearer\x20','883130vlKwTa','SIGNIN_URL','exchange','Request\x20Timeout:\x20>\x20','now','」\x20OAuth2\x20token\x20refreshed\x20successfully','step3Result:','login\x20-\x20csrf\x20not\x20found','handleHttpError','setCommonHeader','default','data','_retry','Authorization','Mozilla/5.0\x20(Windows\x20NT\x2010.0;\x20Win64;\x20x64)\x20AppleWebKit/537.36\x20(KHTML,\x20like\x20Gecko)\x20Chrome/117.0.0.0\x20Safari/537.36','ECONNABORTED','handleAccountLocked','getOauthClient','OAUTH_URL','append','2530170JfnQnb','https://thegarth.s3.amazonaws.com/oauth_consumer.json','HTTP\x20Error:','expires_at','exec','create','358SzUzcZ','」in「','true','push','access_token','name=\x22_csrf\x22\x5cs+value=\x22(.+?)\x22','each','oauth2Token','Update\x20Phone\x20Number','update','Missing\x20required\x20tokens\x20for\x20refresh','timeout','toSeconds','defaults','embed','log','2126994mkuace','token','login\x20failed\x20(Ticket\x20not\x20found\x20or\x20MFA),\x20please\x20check\x20username\x20and\x20password','Token\x20expired!','):\x20','username','__esModule','error','handlePageTitle','digest','login\x20failed\x20(AccountLocked),\x20please\x20open\x20connect\x20web\x20page\x20to\x20unlock\x20your\x20account','oauth','24QncQiS','4975605VdJWVz','setOauth2TokenExpiresAt','getOauth1Token','Network\x20error\x20or\x20unknown\x20error\x20occurred','4kYrYiY','oauth_token','var\x20statuss*=s*\x22([^\x22]*)\x22','message','client','toString','21790jlUmCG','post'];a1_0x1ac8=function(){return _0x3486b5;};return a1_0x1ac8();}const a1_0x7c9029=a1_0x4ba0;function a1_0x4ba0(_0x22e370,_0xbb61ea){_0x22e370=_0x22e370-0x14e;const _0x103716=a1_0x3c1a();let _0x4c2066=_0x103716[_0x22e370];return _0x4c2066;}(function(_0x40ccd4,_0x5accad){const _0x202c17=a1_0x6651,_0x27741a=a1_0x4ba0,_0x561e8e=_0x40ccd4();while(!![]){try{const _0x6e8a60=parseInt(_0x27741a(0x1a4))/0x1+parseInt(_0x27741a(0x164))/0x2*(-parseInt(_0x27741a(0x1bc))/0x3)+-parseInt(_0x27741a(0x176))/0x4*(-parseInt(_0x27741a(0x1a7))/0x5)+-parseInt(_0x27741a(0x14e))/0x6*(parseInt(_0x27741a(0x1c0))/0x7)+-parseInt(_0x27741a(0x188))/0x8*(parseInt(_0x27741a(0x1a0))/0x9)+parseInt(_0x27741a(0x155))/0xa+parseInt(_0x27741a(0x1b0))/0xb;if(_0x6e8a60===_0x5accad)break;else _0x561e8e[_0x202c17(0xfa)](_0x561e8e[_0x202c17(0x12b)]());}catch(_0x7387fb){_0x561e8e[_0x202c17(0xfa)](_0x561e8e[_0x202c17(0x12b)]());}}}(a1_0x3c1a,0x5ea16));var __importDefault=this&&this[a1_0x7c9029(0x1ae)]||function(_0x4a30ee){const _0x16ce3c=a1_0x7c9029;return _0x4a30ee&&_0x4a30ee[_0x16ce3c(0x169)]?_0x4a30ee:{'default':_0x4a30ee};};Object[a1_0x59d6ab(0x15f)](exports,a1_0x7c9029(0x169),{'value':!![]}),exports[a1_0x7c9029(0x1ba)]=void 0x0;const axios_1=__importDefault(require(a1_0x59d6ab(0x156))),form_data_1=__importDefault(require(a1_0x7c9029(0x151))),lodash_1=__importDefault(require(a1_0x59d6ab(0x13d))),luxon_1=require(a1_0x7c9029(0x18a)),oauth_1_0a_1=__importDefault(require(a1_0x7c9029(0x18f))),qs_1=__importDefault(require('qs')),node_crypto_1=__importDefault(require(a1_0x59d6ab(0x138))),CSRF_RE=new RegExp(a1_0x7c9029(0x1ab)),TICKET_RE=new RegExp(a1_0x7c9029(0x159)),ACCOUNT_LOCKED_RE=new RegExp(a1_0x7c9029(0x16a)),PAGE_TITLE_RE=new RegExp('<title>([^<]*)</title>'),USER_AGENT_CONNECTMOBILE=a1_0x7c9029(0x198),USER_AGENT_BROWSER=a1_0x7c9029(0x185),USER_AGENT_BROWSER_MAC=a1_0x7c9029(0x158),OAUTH_CONSUMER_URL=a1_0x7c9029(0x153),HTTP_STATUS={'UNAUTHORIZED':0x191};function a1_0x3c1a(){const _0x2027a3=a1_0x59d6ab,_0x1ec2e2=[_0x2027a3(0x109),'5ffQeXv',_0x2027a3(0x143),_0x2027a3(0xee),_0x2027a3(0x11d),_0x2027a3(0xfc),_0x2027a3(0xff),'use',_0x2027a3(0x128),_0x2027a3(0x100),_0x2027a3(0x158),_0x2027a3(0x136),_0x2027a3(0x101),'common',_0x2027a3(0x13b),_0x2027a3(0x12d),_0x2027a3(0x135),_0x2027a3(0x144),_0x2027a3(0x164),_0x2027a3(0x102),_0x2027a3(0x12f),_0x2027a3(0x13f),'270YyGlgE',_0x2027a3(0x13a),_0x2027a3(0x111),_0x2027a3(0x167),_0x2027a3(0x148),_0x2027a3(0x153),_0x2027a3(0xfe),_0x2027a3(0x14d),_0x2027a3(0xec),'getLoginTicket','form-data','GarminConnect',_0x2027a3(0xf2),_0x2027a3(0x16a),_0x2027a3(0x13e),'domain',_0x2027a3(0x16e),'Mozilla/5.0\x20(Macintosh;\x20Intel\x20Mac\x20OS\x20X\x2010_15_7)\x20AppleWebKit/537.36\x20(KHTML,\x20like\x20Gecko)\x20Chrome/131.0.0.0\x20Safari/537.36',_0x2027a3(0x12a),_0x2027a3(0x103),_0x2027a3(0x11f),_0x2027a3(0xef),_0x2027a3(0x112),_0x2027a3(0x165),_0x2027a3(0x11b),_0x2027a3(0x166),_0x2027a3(0x160),_0x2027a3(0x141),'toLocal',_0x2027a3(0xf7),_0x2027a3(0x12e),_0x2027a3(0x116),_0x2027a3(0xf0),_0x2027a3(0x129),_0x2027a3(0x10d),_0x2027a3(0x11a),'\x20ms',_0x2027a3(0x105),_0x2027a3(0x14b),_0x2027a3(0x15a),_0x2027a3(0x131),_0x2027a3(0x108),'setOauth2TokenExpiresAt',_0x2027a3(0xf3),_0x2027a3(0x125),_0x2027a3(0xf8),_0x2027a3(0x15b),'343716ktyAhv',_0x2027a3(0x149),_0x2027a3(0x16f),'plus',_0x2027a3(0x132),_0x2027a3(0x110),'Failed\x20to\x20refresh\x20OAuth2\x20token:',_0x2027a3(0x169),_0x2027a3(0x10e),_0x2027a3(0x15e),_0x2027a3(0xed),_0x2027a3(0xfb),_0x2027a3(0x127),_0x2027a3(0x142),_0x2027a3(0x168),_0x2027a3(0xeb),'response',_0x2027a3(0xf5),_0x2027a3(0x113),_0x2027a3(0x152),'luxon','handleMFA','refresh_token_expires_in',_0x2027a3(0x134),'status',_0x2027a3(0x122),_0x2027a3(0x130),_0x2027a3(0x10f),_0x2027a3(0x11c),_0x2027a3(0x104),_0x2027a3(0x106),_0x2027a3(0x162),'authorize',_0x2027a3(0x14a),'com.garmin.android.apps.connectmobile',_0x2027a3(0x12c),_0x2027a3(0x16d),_0x2027a3(0x139),_0x2027a3(0x126),_0x2027a3(0x13c),_0x2027a3(0xf9),_0x2027a3(0x123),_0x2027a3(0x14e),_0x2027a3(0x133),'handleHttpError','expires_in',_0x2027a3(0x121),'checkTokenVaild'];return a1_0x3c1a=function(){return _0x1ec2e2;},a1_0x3c1a();}let tokenRefreshPromise=null,refreshSubscribers=[];function a1_0x6651(_0x938c90,_0x1ee7d1){_0x938c90=_0x938c90-0xeb;const _0x1ac89f=a1_0x1ac8();let _0x6651db=_0x1ac89f[_0x938c90];return _0x6651db;}class HttpClient{constructor(_0x20f461,_0x15c933){const _0x94be36=a1_0x59d6ab,_0x344352=a1_0x7c9029;var _0x2b7cc4,_0x471e1f;this[_0x344352(0x189)]=_0x20f461,this[_0x344352(0x192)]=axios_1[_0x344352(0x19a)][_0x94be36(0xf6)]({'timeout':(_0x2b7cc4=_0x15c933===null||_0x15c933===void 0x0?void 0x0:_0x15c933[_0x344352(0x1b9)])!==null&&_0x2b7cc4!==void 0x0?_0x2b7cc4:0x1388,'timeoutErrorMessage':_0x344352(0x160)+((_0x471e1f=_0x15c933===null||_0x15c933===void 0x0?void 0x0:_0x15c933[_0x344352(0x1b9)])!==null&&_0x471e1f!==void 0x0?_0x471e1f:0x1388)+_0x344352(0x16b)}),this[_0x94be36(0x139)]=_0x15c933,this[_0x344352(0x192)][_0x344352(0x183)][_0x344352(0x186)][_0x344352(0x1ad)](_0x338d6b=>_0x338d6b,async _0x3de6d4=>{const _0xfb5bce=_0x94be36,_0x2c15c3=_0x344352;var _0x17fef4;if(axios_1[_0x2c15c3(0x19a)][_0x2c15c3(0x1bb)](_0x3de6d4)&&_0x3de6d4[_0x2c15c3(0x175)]===_0x2c15c3(0x14f))throw new Error(_0x3de6d4[_0x2c15c3(0x15f)]||_0xfb5bce(0x157));const _0x1a169f=_0x3de6d4[_0x2c15c3(0x19b)];if(((_0x17fef4=_0x3de6d4===null||_0x3de6d4===void 0x0?void 0x0:_0x3de6d4[_0xfb5bce(0x137)])===null||_0x17fef4===void 0x0?void 0x0:_0x17fef4[_0x2c15c3(0x18e)])===HTTP_STATUS[_0x2c15c3(0x1b5)]&&!(_0x1a169f===null||_0x1a169f===void 0x0?void 0x0:_0x1a169f[_0x2c15c3(0x178)])){if(!this[_0x2c15c3(0x1c2)])throw new Error(_0xfb5bce(0x145));_0x1a169f[_0x2c15c3(0x178)]=!![];try{return!tokenRefreshPromise&&(tokenRefreshPromise=this[_0xfb5bce(0x129)]()[_0x2c15c3(0x1c1)](()=>{tokenRefreshPromise=null;})),await tokenRefreshPromise,_0x1a169f[_0xfb5bce(0x144)][_0xfb5bce(0x170)]=_0x2c15c3(0x195)+this[_0x2c15c3(0x1c2)][_0x2c15c3(0x181)],this[_0x2c15c3(0x192)](_0x1a169f);}catch(_0xa59e36){console[_0x2c15c3(0x17e)](_0xfb5bce(0x151),_0xa59e36);throw _0xa59e36;}}if(axios_1[_0x2c15c3(0x19a)][_0xfb5bce(0x13f)](_0x3de6d4)&&_0x3de6d4[_0x2c15c3(0x186)])this[_0x2c15c3(0x17f)](_0x3de6d4['response']);else throw new Error(_0xfb5bce(0x117));throw _0x3de6d4;}),this[_0x344352(0x192)][_0x344352(0x183)][_0x344352(0x1b1)][_0x344352(0x1ad)](async _0x46e65b=>{const _0x45cd5c=_0x94be36,_0x3566c4=_0x344352;return this[_0x3566c4(0x1c2)]&&(_0x46e65b[_0x45cd5c(0x144)][_0x45cd5c(0x170)]=_0x3566c4(0x195)+this[_0x3566c4(0x1c2)][_0x3566c4(0x181)]),_0x46e65b;});}async[a1_0x59d6ab(0x160)](){const _0x29aee5=a1_0x59d6ab,_0x168dc5=a1_0x7c9029,_0x547e9a=await axios_1[_0x29aee5(0x16d)][_0x168dc5(0x1bd)](OAUTH_CONSUMER_URL);this[_0x168dc5(0x1b6)]={'key':_0x547e9a[_0x168dc5(0x157)][_0x168dc5(0x199)],'secret':_0x547e9a[_0x168dc5(0x157)][_0x168dc5(0x16e)]};}async[a1_0x7c9029(0x1a5)](){const _0xf8b079=a1_0x59d6ab,_0x3ce7a1=a1_0x7c9029;this[_0x3ce7a1(0x1c2)]&&(this[_0x3ce7a1(0x1c2)][_0xf8b079(0xf4)]<luxon_1[_0xf8b079(0x13b)][_0xf8b079(0x167)]()[_0xf8b079(0x103)]()&&(console[_0x3ce7a1(0x17e)](_0xf8b079(0x10a)),await this[_0xf8b079(0x129)]()));}async['get'](_0x370c37,_0x282442){const _0x4e724f=a1_0x59d6ab,_0x4cfad0=a1_0x7c9029,_0x4a70bd=await this[_0x4cfad0(0x192)][_0x4e724f(0x13a)](_0x370c37,_0x282442);return _0x4a70bd===null||_0x4a70bd===void 0x0?void 0x0:_0x4a70bd[_0x4cfad0(0x157)];}async[a1_0x7c9029(0x15b)](_0x208281,_0x3dccf1,_0x4ed514){const _0x14fef3=a1_0x59d6ab,_0x339325=a1_0x7c9029,_0x1fb80d=await this[_0x14fef3(0x11c)][_0x339325(0x15b)](_0x208281,_0x3dccf1,_0x4ed514);return _0x1fb80d===null||_0x1fb80d===void 0x0?void 0x0:_0x1fb80d[_0x339325(0x157)];}async[a1_0x7c9029(0x17a)](_0xb44bdd,_0x171d92,_0xc26fc5){const _0x54731c=a1_0x7c9029,_0x288237=await this[_0x54731c(0x192)][_0x54731c(0x17a)](_0xb44bdd,_0x171d92,_0xc26fc5);return _0x288237===null||_0x288237===void 0x0?void 0x0:_0x288237[_0x54731c(0x157)];}async[a1_0x59d6ab(0x15c)](_0x41ae59,_0x1b51fe){const _0x464942=a1_0x59d6ab,_0x59f524=a1_0x7c9029,_0xe84c91=await this[_0x59f524(0x192)][_0x464942(0x11f)](_0x41ae59,null,{..._0x1b51fe,'headers':{..._0x1b51fe===null||_0x1b51fe===void 0x0?void 0x0:_0x1b51fe[_0x59f524(0x1b7)],'X-Http-Method-Override':'DELETE'}});return _0xe84c91===null||_0xe84c91===void 0x0?void 0x0:_0xe84c91[_0x59f524(0x157)];}[a1_0x59d6ab(0x16c)](_0xded69b){const _0x4808c9=a1_0x59d6ab,_0x18c077=a1_0x7c9029;lodash_1[_0x18c077(0x19a)][_0x4808c9(0xfd)](_0xded69b,(_0x2ede95,_0x3b663a)=>{const _0x2721e9=_0x4808c9,_0x4cfdbe=_0x18c077;this[_0x4cfdbe(0x192)][_0x4cfdbe(0x193)][_0x2721e9(0x144)][_0x4cfdbe(0x1b3)][_0x3b663a]=_0x2ede95;});}[a1_0x59d6ab(0x15e)](_0x2faa8f){const _0x50c667=a1_0x7c9029;this[_0x50c667(0x1a2)](_0x2faa8f);}[a1_0x59d6ab(0x16b)](_0x1b422b){const _0x57c365=a1_0x59d6ab,_0x3ff31b=a1_0x7c9029,{status:_0x26e893,statusText:_0x1138a6,data:_0x269faa}=_0x1b422b,_0x5c2920={'status':_0x26e893,'statusText':_0x1138a6,'data':typeof _0x269faa===_0x57c365(0x120)?JSON[_0x3ff31b(0x173)](_0x269faa):_0x269faa};console['error'](_0x3ff31b(0x172),_0x5c2920);throw new Error(_0x3ff31b(0x177)+_0x26e893+_0x57c365(0x10b)+_0x1138a6);}async['login'](_0x14fd10,_0x15e063,_0x3e4019){const _0x515c88=a1_0x7c9029;await this[_0x515c88(0x161)]();const _0x46f8df=await this[_0x515c88(0x150)](_0x14fd10,_0x15e063),_0x3d021a=await this['getOauth1Token'](_0x46f8df);return await this[_0x515c88(0x15e)](_0x3d021a),this;}async[a1_0x7c9029(0x150)](_0x2005b6,_0x129fda){const _0x12edad=a1_0x59d6ab,_0x1e180e=a1_0x7c9029,_0x592493={'clientId':_0x1e180e(0x152),'locale':'en','service':this[_0x1e180e(0x189)][_0x1e180e(0x16d)]},_0x216b8a=this[_0x1e180e(0x189)][_0x1e180e(0x18d)]+'?'+qs_1[_0x1e180e(0x19a)][_0x1e180e(0x173)](_0x592493);await this[_0x12edad(0x11c)][_0x12edad(0x13a)](_0x216b8a);const _0x58dfb5={'id':_0x1e180e(0x1a1),'embedWidget':!![],'locale':'en','gauthHost':this[_0x12edad(0x152)][_0x1e180e(0x18d)]},_0xaece8f=this[_0x12edad(0x152)]['SIGNIN_URL']+'?'+qs_1[_0x12edad(0x16d)][_0x1e180e(0x173)](_0x58dfb5),_0x5c5c41=await this[_0x1e180e(0x1bd)](_0xaece8f),_0x11b441=CSRF_RE[_0x12edad(0xf5)](_0x5c5c41);if(!_0x11b441)throw new Error(_0x1e180e(0x154));const _0x3b5bda=_0x11b441[0x1],_0x46737c={'id':_0x1e180e(0x1a1),'embedWidget':!![],'clientId':_0x1e180e(0x152),'locale':'en','gauthHost':this[_0x1e180e(0x189)][_0x12edad(0x134)],'service':this[_0x1e180e(0x189)][_0x1e180e(0x18d)],'source':this[_0x12edad(0x152)][_0x1e180e(0x18d)],'redirectAfterAccountLoginUrl':this[_0x1e180e(0x189)][_0x1e180e(0x18d)],'redirectAfterAccountCreationUrl':this[_0x1e180e(0x189)]['GARMIN_SSO_EMBED']},_0x27d94c=this[_0x1e180e(0x189)][_0x12edad(0x164)]+'?'+qs_1[_0x1e180e(0x19a)][_0x1e180e(0x173)](_0x46737c),_0x3a674e=new form_data_1[(_0x1e180e(0x19a))]();_0x3a674e[_0x12edad(0xf0)](_0x12edad(0x10c),_0x2005b6),_0x3a674e[_0x1e180e(0x167)](_0x1e180e(0x16f),_0x129fda),_0x3a674e[_0x1e180e(0x167)](_0x1e180e(0x16c),_0x1e180e(0x19e)),_0x3a674e[_0x12edad(0xf0)](_0x1e180e(0x19f),_0x3b5bda);const _0x13cfaa=await this[_0x1e180e(0x15b)](_0x27d94c,_0x3a674e,{'headers':{'Content-Type':_0x1e180e(0x19d),'Dnt':0x1,'Origin':this[_0x1e180e(0x189)]['GARMIN_SSO_ORIGIN'],'Referer':this[_0x1e180e(0x189)][_0x1e180e(0x1b8)],'User-Agent':USER_AGENT_BROWSER}});console[_0x1e180e(0x194)](_0x1e180e(0x17d),_0x13cfaa),this[_0x1e180e(0x180)](_0x13cfaa),this[_0x1e180e(0x191)](_0x13cfaa),this[_0x1e180e(0x18b)](_0x13cfaa);const _0x120377=TICKET_RE[_0x1e180e(0x187)](_0x13cfaa);if(!_0x120377)throw new Error(_0x1e180e(0x1a6));const _0x488658=_0x120377[0x1];return _0x488658;}[a1_0x7c9029(0x18b)](_0x17f8bc){}[a1_0x7c9029(0x191)](_0x6072cc){const _0x441196=a1_0x59d6ab,_0x46653c=a1_0x7c9029,_0x17d264=PAGE_TITLE_RE[_0x46653c(0x187)](_0x6072cc);if(_0x17d264){const _0x511eb2=_0x17d264[0x1];console[_0x46653c(0x194)](_0x46653c(0x197),_0x511eb2);if(lodash_1[_0x46653c(0x19a)]['includes'](_0x511eb2,_0x46653c(0x1ac)))throw new Error(_0x441196(0x155));}}[a1_0x59d6ab(0xed)](_0x5be52b){const _0x506127=a1_0x7c9029,_0x459c6b=ACCOUNT_LOCKED_RE[_0x506127(0x187)](_0x5be52b);if(_0x459c6b){const _0x31eb35=_0x459c6b[0x1];console[_0x506127(0x17e)](_0x31eb35);throw new Error(_0x506127(0x1be));}}async[a1_0x7c9029(0x168)](){const _0x432098=a1_0x59d6ab,_0x5bda97=a1_0x7c9029;try{!this[_0x5bda97(0x1b6)]&&await this['fetchOauthConsumer']();if(!this[_0x5bda97(0x1c2)]||!this[_0x5bda97(0x1a8)])throw new Error(_0x5bda97(0x1b2));const _0x14731c={'oauth':this[_0x5bda97(0x1a9)](this[_0x432098(0x135)]),'token':this[_0x5bda97(0x1a8)]};await this[_0x5bda97(0x15e)](_0x14731c),console[_0x5bda97(0x194)]('「'+this[_0x5bda97(0x19b)][_0x432098(0x10c)]+_0x5bda97(0x174)+this[_0x5bda97(0x189)][_0x5bda97(0x156)]+_0x5bda97(0x184));}catch(_0x6295f9){console[_0x5bda97(0x17e)](_0x5bda97(0x17c),_0x6295f9);throw _0x6295f9;}}async[a1_0x7c9029(0x166)](_0x8bab4d){const _0x43f113=a1_0x59d6ab,_0x483f91=a1_0x7c9029;if(!this['OAUTH_CONSUMER'])throw new Error(_0x43f113(0x124));const _0x4b5fa7={'ticket':_0x8bab4d,'login-url':this[_0x483f91(0x189)][_0x483f91(0x18d)],'accepts-mfa-tokens':!![]},_0x34e4a7=this[_0x483f91(0x189)][_0x483f91(0x15c)]+_0x43f113(0x14c)+qs_1[_0x483f91(0x19a)][_0x483f91(0x173)](_0x4b5fa7),_0x2d202c=this[_0x483f91(0x1a9)](this[_0x483f91(0x1b6)]),_0x4772a8={'url':_0x34e4a7,'method':_0x483f91(0x182)},_0x242c64=_0x2d202c[_0x483f91(0x190)](_0x2d202c[_0x483f91(0x196)](_0x4772a8)),_0xc3e4a2=await this[_0x483f91(0x1bd)](_0x34e4a7,{'headers':{..._0x242c64,'User-Agent':USER_AGENT_CONNECTMOBILE}}),_0x583857=qs_1[_0x483f91(0x19a)][_0x483f91(0x19c)](_0xc3e4a2);return this[_0x43f113(0x143)]=_0x583857,{'token':_0x583857,'oauth':_0x2d202c};}[a1_0x7c9029(0x1a9)](_0x49f614){const _0x48fa12=a1_0x59d6ab,_0x267177=new oauth_1_0a_1[(_0x48fa12(0x16d))]({'consumer':_0x49f614,'signature_method':_0x48fa12(0x159),'hash_function'(_0xacafa9,_0x705c){const _0xf17ec7=_0x48fa12,_0x351e4d=a1_0x4ba0;return node_crypto_1[_0x351e4d(0x19a)][_0x351e4d(0x162)]('sha1',_0x705c)[_0x351e4d(0x1af)](_0xacafa9)[_0x351e4d(0x17b)](_0xf17ec7(0x154));}});return _0x267177;}async[a1_0x7c9029(0x15e)](_0x17face){const _0x592a7e=a1_0x59d6ab,_0x32a414=a1_0x7c9029,_0x417128={'key':_0x17face[_0x592a7e(0x108)][_0x592a7e(0x119)],'secret':_0x17face[_0x32a414(0x170)][_0x32a414(0x165)]},_0x53ecc4=this[_0x32a414(0x189)]['OAUTH_URL']+_0x592a7e(0x146),_0xa08b70={'url':_0x53ecc4,'method':'POST','data':null},_0x16a40d=_0x17face[_0x32a414(0x15d)]['authorize'](_0xa08b70,_0x417128),_0x2c2a6b=_0x53ecc4+'?'+qs_1[_0x592a7e(0x16d)][_0x592a7e(0x125)](_0x16a40d);this[_0x592a7e(0xfe)]=undefined;const _0xe53662=await this[_0x32a414(0x15b)](_0x2c2a6b,null,{'headers':{'User-Agent':USER_AGENT_CONNECTMOBILE,'Content-Type':_0x32a414(0x19d)}});this[_0x32a414(0x1c2)]=this[_0x32a414(0x171)](_0xe53662);}[a1_0x59d6ab(0x115)](_0x4074e4){const _0x558d4c=a1_0x59d6ab,_0x4e2132=a1_0x7c9029,_0x6594bc=luxon_1[_0x4e2132(0x1b4)][_0x4e2132(0x1bf)](),_0x3c99fc=_0x6594bc[_0x558d4c(0x161)]({'seconds':_0x4074e4[_0x4e2132(0x1a3)]}),_0x469954=_0x6594bc[_0x4e2132(0x179)]({'seconds':_0x4074e4[_0x4e2132(0x18c)]});return{..._0x4074e4,'last_update_date':_0x6594bc[_0x4e2132(0x163)]()[_0x4e2132(0x1aa)](),'expires_date':_0x3c99fc[_0x4e2132(0x163)]()[_0x4e2132(0x1aa)](),'expires_at':_0x3c99fc[_0x558d4c(0x103)](),'refresh_token_expires_at':_0x469954[_0x4e2132(0x15a)]()};}}exports[a1_0x7c9029(0x1ba)]=HttpClient;
|