cauthy-auth 0.12.0 → 0.14.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/README.md +8 -0
- package/dist/client.d.mts +86 -1
- package/dist/client.d.ts +86 -1
- package/dist/client.js +21 -7
- package/dist/client.js.map +1 -1
- package/dist/client.mjs +21 -7
- package/dist/client.mjs.map +1 -1
- package/dist/index.js +81 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +81 -2
- package/dist/index.mjs.map +1 -1
- package/dist/mcp.d.mts +103 -0
- package/dist/mcp.d.ts +103 -0
- package/dist/mcp.js +218 -0
- package/dist/mcp.js.map +1 -0
- package/dist/mcp.mjs +191 -0
- package/dist/mcp.mjs.map +1 -0
- package/dist/react.d.mts +104 -1
- package/dist/react.d.ts +104 -1
- package/dist/react.js +259 -12
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +259 -12
- package/dist/react.mjs.map +1 -1
- package/dist/styles.css +5 -0
- package/dist/svelte.js +21 -7
- package/dist/svelte.js.map +1 -1
- package/dist/svelte.mjs +21 -7
- package/dist/svelte.mjs.map +1 -1
- package/dist/vue.js +21 -7
- package/dist/vue.js.map +1 -1
- package/dist/vue.mjs +21 -7
- package/dist/vue.mjs.map +1 -1
- package/package.json +6 -1
package/dist/react.js
CHANGED
|
@@ -240,13 +240,13 @@ function createAuthClient(options = {}) {
|
|
|
240
240
|
const said = typeof options.locale === "function" ? options.locale() : options.locale;
|
|
241
241
|
return (said ?? (typeof document === "undefined" ? "" : document.documentElement?.lang) ?? "").trim();
|
|
242
242
|
};
|
|
243
|
-
async function post(path, form, bad) {
|
|
243
|
+
async function post(path, form, bad, captchaToken) {
|
|
244
244
|
if (bad) return { ok: false, error: { code: bad.code, message: bad.message, field: bad.field } };
|
|
245
245
|
try {
|
|
246
246
|
const res = await doFetch(`${base}${path}`, {
|
|
247
247
|
method: "POST",
|
|
248
248
|
credentials: "same-origin",
|
|
249
|
-
headers: { "content-type": "application/json", accept: "application/json", ...locale() ? { "x-cauthy-locale": locale() } : {} },
|
|
249
|
+
headers: { "content-type": "application/json", accept: "application/json", ...locale() ? { "x-cauthy-locale": locale() } : {}, ...captchaToken ? { "x-cauthy-captcha": captchaToken } : {} },
|
|
250
250
|
body: JSON.stringify(form)
|
|
251
251
|
});
|
|
252
252
|
const body = await res.json().catch(() => null);
|
|
@@ -298,9 +298,11 @@ function createAuthClient(options = {}) {
|
|
|
298
298
|
}
|
|
299
299
|
return {
|
|
300
300
|
signIn: {
|
|
301
|
-
email: (f) => post("/sign-in/email", { email: f.email, password: f.password }, firstProblem(checkEmail(f.email), checkPassword(f.password))),
|
|
301
|
+
email: (f) => post("/sign-in/email", { email: f.email, password: f.password }, firstProblem(checkEmail(f.email), checkPassword(f.password)), f.captchaToken),
|
|
302
302
|
mfa: (f) => post("/sign-in/mfa", { code: f.code }, checkCode(f.code)),
|
|
303
|
-
|
|
303
|
+
mfaMethods: () => post("/sign-in/mfa/methods", {}, null),
|
|
304
|
+
mfaSendCode: () => post("/sign-in/mfa/send", {}, null),
|
|
305
|
+
magicLink: (f) => post("/sign-in/magic-link", { email: f.email }, checkEmail(f.email), f.captchaToken),
|
|
304
306
|
magicLinkVerify: (f) => post("/sign-in/magic-link/verify", { token: f.token }, null),
|
|
305
307
|
emailCode: (f) => post("/sign-in/email-code", { code: f.code }, checkCode(f.code)),
|
|
306
308
|
passkeyUrl,
|
|
@@ -381,9 +383,9 @@ function createAuthClient(options = {}) {
|
|
|
381
383
|
}
|
|
382
384
|
},
|
|
383
385
|
signUp: {
|
|
384
|
-
email: (f) => post("/sign-up/email", { email: f.email, password: f.password, name: f.name }, firstProblem(checkName(f.name), checkEmail(f.email), checkNewPassword(f.password)))
|
|
386
|
+
email: (f) => post("/sign-up/email", { email: f.email, password: f.password, name: f.name }, firstProblem(checkName(f.name), checkEmail(f.email), checkNewPassword(f.password)), f.captchaToken)
|
|
385
387
|
},
|
|
386
|
-
forgotPassword: (f) => post("/forgot-password", { email: f.email }, checkEmail(f.email)),
|
|
388
|
+
forgotPassword: (f) => post("/forgot-password", { email: f.email }, checkEmail(f.email), f.captchaToken),
|
|
387
389
|
resetPassword: (f) => post("/reset-password", { token: f.token, password: f.password }, checkNewPassword(f.password)),
|
|
388
390
|
verifyEmail: (f) => post("/verify-email", { token: f.token }, null),
|
|
389
391
|
signOut: () => post("/sign-out", {}, null),
|
|
@@ -401,7 +403,14 @@ function createAuthClient(options = {}) {
|
|
|
401
403
|
setup: (f) => post("/me/mfa/setup", { password: f.password }, null),
|
|
402
404
|
verify: (f) => post("/me/mfa/verify", { code: f.code }, checkCode(f.code)),
|
|
403
405
|
disable: (f) => post("/me/mfa/disable", { password: f.password }, null),
|
|
404
|
-
recoveryCodes: (f) => post("/me/mfa/recovery-codes", { password: f.password }, null)
|
|
406
|
+
recoveryCodes: (f) => post("/me/mfa/recovery-codes", { password: f.password }, null),
|
|
407
|
+
async factors() {
|
|
408
|
+
const body = await read("/me/mfa/factors");
|
|
409
|
+
return body && typeof body.totp === "boolean" ? body : null;
|
|
410
|
+
},
|
|
411
|
+
addPhone: (f) => post("/me/mfa/phone", { phone: f.phone, channel: f.channel, password: f.password }, null),
|
|
412
|
+
verifyPhone: (f) => post("/me/mfa/phone/verify", { code: f.code }, checkCode(f.code)),
|
|
413
|
+
removePhone: (f) => post("/me/mfa/phone/remove", { password: f.password }, null)
|
|
405
414
|
},
|
|
406
415
|
changeEmail: (f) => post("/me/email", { email: f.email, password: f.password }, checkEmail(f.email)),
|
|
407
416
|
async identities() {
|
|
@@ -418,6 +427,11 @@ function createAuthClient(options = {}) {
|
|
|
418
427
|
return body && Array.isArray(body.sessions) ? body.sessions : [];
|
|
419
428
|
},
|
|
420
429
|
signOutEverywhere: () => post("/me/sessions/end", {}, null),
|
|
430
|
+
async agents() {
|
|
431
|
+
const body = await read("/me/agents");
|
|
432
|
+
return body && Array.isArray(body.agents) ? body.agents : [];
|
|
433
|
+
},
|
|
434
|
+
disconnectAgent: (id) => post("/me/agents/disconnect", { id }, null),
|
|
421
435
|
async passkeys() {
|
|
422
436
|
const body = await read("/me/passkeys");
|
|
423
437
|
return body && Array.isArray(body.passkeys) ? body.passkeys : [];
|
|
@@ -519,6 +533,18 @@ var TEXTS = {
|
|
|
519
533
|
linkSent: "If that address has an account, a link to choose a new password is on its way.",
|
|
520
534
|
codeHelp: "Enter the code from your authenticator app, or a recovery code.",
|
|
521
535
|
verify: "Verify",
|
|
536
|
+
codeHelpPhone: "We send a code to your phone. Ask for it, then type it here, or use a recovery code.",
|
|
537
|
+
sendCodeSms: "Send a code by SMS to {to}",
|
|
538
|
+
sendCodeWhatsapp: "Send a code by WhatsApp to {to}",
|
|
539
|
+
codeSent: "We sent a code to {to}. Type it here.",
|
|
540
|
+
phone: "Phone, with its country code",
|
|
541
|
+
phoneHelp: "Get your codes by SMS or WhatsApp instead of an app.",
|
|
542
|
+
phoneOn: "Codes go to {to}.",
|
|
543
|
+
phoneOff: "No phone yet.",
|
|
544
|
+
addPhone: "Add phone",
|
|
545
|
+
removePhone: "Remove phone",
|
|
546
|
+
bySms: "SMS",
|
|
547
|
+
byWhatsapp: "WhatsApp",
|
|
522
548
|
checkEmail: "Almost there: open the link we sent to confirm your address, then sign in.",
|
|
523
549
|
backToSignIn: "Back to sign in",
|
|
524
550
|
emailMeALink: "Email me a sign-in link",
|
|
@@ -557,6 +583,10 @@ var TEXTS = {
|
|
|
557
583
|
passkeyUnnamed: "Passkey",
|
|
558
584
|
sessions: "Where you are signed in",
|
|
559
585
|
signOutEverywhere: "Sign out everywhere",
|
|
586
|
+
agents: "AI agents",
|
|
587
|
+
agentsHelp: "Agents you allowed to act for you. Disconnect one and it loses its access within minutes.",
|
|
588
|
+
disconnect: "Disconnect",
|
|
589
|
+
anAgent: "An AI agent",
|
|
560
590
|
unknownDevice: "Unknown device",
|
|
561
591
|
emailAddress: "Email address",
|
|
562
592
|
newEmail: "New email address",
|
|
@@ -586,6 +616,13 @@ var TEXTS = {
|
|
|
586
616
|
step_up_required: "Enter your current password.",
|
|
587
617
|
weak_password: "Choose a stronger password.",
|
|
588
618
|
unauthenticated: "Sign in first.",
|
|
619
|
+
phone_refused: "The code could not be sent to that number.",
|
|
620
|
+
too_many_codes: "Enough codes were sent. Use the last one, or sign in again.",
|
|
621
|
+
phone_unavailable: "Codes cannot be sent that way here.",
|
|
622
|
+
phone_already_set: "Remove the phone you have first.",
|
|
623
|
+
phone_codes_unavailable: "Codes cannot be sent right now. Try again in a moment.",
|
|
624
|
+
captcha_required: "Complete the check that you are not a bot, then try again.",
|
|
625
|
+
captcha_failed: "The check that you are not a bot did not pass. Try it again.",
|
|
589
626
|
passkey_failed: "The passkey could not be used. Try again, or sign in another way.",
|
|
590
627
|
passkey_exists: "This device already has a passkey for your account.",
|
|
591
628
|
passkey_unavailable: "Passkeys cannot be used here."
|
|
@@ -608,6 +645,18 @@ var TEXTS = {
|
|
|
608
645
|
linkSent: "Si ese correo tiene una cuenta, ya va en camino un enlace para elegir una contrase\xF1a nueva.",
|
|
609
646
|
codeHelp: "Escribe el c\xF3digo de tu aplicaci\xF3n de autenticaci\xF3n, o un c\xF3digo de recuperaci\xF3n.",
|
|
610
647
|
verify: "Verificar",
|
|
648
|
+
codeHelpPhone: "Te enviamos un c\xF3digo a tu tel\xE9fono. P\xEDdelo y escr\xEDbelo aqu\xED, o usa un c\xF3digo de recuperaci\xF3n.",
|
|
649
|
+
sendCodeSms: "Enviar un c\xF3digo por SMS a {to}",
|
|
650
|
+
sendCodeWhatsapp: "Enviar un c\xF3digo por WhatsApp a {to}",
|
|
651
|
+
codeSent: "Te enviamos un c\xF3digo a {to}. Escr\xEDbelo aqu\xED.",
|
|
652
|
+
phone: "Tel\xE9fono, con su c\xF3digo de pa\xEDs",
|
|
653
|
+
phoneHelp: "Recibe tus c\xF3digos por SMS o WhatsApp en vez de una app.",
|
|
654
|
+
phoneOn: "Los c\xF3digos van a {to}.",
|
|
655
|
+
phoneOff: "Todav\xEDa no tienes un tel\xE9fono.",
|
|
656
|
+
addPhone: "Agregar tel\xE9fono",
|
|
657
|
+
removePhone: "Quitar tel\xE9fono",
|
|
658
|
+
bySms: "SMS",
|
|
659
|
+
byWhatsapp: "WhatsApp",
|
|
611
660
|
checkEmail: "Ya casi: abre el enlace que te enviamos para confirmar tu correo y luego entra.",
|
|
612
661
|
backToSignIn: "Volver a entrar",
|
|
613
662
|
emailMeALink: "Env\xEDame un enlace para entrar",
|
|
@@ -646,6 +695,10 @@ var TEXTS = {
|
|
|
646
695
|
passkeyUnnamed: "Llave de acceso",
|
|
647
696
|
sessions: "D\xF3nde tienes la sesi\xF3n abierta",
|
|
648
697
|
signOutEverywhere: "Cerrar sesi\xF3n en todas partes",
|
|
698
|
+
agents: "Agentes de IA",
|
|
699
|
+
agentsHelp: "Los agentes a los que permitiste actuar por ti. Si desconectas uno, pierde el acceso en pocos minutos.",
|
|
700
|
+
disconnect: "Desconectar",
|
|
701
|
+
anAgent: "Un agente de IA",
|
|
649
702
|
unknownDevice: "Dispositivo desconocido",
|
|
650
703
|
emailAddress: "Correo",
|
|
651
704
|
newEmail: "Correo nuevo",
|
|
@@ -675,6 +728,13 @@ var TEXTS = {
|
|
|
675
728
|
step_up_required: "Escribe tu contrase\xF1a actual.",
|
|
676
729
|
weak_password: "Elige una contrase\xF1a m\xE1s fuerte.",
|
|
677
730
|
unauthenticated: "Inicia sesi\xF3n primero.",
|
|
731
|
+
phone_refused: "No se pudo enviar el c\xF3digo a ese n\xFAmero.",
|
|
732
|
+
too_many_codes: "Ya se enviaron suficientes c\xF3digos. Usa el \xFAltimo o vuelve a entrar.",
|
|
733
|
+
phone_unavailable: "Aqu\xED no se pueden enviar c\xF3digos de esa forma.",
|
|
734
|
+
phone_already_set: "Primero quita el tel\xE9fono que tienes.",
|
|
735
|
+
phone_codes_unavailable: "Ahora no se pueden enviar c\xF3digos. Int\xE9ntalo en un momento.",
|
|
736
|
+
captcha_required: "Completa la verificaci\xF3n de que no eres un robot y vuelve a intentarlo.",
|
|
737
|
+
captcha_failed: "La verificaci\xF3n de que no eres un robot no pas\xF3. Int\xE9ntalo de nuevo.",
|
|
678
738
|
passkey_failed: "No se pudo usar la llave de acceso. Intenta de nuevo o entra de otra forma.",
|
|
679
739
|
passkey_exists: "Este dispositivo ya tiene una llave de acceso de tu cuenta.",
|
|
680
740
|
passkey_unavailable: "Aqu\xED no se pueden usar llaves de acceso."
|
|
@@ -719,6 +779,63 @@ function useRoot(props) {
|
|
|
719
779
|
if (props.unstyled) return {};
|
|
720
780
|
return { "data-cauthy": "", style: vars };
|
|
721
781
|
}
|
|
782
|
+
var turnstileScript = null;
|
|
783
|
+
function loadTurnstile() {
|
|
784
|
+
const ready = () => window.turnstile;
|
|
785
|
+
if (ready()) return Promise.resolve(ready());
|
|
786
|
+
turnstileScript ??= new Promise((resolve, reject) => {
|
|
787
|
+
const script = document.createElement("script");
|
|
788
|
+
script.src = "https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit";
|
|
789
|
+
script.async = true;
|
|
790
|
+
script.onload = () => ready() ? resolve(ready()) : reject(new Error("turnstile did not load"));
|
|
791
|
+
script.onerror = () => {
|
|
792
|
+
turnstileScript = null;
|
|
793
|
+
reject(new Error("turnstile did not load"));
|
|
794
|
+
};
|
|
795
|
+
document.head.appendChild(script);
|
|
796
|
+
});
|
|
797
|
+
return turnstileScript;
|
|
798
|
+
}
|
|
799
|
+
function useChallenge(siteKey, locale) {
|
|
800
|
+
const box = (0, import_react.useRef)(null);
|
|
801
|
+
const widget = (0, import_react.useRef)(null);
|
|
802
|
+
const [token, setToken] = (0, import_react.useState)("");
|
|
803
|
+
(0, import_react.useEffect)(() => {
|
|
804
|
+
if (!siteKey || !box.current) return;
|
|
805
|
+
let gone = false;
|
|
806
|
+
void loadTurnstile().then((api) => {
|
|
807
|
+
if (gone || !box.current) return;
|
|
808
|
+
const id = api.render(box.current, {
|
|
809
|
+
sitekey: siteKey,
|
|
810
|
+
language: locale ?? "auto",
|
|
811
|
+
size: "flexible",
|
|
812
|
+
callback: (t) => setToken(t),
|
|
813
|
+
"expired-callback": () => setToken(""),
|
|
814
|
+
"error-callback": () => setToken("")
|
|
815
|
+
});
|
|
816
|
+
widget.current = { api, id };
|
|
817
|
+
}).catch(() => {
|
|
818
|
+
});
|
|
819
|
+
return () => {
|
|
820
|
+
gone = true;
|
|
821
|
+
if (widget.current) widget.current.api.remove(widget.current.id);
|
|
822
|
+
widget.current = null;
|
|
823
|
+
};
|
|
824
|
+
}, [siteKey, locale]);
|
|
825
|
+
const renew = () => {
|
|
826
|
+
setToken("");
|
|
827
|
+
if (widget.current) widget.current.api.reset(widget.current.id);
|
|
828
|
+
};
|
|
829
|
+
const node = siteKey ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: box, className: "cauthy-challenge" }) : null;
|
|
830
|
+
return { node, token: token || void 0, renew };
|
|
831
|
+
}
|
|
832
|
+
function useMethods(auth) {
|
|
833
|
+
const [methods, setMethods] = (0, import_react.useState)(null);
|
|
834
|
+
(0, import_react.useEffect)(() => {
|
|
835
|
+
void auth.methods().then(setMethods);
|
|
836
|
+
}, []);
|
|
837
|
+
return methods;
|
|
838
|
+
}
|
|
722
839
|
function useForm(props) {
|
|
723
840
|
const t = { ...TEXTS[props.locale ?? "en"], ...props.texts, errors: { ...TEXTS[props.locale ?? "en"].errors, ...props.texts?.errors } };
|
|
724
841
|
const cx = (slot) => props.classNames?.[slot] ?? `cauthy-${slot}`;
|
|
@@ -791,6 +908,23 @@ function SignIn(props) {
|
|
|
791
908
|
const [password, setPassword] = (0, import_react.useState)("");
|
|
792
909
|
const [code, setCode] = (0, import_react.useState)("");
|
|
793
910
|
const [step, setStep] = (0, import_react.useState)("password");
|
|
911
|
+
const challenge = useChallenge(methods?.captchaSiteKey, props.locale);
|
|
912
|
+
const [phoneWay, setPhoneWay] = (0, import_react.useState)(null);
|
|
913
|
+
const [phoneSent, setPhoneSent] = (0, import_react.useState)("");
|
|
914
|
+
(0, import_react.useEffect)(() => {
|
|
915
|
+
if (step !== "code") return;
|
|
916
|
+
void auth.signIn.mfaMethods().then((r) => {
|
|
917
|
+
if (r.ok) setPhoneWay({ totp: r.totp, phone: r.phone });
|
|
918
|
+
});
|
|
919
|
+
}, [step]);
|
|
920
|
+
const sendCode = async () => {
|
|
921
|
+
f.setBusy(true);
|
|
922
|
+
f.setError(null);
|
|
923
|
+
const r = await auth.signIn.mfaSendCode();
|
|
924
|
+
f.setBusy(false);
|
|
925
|
+
if (!r.ok) return f.setError(r.error);
|
|
926
|
+
setPhoneSent(r.sentTo);
|
|
927
|
+
};
|
|
794
928
|
const autofill = (0, import_react.useRef)(null);
|
|
795
929
|
const [offer, setOffer] = (0, import_react.useState)(0);
|
|
796
930
|
(0, import_react.useEffect)(() => {
|
|
@@ -825,8 +959,9 @@ function SignIn(props) {
|
|
|
825
959
|
autofill.current?.abort();
|
|
826
960
|
f.setBusy(true);
|
|
827
961
|
f.setError(null);
|
|
828
|
-
const r = step === "code" ? await auth.signIn.mfa({ code }) : step === "sent" ? await auth.signIn.emailCode({ code }) : await auth.signIn.email({ email, password });
|
|
962
|
+
const r = step === "code" ? await auth.signIn.mfa({ code }) : step === "sent" ? await auth.signIn.emailCode({ code }) : await auth.signIn.email({ email, password, captchaToken: challenge.token });
|
|
829
963
|
f.setBusy(false);
|
|
964
|
+
if (step === "password") challenge.renew();
|
|
830
965
|
if (!r.ok) {
|
|
831
966
|
setOffer((n) => n + 1);
|
|
832
967
|
return f.setError(r.error);
|
|
@@ -849,8 +984,9 @@ function SignIn(props) {
|
|
|
849
984
|
autofill.current?.abort();
|
|
850
985
|
f.setBusy(true);
|
|
851
986
|
f.setError(null);
|
|
852
|
-
const r = await auth.signIn.magicLink({ email });
|
|
987
|
+
const r = await auth.signIn.magicLink({ email, captchaToken: challenge.token });
|
|
853
988
|
f.setBusy(false);
|
|
989
|
+
challenge.renew();
|
|
854
990
|
if (!r.ok) return f.setError(r.error);
|
|
855
991
|
setStep("sent");
|
|
856
992
|
};
|
|
@@ -866,9 +1002,11 @@ function SignIn(props) {
|
|
|
866
1002
|
] });
|
|
867
1003
|
}
|
|
868
1004
|
if (step === "code") {
|
|
1005
|
+
const to = phoneWay?.phone?.number ?? "";
|
|
869
1006
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
|
|
870
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: f.cx("notice"), children: f.t.codeHelp }),
|
|
1007
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: f.cx("notice"), children: phoneSent ? f.t.codeSent.replace("{to}", phoneSent) : phoneWay?.phone && !phoneWay.totp ? f.t.codeHelpPhone : f.t.codeHelp }),
|
|
871
1008
|
general && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
|
|
1009
|
+
phoneWay?.phone && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void sendCode(), children: (phoneWay.phone.channel === "whatsapp" ? f.t.sendCodeWhatsapp : f.t.sendCodeSms).replace("{to}", to) }),
|
|
872
1010
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "code", type: "text", label: f.t.code, value: code, autoComplete: "one-time-code", required: true, onChange: setCode }),
|
|
873
1011
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.verify })
|
|
874
1012
|
] });
|
|
@@ -897,6 +1035,7 @@ function SignIn(props) {
|
|
|
897
1035
|
aside: props.links?.forgotPassword ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { className: f.cx("link"), href: props.links.forgotPassword, children: f.t.forgotPassword }) : void 0
|
|
898
1036
|
}
|
|
899
1037
|
),
|
|
1038
|
+
challenge.node,
|
|
900
1039
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.signIn }),
|
|
901
1040
|
methods?.magicLink && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void sendLink(), children: f.t.emailMeALink }),
|
|
902
1041
|
methods?.signUp !== false && props.links?.signUp && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: f.cx("footer"), children: [
|
|
@@ -928,12 +1067,14 @@ function SignUp(props) {
|
|
|
928
1067
|
const [email, setEmail] = (0, import_react.useState)("");
|
|
929
1068
|
const [password, setPassword] = (0, import_react.useState)("");
|
|
930
1069
|
const [sent, setSent] = (0, import_react.useState)(false);
|
|
1070
|
+
const challenge = useChallenge(useMethods(auth)?.captchaSiteKey, props.locale);
|
|
931
1071
|
const submit = async (e) => {
|
|
932
1072
|
e.preventDefault();
|
|
933
1073
|
f.setBusy(true);
|
|
934
1074
|
f.setError(null);
|
|
935
|
-
const r = await auth.signUp.email({ name, email, password });
|
|
1075
|
+
const r = await auth.signUp.email({ name, email, password, captchaToken: challenge.token });
|
|
936
1076
|
f.setBusy(false);
|
|
1077
|
+
challenge.renew();
|
|
937
1078
|
if (!r.ok) return f.setError(r.error);
|
|
938
1079
|
if (r.status === "verification_required") return setSent(true);
|
|
939
1080
|
f.done();
|
|
@@ -950,6 +1091,7 @@ function SignUp(props) {
|
|
|
950
1091
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "name", type: "text", label: f.t.name, value: name, autoComplete: "name", onChange: setName }),
|
|
951
1092
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: "username", required: true, onChange: setEmail }),
|
|
952
1093
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "password", type: "password", label: f.t.password, value: password, autoComplete: "new-password", required: true, onChange: setPassword }),
|
|
1094
|
+
challenge.node,
|
|
953
1095
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.signUp }),
|
|
954
1096
|
props.links?.signIn && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: f.cx("footer"), children: [
|
|
955
1097
|
f.t.haveAccount,
|
|
@@ -963,12 +1105,14 @@ function ForgotPassword(props) {
|
|
|
963
1105
|
const f = useForm(props);
|
|
964
1106
|
const [email, setEmail] = (0, import_react.useState)("");
|
|
965
1107
|
const [sent, setSent] = (0, import_react.useState)(false);
|
|
1108
|
+
const challenge = useChallenge(useMethods(auth)?.captchaSiteKey, props.locale);
|
|
966
1109
|
const submit = async (e) => {
|
|
967
1110
|
e.preventDefault();
|
|
968
1111
|
f.setBusy(true);
|
|
969
1112
|
f.setError(null);
|
|
970
|
-
const r = await auth.forgotPassword({ email });
|
|
1113
|
+
const r = await auth.forgotPassword({ email, captchaToken: challenge.token });
|
|
971
1114
|
f.setBusy(false);
|
|
1115
|
+
challenge.renew();
|
|
972
1116
|
if (!r.ok) return f.setError(r.error);
|
|
973
1117
|
setSent(true);
|
|
974
1118
|
};
|
|
@@ -982,6 +1126,7 @@ function ForgotPassword(props) {
|
|
|
982
1126
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
|
|
983
1127
|
general && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
|
|
984
1128
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: "username", required: true, onChange: setEmail }),
|
|
1129
|
+
challenge.node,
|
|
985
1130
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.sendLink }),
|
|
986
1131
|
props.links?.signIn && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: f.cx("footer"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { className: f.cx("link"), href: props.links.signIn, children: f.t.backToSignIn }) })
|
|
987
1132
|
] });
|
|
@@ -1081,7 +1226,9 @@ function Account(props) {
|
|
|
1081
1226
|
account.hasPassword && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PasswordPart, { props }),
|
|
1082
1227
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(LinkedPart, { props }),
|
|
1083
1228
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SecondStepPart, { props, account, onChanged: (mfaEnabled) => setAccount({ ...account, mfaEnabled }) }),
|
|
1229
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(PhonePart, { props, account, onChanged: (mfaEnabled) => setAccount({ ...account, mfaEnabled }) }),
|
|
1084
1230
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(PasskeysPart, { props, account, accountUrl: accountUrl(), when }),
|
|
1231
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AgentsPart, { props, when }),
|
|
1085
1232
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: cx("section"), children: [
|
|
1086
1233
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: cx("heading"), children: t.sessions }),
|
|
1087
1234
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: cx("sessions"), children: sessions.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: cx("session"), children: [
|
|
@@ -1310,6 +1457,106 @@ function SecondStepPart({ props, account, onChanged }) {
|
|
|
1310
1457
|
account.mfaEnabled && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void renew(), children: f.t.newRecoveryCodes })
|
|
1311
1458
|
] });
|
|
1312
1459
|
}
|
|
1460
|
+
function PhonePart({ props, account, onChanged }) {
|
|
1461
|
+
const auth = useAuth();
|
|
1462
|
+
const { f, run, general } = useSection(props);
|
|
1463
|
+
const [ways, setWays] = (0, import_react.useState)(null);
|
|
1464
|
+
const [number, setNumber] = (0, import_react.useState)("");
|
|
1465
|
+
const [channel, setChannel] = (0, import_react.useState)("sms");
|
|
1466
|
+
const [password, setPassword] = (0, import_react.useState)("");
|
|
1467
|
+
const [code, setCode] = (0, import_react.useState)("");
|
|
1468
|
+
const [sentTo, setSentTo] = (0, import_react.useState)("");
|
|
1469
|
+
const [codes, setCodes] = (0, import_react.useState)(null);
|
|
1470
|
+
const load = () => auth.account.mfa.factors().then((w) => {
|
|
1471
|
+
setWays(w);
|
|
1472
|
+
if (w && w.phoneChannels.length > 0 && !w.phoneChannels.includes(channel)) setChannel(w.phoneChannels[0]);
|
|
1473
|
+
});
|
|
1474
|
+
(0, import_react.useEffect)(() => {
|
|
1475
|
+
void load();
|
|
1476
|
+
}, []);
|
|
1477
|
+
if (!ways || ways.phoneChannels.length === 0) return null;
|
|
1478
|
+
const add = async (e) => {
|
|
1479
|
+
e.preventDefault();
|
|
1480
|
+
const r = await run(() => auth.account.mfa.addPhone({ phone: number, channel, password }));
|
|
1481
|
+
if (r.ok) setSentTo(r.sentTo);
|
|
1482
|
+
};
|
|
1483
|
+
const confirm = async (e) => {
|
|
1484
|
+
e.preventDefault();
|
|
1485
|
+
const r = await run(() => auth.account.mfa.verifyPhone({ code }));
|
|
1486
|
+
if (!r.ok) return;
|
|
1487
|
+
setSentTo("");
|
|
1488
|
+
setCode("");
|
|
1489
|
+
setPassword("");
|
|
1490
|
+
if (r.recoveryCodes.length > 0) setCodes(r.recoveryCodes);
|
|
1491
|
+
onChanged(true);
|
|
1492
|
+
await load();
|
|
1493
|
+
};
|
|
1494
|
+
const remove = async (e) => {
|
|
1495
|
+
e.preventDefault();
|
|
1496
|
+
const r = await run(() => auth.account.mfa.removePhone({ password }));
|
|
1497
|
+
if (!r.ok) return;
|
|
1498
|
+
setPassword("");
|
|
1499
|
+
await load();
|
|
1500
|
+
const left = await auth.account.mfa.factors();
|
|
1501
|
+
onChanged(Boolean(left?.totp));
|
|
1502
|
+
};
|
|
1503
|
+
const passwordField = account.hasPassword && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword });
|
|
1504
|
+
if (sentTo) {
|
|
1505
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { className: f.cx("section"), onSubmit: confirm, noValidate: true, children: [
|
|
1506
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: f.cx("heading"), children: f.t.phone }),
|
|
1507
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: f.cx("notice"), children: f.t.codeSent.replace("{to}", sentTo) }),
|
|
1508
|
+
general && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
|
|
1509
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "code", type: "text", label: f.t.code, value: code, autoComplete: "one-time-code", required: true, onChange: setCode }),
|
|
1510
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.verify })
|
|
1511
|
+
] });
|
|
1512
|
+
}
|
|
1513
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { className: f.cx("section"), onSubmit: ways.phone ? remove : add, noValidate: true, children: [
|
|
1514
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: f.cx("heading"), children: f.t.phone }),
|
|
1515
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: f.cx("notice"), children: ways.phone ? f.t.phoneOn.replace("{to}", ways.phone.number) : `${f.t.phoneOff} ${f.t.phoneHelp}` }),
|
|
1516
|
+
codes && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1517
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: f.cx("notice"), children: f.t.keepCodes }),
|
|
1518
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: f.cx("codes"), children: codes.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: c }) }, c)) })
|
|
1519
|
+
] }),
|
|
1520
|
+
general && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
|
|
1521
|
+
!ways.phone && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "phone", type: "tel", label: f.t.phone, value: number, autoComplete: "tel", required: true, onChange: setNumber }),
|
|
1522
|
+
!ways.phone && ways.phoneChannels.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: f.cx("field"), role: "radiogroup", children: ways.phoneChannels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: f.cx("label"), children: [
|
|
1523
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "radio", name: "channel", value: c, checked: channel === c, onChange: () => setChannel(c) }),
|
|
1524
|
+
" ",
|
|
1525
|
+
c === "whatsapp" ? f.t.byWhatsapp : f.t.bySms
|
|
1526
|
+
] }, c)) }),
|
|
1527
|
+
passwordField,
|
|
1528
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: ways.phone ? f.t.removePhone : f.t.addPhone })
|
|
1529
|
+
] });
|
|
1530
|
+
}
|
|
1531
|
+
function AgentsPart({ props, when }) {
|
|
1532
|
+
const auth = useAuth();
|
|
1533
|
+
const { f, run, general } = useSection(props);
|
|
1534
|
+
const [list, setList] = (0, import_react.useState)([]);
|
|
1535
|
+
(0, import_react.useEffect)(() => {
|
|
1536
|
+
void auth.account.agents().then(setList);
|
|
1537
|
+
}, []);
|
|
1538
|
+
if (list.length === 0) return null;
|
|
1539
|
+
const disconnect = async (id) => {
|
|
1540
|
+
const r = await run(() => auth.account.disconnectAgent(id));
|
|
1541
|
+
if (r.ok) setList(list.filter((a) => a.id !== id));
|
|
1542
|
+
};
|
|
1543
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: f.cx("section"), children: [
|
|
1544
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: f.cx("heading"), children: f.t.agents }),
|
|
1545
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: f.cx("notice"), children: f.t.agentsHelp }),
|
|
1546
|
+
general && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
|
|
1547
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: f.cx("sessions"), children: list.map((a) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: f.cx("session"), children: [
|
|
1548
|
+
a.name || f.t.anAgent,
|
|
1549
|
+
a.redirectHost ? ` (${a.redirectHost})` : "",
|
|
1550
|
+
" \u2192 ",
|
|
1551
|
+
a.resource.name,
|
|
1552
|
+
a.scopes.length > 0 ? ` \xB7 ${a.scopes.map((s) => s.description || s.name).join(", ")}` : "",
|
|
1553
|
+
" \xB7 ",
|
|
1554
|
+
when(a.lastUsedAt),
|
|
1555
|
+
" ",
|
|
1556
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void disconnect(a.id), children: f.t.disconnect })
|
|
1557
|
+
] }, a.id)) })
|
|
1558
|
+
] });
|
|
1559
|
+
}
|
|
1313
1560
|
function SignOutEverywhere({ props }) {
|
|
1314
1561
|
const auth = useAuth();
|
|
1315
1562
|
const { f, run, general } = useSection(props);
|