moontraze 2.0.4 → 2.0.6
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/lib/auth.js +95 -10
- package/package.json +1 -1
package/lib/auth.js
CHANGED
|
@@ -68,11 +68,23 @@ async function loginWithEmail({ apiUrl, label }) {
|
|
|
68
68
|
});
|
|
69
69
|
|
|
70
70
|
const data = await res.json().catch(() => ({}));
|
|
71
|
+
|
|
71
72
|
if (!res.ok) throw new Error(data.error || 'Invalid email or password');
|
|
73
|
+
|
|
74
|
+
// ---------- TOTP required ----------
|
|
75
|
+
if (data.requiresTotp && data.loginTicket) {
|
|
76
|
+
const token = await promptAndVerifyTotp({
|
|
77
|
+
apiUrl,
|
|
78
|
+
loginTicket: data.loginTicket,
|
|
79
|
+
label,
|
|
80
|
+
});
|
|
81
|
+
await saveAndValidateToken(token, { apiUrl, label });
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
72
85
|
if (!data.token) throw new Error('Login succeeded but no token returned');
|
|
73
86
|
|
|
74
87
|
setConfig({ token: data.token, apiUrl });
|
|
75
|
-
|
|
76
88
|
console.log('');
|
|
77
89
|
console.log(chalk.green('✓ Logged in'));
|
|
78
90
|
if (data.user?.email) console.log(chalk.gray(` ${data.user.email}`));
|
|
@@ -123,12 +135,33 @@ async function loginWithMoonID({ apiUrl, label }) {
|
|
|
123
135
|
console.log(chalk.gray('Waiting for approval... (Ctrl+C to cancel)'));
|
|
124
136
|
console.log('');
|
|
125
137
|
|
|
126
|
-
const
|
|
127
|
-
if (!token) throw new Error('MoonID login timed out or denied');
|
|
138
|
+
const result = await pollWebStatus({ apiUrl, state, timeoutMs: 180000 });
|
|
128
139
|
|
|
129
|
-
|
|
140
|
+
if (!result) throw new Error('MoonID login timed out or denied');
|
|
141
|
+
|
|
142
|
+
// ---------- TOTP required ----------
|
|
143
|
+
if (result.requiresTotp && result.loginTicket) {
|
|
144
|
+
const token = await promptAndVerifyTotp({
|
|
145
|
+
apiUrl,
|
|
146
|
+
loginTicket: result.loginTicket,
|
|
147
|
+
label,
|
|
148
|
+
});
|
|
149
|
+
await saveAndValidateToken(token, { apiUrl, label });
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (!result.token) throw new Error('MoonID login succeeded but no token returned');
|
|
154
|
+
|
|
155
|
+
await saveAndValidateToken(result.token, { apiUrl, label });
|
|
130
156
|
}
|
|
131
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Poll /moonid/status
|
|
160
|
+
* Returns:
|
|
161
|
+
* { token } → success
|
|
162
|
+
* { requiresTotp, loginTicket } → need authenticator code
|
|
163
|
+
* null → timeout
|
|
164
|
+
*/
|
|
132
165
|
async function pollWebStatus({ apiUrl, state, timeoutMs }) {
|
|
133
166
|
const fetch = require('node-fetch');
|
|
134
167
|
const start = Date.now();
|
|
@@ -136,18 +169,26 @@ async function pollWebStatus({ apiUrl, state, timeoutMs }) {
|
|
|
136
169
|
|
|
137
170
|
while (Date.now() - start < timeoutMs) {
|
|
138
171
|
await new Promise((r) => setTimeout(r, interval));
|
|
172
|
+
|
|
139
173
|
try {
|
|
140
174
|
const res = await fetch(
|
|
141
175
|
`${apiUrl}/api/platform/moonid/status?state=${encodeURIComponent(state)}`
|
|
142
176
|
);
|
|
143
177
|
const data = await res.json().catch(() => ({}));
|
|
144
178
|
|
|
145
|
-
if (
|
|
146
|
-
|
|
147
|
-
data.token
|
|
148
|
-
) {
|
|
149
|
-
return data.token;
|
|
179
|
+
if ((data.status === 'success' || data.status === 'done') && data.token) {
|
|
180
|
+
return { token: data.token };
|
|
150
181
|
}
|
|
182
|
+
|
|
183
|
+
// Authenticator required
|
|
184
|
+
if (data.status === 'requires_totp' && data.loginTicket) {
|
|
185
|
+
return {
|
|
186
|
+
requiresTotp: true,
|
|
187
|
+
loginTicket: data.loginTicket,
|
|
188
|
+
user: data.user,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
151
192
|
if (data.status === 'error' || data.status === 'denied') {
|
|
152
193
|
throw new Error(data.error || 'MoonID login denied');
|
|
153
194
|
}
|
|
@@ -160,9 +201,54 @@ async function pollWebStatus({ apiUrl, state, timeoutMs }) {
|
|
|
160
201
|
}
|
|
161
202
|
}
|
|
162
203
|
}
|
|
204
|
+
|
|
163
205
|
return null;
|
|
164
206
|
}
|
|
165
207
|
|
|
208
|
+
/**
|
|
209
|
+
* Prompt for 6-digit code and verify against loginTicket
|
|
210
|
+
*/
|
|
211
|
+
async function promptAndVerifyTotp({ apiUrl, loginTicket, label }) {
|
|
212
|
+
console.log('');
|
|
213
|
+
console.log(chalk.yellow('MOON Authenticator required'));
|
|
214
|
+
console.log(chalk.gray('Enter the 6-digit code from the MOON Authenticator app'));
|
|
215
|
+
console.log('');
|
|
216
|
+
|
|
217
|
+
const { code } = await prompts({
|
|
218
|
+
type: 'text',
|
|
219
|
+
name: 'code',
|
|
220
|
+
message: 'Authenticator code',
|
|
221
|
+
validate: (v) =>
|
|
222
|
+
/^\d{6}$/.test(String(v || '').trim())
|
|
223
|
+
? true
|
|
224
|
+
: 'Enter a valid 6-digit code',
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
if (!code) throw new Error('Login cancelled');
|
|
228
|
+
|
|
229
|
+
const fetch = require('node-fetch');
|
|
230
|
+
const res = await fetch(`${apiUrl}/api/authenticator/login-verify`, { // ← yahan fix
|
|
231
|
+
method: 'POST',
|
|
232
|
+
headers: { 'Content-Type': 'application/json' },
|
|
233
|
+
body: JSON.stringify({
|
|
234
|
+
loginTicket,
|
|
235
|
+
code: String(code).trim(),
|
|
236
|
+
}),
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
const data = await res.json().catch(() => ({}));
|
|
240
|
+
|
|
241
|
+
if (!res.ok) {
|
|
242
|
+
throw new Error(data.error || 'Invalid authenticator code');
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (!data.token) {
|
|
246
|
+
throw new Error('Verification succeeded but no token returned');
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return data.token;
|
|
250
|
+
}
|
|
251
|
+
|
|
166
252
|
async function saveAndValidateToken(token, { apiUrl, label }) {
|
|
167
253
|
const fetch = require('node-fetch');
|
|
168
254
|
const res = await fetch(`${apiUrl}/api/hosting/quota`, {
|
|
@@ -174,7 +260,6 @@ async function saveAndValidateToken(token, { apiUrl, label }) {
|
|
|
174
260
|
}
|
|
175
261
|
|
|
176
262
|
setConfig({ token, apiUrl });
|
|
177
|
-
|
|
178
263
|
console.log('');
|
|
179
264
|
console.log(chalk.green('✓ Logged in'));
|
|
180
265
|
console.log(chalk.gray(` Config: ${GLOBAL_FILE}`));
|