moontraze 2.0.3 → 2.0.5
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/bin/moontraze.js +68 -8
- package/lib/auth.js +95 -10
- package/package.json +1 -1
package/bin/moontraze.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
const { Command } = require('commander');
|
|
3
3
|
const chalk = require('chalk');
|
|
4
|
-
const path = require('path');
|
|
5
4
|
const { login } = require('../lib/auth');
|
|
6
|
-
const {
|
|
5
|
+
const {
|
|
6
|
+
getConfig,
|
|
7
|
+
getProject,
|
|
8
|
+
setProject,
|
|
9
|
+
GLOBAL_FILE,
|
|
10
|
+
} = require('../lib/config');
|
|
7
11
|
const { deploy } = require('../lib/deploy');
|
|
8
12
|
const { selfUpdate, INSTALL_DIR } = require('../lib/selfUpdate');
|
|
9
13
|
const { uninstall } = require('../lib/uninstall');
|
|
@@ -11,12 +15,14 @@ const { MOONTRAZE_HOME } = require('../lib/paths');
|
|
|
11
15
|
|
|
12
16
|
const program = new Command();
|
|
13
17
|
|
|
14
|
-
// Moon CLI se aata hai
|
|
18
|
+
// Moon CLI se aata hai
|
|
15
19
|
const platformName = process.env.MOON_PLATFORM || 'moontraze';
|
|
16
|
-
const apiUrl =
|
|
17
|
-
|
|
20
|
+
const apiUrl =
|
|
21
|
+
process.env.MOON_API || getConfig().apiUrl || 'https://api.moontraze.com';
|
|
22
|
+
const domain =
|
|
23
|
+
process.env.MOON_DOMAIN || getConfig().domain || 'moontraze.com';
|
|
18
24
|
|
|
19
|
-
let version = '
|
|
25
|
+
let version = '2.0.1';
|
|
20
26
|
try {
|
|
21
27
|
version = require('../package.json').version || version;
|
|
22
28
|
} catch (_) {}
|
|
@@ -114,7 +120,11 @@ program
|
|
|
114
120
|
.option('-y, --yes', 'Confirm uninstall')
|
|
115
121
|
.action((opts) => {
|
|
116
122
|
if (!opts.yes) {
|
|
117
|
-
console.log(
|
|
123
|
+
console.log(
|
|
124
|
+
chalk.yellow(
|
|
125
|
+
'This will remove Moontraze CLI and local data from your system.'
|
|
126
|
+
)
|
|
127
|
+
);
|
|
118
128
|
console.log(chalk.gray(` Target: ${MOONTRAZE_HOME}`));
|
|
119
129
|
console.log(chalk.gray(' Also removes old ~/.moontraze if present.'));
|
|
120
130
|
console.log(chalk.gray(' Global Moon CLI is NOT deleted.'));
|
|
@@ -135,4 +145,54 @@ program
|
|
|
135
145
|
async function runDeploy(opts) {
|
|
136
146
|
try {
|
|
137
147
|
await deploy({
|
|
138
|
-
prod:
|
|
148
|
+
prod: !!(opts.prod || opts.production),
|
|
149
|
+
projectName: opts.project || opts.name,
|
|
150
|
+
apiUrl,
|
|
151
|
+
domain,
|
|
152
|
+
});
|
|
153
|
+
} catch (e) {
|
|
154
|
+
console.error(chalk.red('\nDeploy failed:'), e.message);
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
program
|
|
160
|
+
.command('deploy')
|
|
161
|
+
.description('Deploy current folder')
|
|
162
|
+
.option('--prod', 'Production redeploy')
|
|
163
|
+
.option('--production', 'Alias for --prod')
|
|
164
|
+
.option('-p, --project <name>', 'Project name (or use link)')
|
|
165
|
+
.action(runDeploy);
|
|
166
|
+
|
|
167
|
+
program
|
|
168
|
+
.option('--prod', 'Deploy to production')
|
|
169
|
+
.option('--production', 'Deploy to production')
|
|
170
|
+
.option('-p, --project <name>', 'Project name')
|
|
171
|
+
.action(async (opts, cmd) => {
|
|
172
|
+
if (cmd.args && cmd.args.length) return;
|
|
173
|
+
if (opts.prod || opts.production || opts.project) {
|
|
174
|
+
await runDeploy(opts);
|
|
175
|
+
} else {
|
|
176
|
+
program.help();
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
program.addHelpText(
|
|
181
|
+
'after',
|
|
182
|
+
`
|
|
183
|
+
Examples:
|
|
184
|
+
moon ${platformName} login
|
|
185
|
+
moon ${platformName} link my-site
|
|
186
|
+
moon ${platformName} list
|
|
187
|
+
moon ${platformName} deploy --prod
|
|
188
|
+
moon ${platformName} update
|
|
189
|
+
moon ${platformName} uninstall --yes
|
|
190
|
+
npx moontraze login
|
|
191
|
+
npx moontraze deploy --prod
|
|
192
|
+
`
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
program.parseAsync(process.argv).catch((e) => {
|
|
196
|
+
console.error(chalk.red(e.message));
|
|
197
|
+
process.exit(1);
|
|
198
|
+
});
|
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/verify-login`, {
|
|
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}`));
|