fluxy-bot 0.7.3 → 0.7.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/dist-fluxy/assets/{fluxy-CRSo6Knd.js → fluxy-CR6Sg8AD.js} +22 -22
- package/dist-fluxy/assets/globals-Bs_wR6rP.css +1 -0
- package/dist-fluxy/assets/globals-DxeORYnQ.js +18 -0
- package/dist-fluxy/assets/{onboard-CsZAcwbT.js → onboard-ChgrXiME.js} +1 -1
- package/dist-fluxy/fluxy.html +3 -3
- package/dist-fluxy/onboard.html +3 -3
- package/package.json +1 -1
- package/supervisor/chat/OnboardWizard.tsx +80 -21
- package/dist-fluxy/assets/globals-BWMp2Xbb.js +0 -18
- package/dist-fluxy/assets/globals-C8d9vAbE.css +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{e as o,j as e,R as n,O as r}from"./globals-DxeORYnQ.js";function a(){const t=()=>{window.parent?.postMessage({type:"fluxy:onboard-complete"},"*")};return e.jsx(r,{onComplete:t,isInitialSetup:!0})}o.createRoot(document.getElementById("root")).render(e.jsx(n.StrictMode,{children:e.jsx(a,{})}));
|
package/dist-fluxy/fluxy.html
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, interactive-widget=resizes-content" />
|
|
6
6
|
<title>Fluxy Chat</title>
|
|
7
|
-
<script type="module" crossorigin src="/fluxy/assets/fluxy-
|
|
8
|
-
<link rel="modulepreload" crossorigin href="/fluxy/assets/globals-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/fluxy/assets/globals-
|
|
7
|
+
<script type="module" crossorigin src="/fluxy/assets/fluxy-CR6Sg8AD.js"></script>
|
|
8
|
+
<link rel="modulepreload" crossorigin href="/fluxy/assets/globals-DxeORYnQ.js">
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/fluxy/assets/globals-Bs_wR6rP.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body class="bg-background text-foreground">
|
|
12
12
|
<div id="root"></div>
|
package/dist-fluxy/onboard.html
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, interactive-widget=resizes-content" />
|
|
6
6
|
<title>Fluxy Setup</title>
|
|
7
|
-
<script type="module" crossorigin src="/fluxy/assets/onboard-
|
|
8
|
-
<link rel="modulepreload" crossorigin href="/fluxy/assets/globals-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/fluxy/assets/globals-
|
|
7
|
+
<script type="module" crossorigin src="/fluxy/assets/onboard-ChgrXiME.js"></script>
|
|
8
|
+
<link rel="modulepreload" crossorigin href="/fluxy/assets/globals-DxeORYnQ.js">
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/fluxy/assets/globals-Bs_wR6rP.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body class="bg-background text-foreground">
|
|
12
12
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState, useRef, useEffect, type KeyboardEvent } from 'react';
|
|
2
|
-
import { ArrowRight, LoaderCircle, ExternalLink, ClipboardPaste, RefreshCw, Check, ChevronDown, Mic, Eye, EyeOff, Shield, ShieldCheck, ShieldOff, Copy, Smartphone } from 'lucide-react';
|
|
2
|
+
import { ArrowRight, ArrowLeft, LoaderCircle, ExternalLink, ClipboardPaste, RefreshCw, Check, ChevronDown, Mic, Eye, EyeOff, Shield, ShieldCheck, ShieldOff, Copy, Smartphone } from 'lucide-react';
|
|
3
3
|
import { motion, AnimatePresence } from 'framer-motion';
|
|
4
4
|
|
|
5
5
|
/* ── Provider config ── */
|
|
@@ -174,11 +174,47 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
|
|
|
174
174
|
// Sub-phase within step 3: 'password' | 'totp-setup' | 'recovery'
|
|
175
175
|
const [step3Phase, setStep3Phase] = useState<'password' | 'totp-setup' | 'recovery'>('password');
|
|
176
176
|
|
|
177
|
+
// Clipboard feedback for TOTP secret copy
|
|
178
|
+
const [totpSecretCopied, setTotpSecretCopied] = useState(false);
|
|
179
|
+
|
|
177
180
|
// Pre-fill guard
|
|
178
181
|
const prefillDone = useRef(false);
|
|
179
182
|
|
|
180
183
|
const isConnected = authState[provider] === 'connected';
|
|
181
184
|
|
|
185
|
+
// Persist/restore TOTP setup state across page reloads (mobile deep link → authenticator → return)
|
|
186
|
+
const TOTP_STORAGE_KEY = 'fluxy_totp_setup';
|
|
187
|
+
|
|
188
|
+
function saveTotpState() {
|
|
189
|
+
try {
|
|
190
|
+
sessionStorage.setItem(TOTP_STORAGE_KEY, JSON.stringify({
|
|
191
|
+
secret: totpSecret, qrUri: totpQrUri, otpauthUri: totpOtpauthUri, phase: step3Phase,
|
|
192
|
+
}));
|
|
193
|
+
} catch {}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function restoreTotpState() {
|
|
197
|
+
try {
|
|
198
|
+
const raw = sessionStorage.getItem(TOTP_STORAGE_KEY);
|
|
199
|
+
if (!raw) return false;
|
|
200
|
+
const saved = JSON.parse(raw);
|
|
201
|
+
if (saved.secret && saved.phase === 'totp-setup') {
|
|
202
|
+
setTotpSecret(saved.secret);
|
|
203
|
+
setTotpQrUri(saved.qrUri || '');
|
|
204
|
+
setTotpOtpauthUri(saved.otpauthUri || '');
|
|
205
|
+
setTotpEnabled(true);
|
|
206
|
+
setStep3Phase('totp-setup');
|
|
207
|
+
setStep(3);
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
} catch {}
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function clearTotpStorage() {
|
|
215
|
+
try { sessionStorage.removeItem(TOTP_STORAGE_KEY); } catch {}
|
|
216
|
+
}
|
|
217
|
+
|
|
182
218
|
// Pre-fill from existing settings (re-run wizard)
|
|
183
219
|
useEffect(() => {
|
|
184
220
|
fetch('/api/onboard/status')
|
|
@@ -204,6 +240,9 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
|
|
|
204
240
|
// If user has existing handle, default to 'relay'; otherwise default to 'tunnel'
|
|
205
241
|
if (!data.handle) setHandleChoice('tunnel');
|
|
206
242
|
prefillDone.current = true;
|
|
243
|
+
|
|
244
|
+
// Restore TOTP setup state if returning from authenticator app
|
|
245
|
+
if (!data.totpEnabled) restoreTotpState();
|
|
207
246
|
})
|
|
208
247
|
.catch(() => { prefillDone.current = true; });
|
|
209
248
|
}, []);
|
|
@@ -1152,17 +1191,15 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
|
|
|
1152
1191
|
)}
|
|
1153
1192
|
</div>
|
|
1154
1193
|
<div className="flex-1 min-w-0">
|
|
1155
|
-
<
|
|
1156
|
-
<span className="text-[13px] font-medium text-white">Two-Factor Authentication</span>
|
|
1157
|
-
{(tunnelMode === 'quick' || tunnelMode === 'named') && !totpEnabled && (
|
|
1158
|
-
<span className="text-[10px] px-1.5 py-0.5 rounded-full bg-amber-500/10 text-amber-400 border border-amber-500/20 shrink-0">Recommended</span>
|
|
1159
|
-
)}
|
|
1160
|
-
{totpEnabled && totpVerified && (
|
|
1161
|
-
<span className="text-[10px] px-1.5 py-0.5 rounded-full bg-emerald-500/10 text-emerald-400 border border-emerald-500/20 shrink-0">Active</span>
|
|
1162
|
-
)}
|
|
1163
|
-
</div>
|
|
1194
|
+
<span className="text-[13px] font-medium text-white block">Two-Factor Auth</span>
|
|
1164
1195
|
<p className="text-[11px] text-white/30 mt-0.5">
|
|
1165
|
-
{totpEnabled && totpVerified ?
|
|
1196
|
+
{totpEnabled && totpVerified ? (
|
|
1197
|
+
<span className="text-emerald-400/70">Active — authenticator app required</span>
|
|
1198
|
+
) : (tunnelMode === 'quick' || tunnelMode === 'named') ? (
|
|
1199
|
+
<span>Recommended for public bots</span>
|
|
1200
|
+
) : (
|
|
1201
|
+
<span>Extra security with an authenticator app</span>
|
|
1202
|
+
)}
|
|
1166
1203
|
</p>
|
|
1167
1204
|
</div>
|
|
1168
1205
|
<div className={`w-10 h-6 rounded-full transition-colors relative shrink-0 ${totpEnabled ? 'bg-emerald-500' : 'bg-white/10'}`}>
|
|
@@ -1260,6 +1297,7 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
|
|
|
1260
1297
|
setTotpCode('');
|
|
1261
1298
|
setTotpError('');
|
|
1262
1299
|
setStep3Phase('password');
|
|
1300
|
+
clearTotpStorage();
|
|
1263
1301
|
}}
|
|
1264
1302
|
className="w-7 h-7 rounded-full bg-white/[0.04] flex items-center justify-center text-white/40 hover:text-white/70 transition-colors shrink-0"
|
|
1265
1303
|
>
|
|
@@ -1282,20 +1320,39 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
|
|
|
1282
1320
|
<p className="text-white/40 text-[13px] leading-relaxed mb-4">
|
|
1283
1321
|
Add Fluxy to your authenticator app, then enter the 6-digit code below to confirm.
|
|
1284
1322
|
</p>
|
|
1323
|
+
|
|
1324
|
+
{/* Primary: copy secret key (doesn't leave the app) */}
|
|
1325
|
+
<button
|
|
1326
|
+
onClick={() => {
|
|
1327
|
+
navigator.clipboard.writeText(totpSecret);
|
|
1328
|
+
setTotpSecretCopied(true);
|
|
1329
|
+
setTimeout(() => setTotpSecretCopied(false), 3000);
|
|
1330
|
+
}}
|
|
1331
|
+
className={`w-full py-3 text-[14px] font-medium rounded-xl transition-colors flex items-center justify-center gap-2 ${
|
|
1332
|
+
totpSecretCopied
|
|
1333
|
+
? 'bg-emerald-500/10 text-emerald-400 border border-emerald-500/20'
|
|
1334
|
+
: 'bg-white/[0.05] text-white/70 hover:bg-white/[0.08] border border-white/[0.08]'
|
|
1335
|
+
}`}
|
|
1336
|
+
>
|
|
1337
|
+
{totpSecretCopied ? (
|
|
1338
|
+
<><Check className="h-4 w-4" />Secret key copied</>
|
|
1339
|
+
) : (
|
|
1340
|
+
<><Copy className="h-4 w-4" />Copy secret key</>
|
|
1341
|
+
)}
|
|
1342
|
+
</button>
|
|
1343
|
+
<p className="text-[11px] text-white/20 text-center mt-2">
|
|
1344
|
+
Paste it in your authenticator app → Add account → Enter key
|
|
1345
|
+
</p>
|
|
1346
|
+
|
|
1347
|
+
{/* Secondary: deep link (saves state before leaving) */}
|
|
1285
1348
|
<a
|
|
1286
1349
|
href={totpOtpauthUri}
|
|
1287
|
-
|
|
1350
|
+
onClick={() => saveTotpState()}
|
|
1351
|
+
className="w-full mt-3 py-2.5 text-[13px] text-white/30 hover:text-white/50 flex items-center justify-center gap-1.5 transition-colors"
|
|
1288
1352
|
>
|
|
1289
|
-
<Smartphone className="h-
|
|
1290
|
-
|
|
1353
|
+
<Smartphone className="h-3.5 w-3.5" />
|
|
1354
|
+
Or open directly in authenticator
|
|
1291
1355
|
</a>
|
|
1292
|
-
<button
|
|
1293
|
-
onClick={() => { navigator.clipboard.writeText(totpSecret); }}
|
|
1294
|
-
className="w-full mt-2 text-[11px] text-white/25 hover:text-white/40 flex items-center justify-center gap-1 py-1 transition-colors"
|
|
1295
|
-
>
|
|
1296
|
-
<Copy className="h-3 w-3" />
|
|
1297
|
-
Or copy secret key manually
|
|
1298
|
-
</button>
|
|
1299
1356
|
</div>
|
|
1300
1357
|
) : (
|
|
1301
1358
|
<div className="mt-4 flex gap-4 items-start">
|
|
@@ -1355,6 +1412,7 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
|
|
|
1355
1412
|
setTotpVerified(true);
|
|
1356
1413
|
setRecoveryCodes(data.recoveryCodes || []);
|
|
1357
1414
|
setStep3Phase('recovery');
|
|
1415
|
+
clearTotpStorage();
|
|
1358
1416
|
} else {
|
|
1359
1417
|
setTotpError(data.error || 'Verification failed');
|
|
1360
1418
|
}
|
|
@@ -1429,6 +1487,7 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
|
|
|
1429
1487
|
onClick={() => {
|
|
1430
1488
|
setRecoveryCodes([]);
|
|
1431
1489
|
setStep3Phase('password');
|
|
1490
|
+
clearTotpStorage();
|
|
1432
1491
|
}}
|
|
1433
1492
|
disabled={!recoveryCodesCopied}
|
|
1434
1493
|
className="w-full mt-3 py-3 bg-gradient-brand hover:opacity-90 text-white text-[14px] font-semibold rounded-full transition-colors flex items-center justify-center gap-2 disabled:opacity-40"
|