@seamless-auth/react 0.0.6-beta.1 → 0.0.6-beta.2
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/index.js +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jsx as e,jsxs as o,Fragment as r}from"react/jsx-runtime";import{createContext as t,useContext as n,useState as i,useEffect as a,useCallback as s,useRef as l}from"react";import{useNavigate as d,Routes as c,Route as _,Navigate as m}from"react-router-dom";import{startAuthentication as u,startRegistration as g,WebAuthnError as h}from"@simplewebauthn/browser";import p,{AsYouType as f,parsePhoneNumberFromString as y}from"libphonenumber-js";const b=t(void 0),v=({value:o,children:r})=>e(b.Provider,{value:o,children:r}),w=()=>{const e=n(b);if(!e)throw new Error("useInternalAuth must be used within InternalAuthProvider");return e},k=e=>{const{authMode:o,authHost:r}=e;return async function(e,t){const n=`${r}${"server"===o?"auth":""}${e.startsWith("/")?e:`/${e}`}`,i={...t,credentials:"include",headers:{"Content-Type":"application/json",...t?.headers}},a=await fetch(n,i);if(a.ok)return a;throw console.warn("Auth fetch failed:",a.status,n),new Error(`Failed to make API call to ${n}`)}},x=()=>e("div",{className:"flex items-center justify-center min-h-screen bg-gray-900",children:e("div",{"data-testid":"loading",className:"w-12 h-12 border-4 border-gray-600 border-t-blue-500 rounded-full animate-spin"})});const P=t(void 0),N=()=>{const e=n(P);if(!e)throw new Error("useAuth must be used within an AuthProvider");return e},S=({children:r,apiHost:t,autoDetectPreviousSignin:n=!0,mode:l="web"})=>{const[d,c]=i(null),[_,m]=i([]),[u,g]=i(!1),[h,p]=i(!0),[f,y]=i(null),{hasSignedInBefore:b,markSignedIn:w}=function(e="seamlessauth_seen"){const[o,r]=i(!1);return a(()=>{try{"true"===localStorage.getItem(e)&&r(!0)}catch{}},[e]),{hasSignedInBefore:o,markSignedIn:()=>{try{localStorage.setItem(e,"true"),r(!0)}catch{}}}}(),[N]=i(l),S=k({authMode:N,authHost:t}),C=s(async()=>{if(d)try{await S("/logout",{method:"GET"})}catch{console.error("Error during logout")}finally{g(!1),c(null),y(null)}},[S,d]),T=async()=>{try{const e=await S("users/me",{method:"GET"});if(e.ok){const{user:o,credentials:r}=await e.json();c(o),m(r),g(!0)}else C()}catch{C()}finally{p(!1)}};return a(()=>{T()},[]),a(()=>{d&&u&&w()},[d,u,w]),h?o("div",{className:"min-h-screen flex items-center justify-center bg-gray-100",children:[e(x,{}),";"]}):e(P.Provider,{value:{user:d,logout:C,deleteUser:async()=>{try{if((await S("/users/delete",{method:"delete"})).ok)return c(null),g(!1),void y(null);throw new Error("Could not delete user.")}catch(e){throw console.error("Something went wrong deleting user:",e),new Error("Could not delete user.")}},isAuthenticated:u,hasRole:e=>d?.roles?.includes(e),apiHost:t,token:f,markSignedIn:w,hasSignedInBefore:!!n&&b,mode:l,credentials:_,updateCredential:async e=>{const o=await S("users/credentials",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({friendlyName:e.friendlyName,id:e.id})});if(o.ok)return o.json();throw new Error("Failed to update credential")},deleteCredential:async e=>{const o=await S("users/credentials",{method:"DELETE",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:e})});if(o.ok)return o.json();throw new Error("Failed to update credential")}},children:e(v,{value:{validateToken:T,setLoading:p},children:r})})};function C(e,o){void 0===o&&(o={});var r=o.insertAt;if(e&&"undefined"!=typeof document){var t=document.head||document.getElementsByTagName("head")[0],n=document.createElement("style");n.type="text/css","top"===r&&t.firstChild?t.insertBefore(n,t.firstChild):t.appendChild(n),n.styleSheet?n.styleSheet.cssText=e:n.appendChild(document.createTextNode(e))}}var T="login-module__container___YggDx",O="login-module__card___Ub-Py",L="login-module__heading___neEqb",I="login-module__message___qSejT",E="login-module__inputGroup___P6qgS",M="login-module__label___mx5vu",j="login-module__input___U07lW",A="login-module__helperText___kDQ4-",F="login-module__error___40zxh",B="login-module__button___0kFBs",z="login-module__toggle___1JiG1",G="login-module__underline___gs-RS",V="login-module__phoneRow___oeNtq",$="login-module__select___rRV1O",q="login-module__phoneInput___2MPQC";C(".login-module__container___YggDx{align-items:center;color:#fff;display:flex;justify-content:center}.login-module__card___Ub-Py{background-color:#1f2937;border-radius:.5rem;box-shadow:0 4px 6px rgba(0,0,0,.1);max-width:28rem;padding:2rem;width:100%}.login-module__heading___neEqb{color:#fff;font-size:1.5rem;font-weight:700;margin-bottom:1.5rem;text-align:center}.login-module__message___qSejT{color:#68d391;text-align:center}.login-module__inputGroup___P6qgS{margin-bottom:1rem}.login-module__label___mx5vu{color:#d1d5db;display:block}.login-module__input___U07lW{background-color:#4b5563;border:1px solid #d1d5db;border-radius:.375rem;margin-top:.25rem;padding:.5rem;width:100%}.login-module__input___U07lW:focus{box-shadow:0 0 0 2px #3b82f6;outline:none}.login-module__helperText___kDQ4-{color:#9ca3af;font-size:.75rem;margin-top:.5rem}.login-module__error___40zxh{color:#f87171;font-size:.875rem}.login-module__button___0kFBs{background-color:#2563eb;border-radius:.375rem;color:#fff;cursor:pointer;margin-top:1rem;padding:.5rem;transition:background-color .3s;width:100%}.login-module__button___0kFBs:hover{background-color:#1d4ed8}.login-module__button___0kFBs:disabled{background-color:#9ca3af;cursor:not-allowed}.login-module__toggle___1JiG1{background:none;border:none;color:#60a5fa;cursor:pointer;font-size:.875rem;margin-top:1.5rem;text-align:center;width:100%}.login-module__underline___gs-RS{text-decoration:underline}.login-module__phoneRow___oeNtq{display:grid;gap:.5rem;grid-template-columns:1fr 3fr;margin-top:.25rem}.login-module__phoneInput___2MPQC,.login-module__select___rRV1O{background-color:#4b5563;border:1px solid #d1d5db;border-radius:.375rem;padding:.5rem;width:100%}@media (max-width:500px){.login-module__phoneRow___oeNtq{grid-template-columns:1fr}}");var R="termsModal-module__overlay___-j6r5",U="termsModal-module__modal___4PxZV",D="termsModal-module__header___B7wxb",J="termsModal-module__title___Sucwt",K="termsModal-module__closeBtn___evIs5",W="termsModal-module__content___5BDhN",H="termsModal-module__link___oPZrU";C(".termsModal-module__overlay___-j6r5{align-items:center;background-color:rgba(0,0,0,.7);display:flex;inset:0;justify-content:center;position:fixed;z-index:999}.termsModal-module__modal___4PxZV{background-color:#1a1a1a;border-radius:8px;box-shadow:0 10px 25px rgba(0,0,0,.4);color:#fff;max-height:80vh;max-width:640px;outline:none;overflow-y:auto;padding:24px;width:100%}.termsModal-module__header___B7wxb{align-items:center;display:flex;justify-content:space-between;margin-bottom:16px}.termsModal-module__title___Sucwt{color:#60a5fa;font-size:1.25rem;font-weight:700}.termsModal-module__closeBtn___evIs5{background:none;border:none;color:#ccc;cursor:pointer;font-size:1.75rem}.termsModal-module__closeBtn___evIs5:hover{color:#fff}.termsModal-module__content___5BDhN{color:#d1d5db;font-size:.9rem;line-height:1.6}.termsModal-module__link___oPZrU{color:#60a5fa;text-decoration:underline}.termsModal-module__link___oPZrU:hover{text-decoration:none}");const Z=({isOpen:r,onClose:t})=>{const n=l(null);return a(()=>{const e=e=>{"Escape"===e.key&&t()};return r&&(document.addEventListener("keydown",e),n.current?.focus()),()=>{document.removeEventListener("keydown",e)}},[r,t]),r?e("div",{className:R,role:"dialog","aria-modal":"true","aria-labelledby":"terms-title",children:o("div",{className:U,tabIndex:-1,ref:n,children:[o("div",{className:D,children:[e("h2",{id:"terms-title",className:J,children:"SMS Terms & Conditions"}),e("button",{onClick:t,className:K,children:"×"})]}),o("div",{className:W,children:[o("p",{children:[e("strong",{children:"Effective Date:"})," June 01, 2025"]}),e("p",{children:"By providing your phone number to SeamlessAuth, a Fells Code LLC product, you agree to receive SMS messages for identity verification, authentication, and account security."}),o("p",{children:[e("strong",{children:"1. Purpose:"})," SMS is used only for account security (OTP, MFA). No marketing messages."]}),o("p",{children:[e("strong",{children:"2. Frequency:"})," Based on login and account activity."]}),o("p",{children:[e("strong",{children:"3. Opt-Out:"})," Contact support@seamlessauth.com to opt out."]}),o("p",{children:[e("strong",{children:"4. Fees:"})," Standard carrier rates may apply."]}),o("p",{children:[e("strong",{children:"5. Supported Carriers:"})," Most major providers supported, delivery not guaranteed."]}),o("p",{children:[e("strong",{children:"6. Privacy:"})," Your phone number is not shared or sold. See our Privacy Policy."]}),o("p",{children:[e("strong",{children:"7. Changes:"})," Terms may be updated with notice on this page."]}),o("p",{children:["Questions? Email us at"," ",e("a",{className:H,href:"mailto:support@seamlessauth.com",children:"support@seamlessauth.com"}),"."]})]})]})}):null},Y=[{code:"US",name:"United States",dialCode:"+1",flag:"🇺🇸"},{code:"CA",name:"Canada",dialCode:"+1",flag:"🇨🇦"},{code:"GB",name:"United Kingdom",dialCode:"+44",flag:"🇬🇧"},{code:"IN",name:"India",dialCode:"+91",flag:"🇮🇳"},{code:"AU",name:"Australia",dialCode:"+61",flag:"🇦🇺"}];function Q({phone:r,setPhone:t,phoneError:n,setPhoneError:s}){const[l,d]=i(!1),[c,_]=i(Y[0]);a(()=>{const e=function(){try{const e=Intl.DateTimeFormat().resolvedOptions().locale||"en-US",o=e.split("-")[1]?.toUpperCase()||"US";return Y.find(e=>e.code===o)||Y[0]}catch{return Y[0]}}();_(e)},[]);return o("div",{className:E,children:[e("label",{id:"phone",className:M,children:"Phone Number"}),o("div",{className:V,children:[e("select",{value:c.code,onChange:e=>{const o=Y.find(o=>o.code===e.target.value);if(o){_(o);const e=r.replace(/^\+\d+/,""),n=(new f).input(o.dialCode+e);t(n)}},className:$,children:Y.map(e=>o("option",{value:e.code,children:[e.flag," (",e.dialCode,")"]},e.code))}),e("input",{"aria-labelledby":"phone",type:"tel",value:r,onChange:e=>{const o=e.target.value,r=o.startsWith(c.dialCode)?o:c.dialCode+o,i=(new f).input(r);t(i),n&&s("")},onBlur:()=>{if(r){const e=y(r),o=e?.isValid();s(o?"":"Please enter a valid phone number.")}},autoComplete:"off",placeholder:"(555) 123-4567",className:q})]}),o("p",{className:A,children:["By signing up, you agree to our"," ",e("button",{onClick:()=>d(!0),className:G,children:"SMS Terms & Conditions"}),"."]}),n&&e("p",{className:F,children:n}),e(Z,{isOpen:l,onClose:()=>d(!1)})]})}const X=e=>{if("string"!=typeof e)return!1;const o=e.trim();if(o.length<3||o.length>320)return!1;const r=o.split("@");if(2!==r.length)return!1;const[t,n]=r;return!(!/^[A-Za-z0-9._%+-]+$/.test(t)||t.startsWith(".")||t.endsWith(".")||t.includes(".."))&&!(!/^[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/.test(n)||n.startsWith("-")||n.endsWith("-")||n.startsWith(".")||n.endsWith(".")||n.includes(".."))},ee=e=>{const o=p(e);return o?.isValid()||!1};async function oe(){if(window.PublicKeyCredential&&"function"==typeof window.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable)try{return await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()}catch(e){return console.error("Error checking passkey support:",e),!1}return!1}const re=()=>{const t=d(),{apiHost:n,hasSignedInBefore:s,mode:l}=N(),{validateToken:c}=w(),[_,m]=i(""),[g,h]=i(""),[p,f]=i("register"),[y,b]=i(""),[v,x]=i(""),[P,S]=i(""),[C,G]=i(""),[V,$]=i(""),[q,R]=i(!1),U=k({authMode:l,authHost:n});a(()=>{!async function(){const e=await oe();R(e)}(),s&&f("login")},[s]);const D=async()=>{x("");try{if(!(await U("/login",{method:"POST",body:JSON.stringify({identifier:_,passkeyAvailable:q})})).ok)return void x("Failed to send login link. Please try again.");await(async()=>{try{const e=await U("/webAuthn/login/start",{method:"POST"});if(!e.ok)return void console.error("Something went wrong getting webauthn options");const o=await e.json(),r=await u({optionsJSON:o}),n=await U("/webAuthn/login/finish",{method:"POST",body:JSON.stringify({assertionResponse:r})});n.ok||console.error("Failed to verify passkey");const i=await n.json();if("Success"===i.message)return i.mfaLogin?void t("/mfaLogin"):(await c(),void t("/"));console.error("Passkey login failed:",i.message)}catch(e){console.error("Passkey login error:",e)}})()}catch(e){console.error("Unexpected login error",e),x("An unexpected error occured. Try again. If the problem persists, try resetting your password")}};return e("div",{className:T,children:o("div",{className:O,children:[e("h2",{className:L,children:"login"===p?"Sign In":"Create Account"}),q?e(r,{children:o("form",{onSubmit:async e=>{e.preventDefault(),"login"===p&&D(),"register"===p&&(async()=>{x("");try{const e=await U("/registration/register",{method:"POST",body:JSON.stringify({email:g,phone:y})});if(!e.ok)return void x("Failed to register. Please try again.");"Success"===(await e.json()).message&&t("/verifyOTP"),x("An unexpected error occured. Try again. If the problem persists, try resetting your password")}catch(e){console.error("Unexpected login error",e),x("An unexpected error occured. Try again. If the problem persists, try resetting your password")}})()},children:["login"===p&&o("div",{className:E,children:[e("label",{htmlFor:"identifier",className:M,children:"Email Address / Phone Number"}),e("input",{id:"identifier",type:"text",value:_,onChange:e=>{const o=e.target.value;m(o)},autoComplete:"off",placeholder:"Email or Phone Number",className:j,onBlur:()=>{if(_){const e=X(_)||ee(_);$(e?"":"Please enter a valid email or phone number")}},required:!0}),e("p",{className:A,children:"Phone numbers must include a country code e.g. +1"}),V&&e("p",{className:F,children:V})]}),"register"===p&&o(r,{children:[o("div",{className:E,children:[e("label",{htmlFor:"email",className:M,children:"Email Address"}),e("input",{id:"email",type:"email",value:g,onChange:e=>{const o=e.target.value;h(o)},autoComplete:"off",className:j,onBlur:()=>{if(g){const e=X(g);G(e?"":"Please enter a valid email")}},required:!0}),C&&e("p",{className:F,children:C})]}),e(Q,{phone:y,setPhone:b,phoneError:P,setPhoneError:S})]}),e("button",{type:"submit",className:B,disabled:!("login"===p&&_?X(_)||ee(_):X(g)&&ee(y)),children:"login"===p?"Login":"Register"}),v&&e("p",{className:F,children:v}),e("button",{type:"button",onClick:()=>f("login"===p?"register":"login"),className:z,children:"login"===p?"Don't have an account? Create one":"Already have an account? Sign in"})]})}):e("p",{className:I,children:"❌ This device doesn't support passkey login. You must provide or register a passkey."})]})})};var te="mfaLogin-module__container___CDMP9",ne="mfaLogin-module__card___kWS58",ie="mfaLogin-module__title___dZABE",ae="mfaLogin-module__msg___2lh2D",se="mfaLogin-module__buttonGroup___3Corm",le="mfaLogin-module__button___4X2WF",de="mfaLogin-module__selected___lkiW-",ce="mfaLogin-module__codeLabel___iC4bk",_e="mfaLogin-module__countdown___rgtkd",me="mfaLogin-module__input___JP-RF",ue="mfaLogin-module__submit___n4-FT",ge="mfaLogin-module__error___SqfpH";C(".mfaLogin-module__container___CDMP9{align-items:center;color:#fff;display:flex;justify-content:center;padding:1rem}.mfaLogin-module__card___kWS58{background-color:#1f2937;border-radius:1rem;box-shadow:0 4px 20px rgba(0,0,0,.4);display:flex;flex-direction:column;gap:1.5rem;max-width:400px;padding:1.5rem;width:100%}.mfaLogin-module__title___dZABE{color:#fff;font-size:1.5rem;font-weight:600;text-align:center}.mfaLogin-module__msg___2lh2D{color:#4ade80;text-align:center}.mfaLogin-module__buttonGroup___3Corm{display:flex;flex-direction:column;gap:1rem}.mfaLogin-module__button___4X2WF{background-color:#374151;border:1px solid #4b5563;border-radius:.5rem;color:#fff;font-weight:500;padding:.75rem 1rem;text-align:left;transition:background-color .2s}.mfaLogin-module__button___4X2WF:hover{background-color:#4b5563}.mfaLogin-module__selected___lkiW-{background-color:#2563eb;border-color:#3b82f6}.mfaLogin-module__codeLabel___iC4bk{display:block;font-size:.875rem;font-weight:500;margin-bottom:.25rem}.mfaLogin-module__countdown___rgtkd{color:#facc15;font-size:.875rem}.mfaLogin-module__input___JP-RF{background-color:#374151;border:1px solid #4b5563;border-radius:.5rem;color:#fff;font-family:monospace;font-size:1.25rem;letter-spacing:.2em;padding:.75rem 1rem;width:100%}.mfaLogin-module__input___JP-RF:focus{border-color:#3b82f6;box-shadow:0 0 0 2px #3b82f6;outline:none}.mfaLogin-module__submit___n4-FT{background-color:#2563eb;border:1px solid #3b82f6;border-radius:.5rem;color:#fff;cursor:pointer;font-weight:500;padding:.75rem 1rem;transition:background-color .2s}.mfaLogin-module__submit___n4-FT:disabled{background-color:#9ca3af;cursor:not-allowed}.mfaLogin-module__error___SqfpH{color:#f87171;margin-bottom:.5rem;text-align:center}@media (max-width:480px){.mfaLogin-module__card___kWS58{padding:1rem}.mfaLogin-module__input___JP-RF,.mfaLogin-module__submit___n4-FT{font-size:1rem}}");const he=()=>{const{apiHost:t,mode:n}=N(),{validateToken:s}=w(),l=d(),[c,_]=i(""),[m,u]=i(""),[g,h]=i(!1),[p,f]=i(""),[y,b]=i(300),[v,x]=i(null),P=k({authMode:n,authHost:t}),S=async()=>{const e="phone"===v?"otp/verify-login-phone-otp":"otp/verify-login-email-otp";try{if(!(await P(`/${e}`,{method:"POST",body:JSON.stringify({verificationToken:c})})).ok)return void u("Verification failed.");await s(),l("/")}catch(e){console.error("Error verifying OTP",e),u("Verification failed.")}},C=async e=>{u("");const o="phone"===e?"otp/generate-login-phone-otp":"otp/generate-login-email-otp";try{(await P(`/${o}`,{method:"GET"})).ok?f(`Verification ${"phone"===e?"SMS":"email"} has been sent.`):u(`Failed to send ${e} code. If this persists, refresh the page and try again.`)}catch{u(`Failed to send ${e} code. If this persists, refresh the page and try again.`)}};return a(()=>{const e=setInterval(()=>{b(e=>e>0?e-1:0)},1e3);return()=>clearInterval(e)},[]),e("div",{className:te,children:o("div",{className:ne,children:[e("h2",{className:ie,children:"Multi-factor Authentication"}),p&&e("p",{className:ae,children:p}),o("div",{className:se,children:[o("button",{onClick:()=>{x("phone"),C("phone")},className:`${le} ${"phone"===v?de:""}`,children:["Send code to phone: ",e("span",{className:"font-mono",children:"****1234"})]}),o("button",{onClick:()=>{x("email"),C("email")},className:`${le} ${"email"===v?de:""}`,children:["Send code to email: ",e("span",{className:"font-mono",children:"j***@example.com"})]})]}),v&&o(r,{children:[m&&e("p",{className:ge,children:m}),o("label",{htmlFor:"otp",className:ce,children:["Enter the 6-digit code sent to your ",v,". ",e("br",{}),o("span",{className:_e,children:["Code expires in: ",(T=y,`${Math.floor(T/60).toString().padStart(2,"0")}:${(T%60).toString().padStart(2,"0")}`)]})]}),e("input",{id:"otp",type:"text",maxLength:6,className:me,placeholder:"••••••",onChange:e=>_(e.target.value)}),e("button",{onClick:async e=>{e.preventDefault(),u(""),h(!0);try{await S()}catch{u("Unexpected error occurred.")}finally{h(!1)}},className:ue,disabled:!c||c.length<6||g,children:g?"Verifying...":"Verify"})]})]})});var T};var pe="passKeyLogin-module__container___IUKxF",fe="passKeyLogin-module__card___2sKM1",ye="passKeyLogin-module__title___HZxvc",be="passKeyLogin-module__button___FvR4I";C(".passKeyLogin-module__container___IUKxF{align-items:center;color:#fff;display:flex;justify-content:center;padding:1rem}.passKeyLogin-module__card___2sKM1{background-color:#1f2937;border-radius:1rem;box-shadow:0 4px 20px rgba(0,0,0,.4);display:flex;flex-direction:column;gap:1.5rem;max-width:400px;padding:2rem;width:100%}.passKeyLogin-module__title___HZxvc{color:#fff;font-size:1.5rem;font-weight:600;text-align:center}.passKeyLogin-module__button___FvR4I{background-color:#2563eb;border:1px solid #3b82f6;border-radius:.5rem;color:#fff;cursor:pointer;font-weight:500;padding:.75rem 1rem;text-align:center;transition:background-color .2s ease;width:100%}.passKeyLogin-module__button___FvR4I:hover{background-color:#1d4ed8}@media (max-width:480px){.passKeyLogin-module__card___2sKM1{padding:1.25rem}.passKeyLogin-module__button___FvR4I{font-size:1rem}}");const ve=()=>{const r=d(),{apiHost:t,mode:n}=N(),{validateToken:i}=w(),a=k({authMode:n,authHost:t});return e("div",{className:pe,children:o("div",{className:fe,children:[e("h2",{className:ye,children:"Login with Passkey"}),e("button",{onClick:async()=>{try{const e=await a("/webAuthn/login/start",{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include"});if(!e.ok)return void console.error("Something went wrong getting webauthn options");const o=await e.json(),t=await u({optionsJSON:o}),n=await a("/webAuthn/login/finish",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({assertionResponse:t}),credentials:"include"});n.ok||console.error("Failed to verify passkey");const s=await n.json();if("Success"===s.message)return s.mfaLogin&&r("/mfaLogin"),await i(),void r("/");console.error("Passkey login failed")}catch{console.error("Passkey login error")}},className:be,children:"Use Passkey"})]})})};var we="registerPasskey-module__container___jqEh8",ke="registerPasskey-module__card___MJAyC",xe="registerPasskey-module__loading___Q4i1x",Pe="registerPasskey-module__spinner___V1nhd",Ne="registerPasskey-module__supported___ihTih",Se="registerPasskey-module__title___vn2Qu",Ce="registerPasskey-module__description___AWmO-",Te="registerPasskey-module__button___D3b4B",Oe="registerPasskey-module__message___RiOw-",Le="registerPasskey-module__success___HP5aX",Ie="registerPasskey-module__error___hGiqE";C(".registerPasskey-module__container___jqEh8{align-items:center;color:#fff;display:flex;justify-content:center;padding:1rem}.registerPasskey-module__card___MJAyC{background-color:#1f2937;border-radius:1rem;box-shadow:0 4px 20px rgba(0,0,0,.4);max-width:400px;padding:1.5rem;width:100%}.registerPasskey-module__loading___Q4i1x{align-items:center;background-color:#f9fafb;border-radius:.75rem;box-shadow:0 2px 8px rgba(0,0,0,.1);color:#374151;display:flex;font-weight:500;gap:.75rem;justify-content:center;padding:1.5rem}.registerPasskey-module__spinner___V1nhd{animation:registerPasskey-module__spin___oYcsC 1s linear infinite;border-color:#3b82f6 transparent;border-radius:9999px;border-style:solid;border-width:2px;height:1.5rem;width:1.5rem}@keyframes registerPasskey-module__spin___oYcsC{to{transform:rotate(1turn)}}.registerPasskey-module__supported___ihTih{background-color:#ecfdf5;border-radius:.75rem;box-shadow:0 2px 12px rgba(0,0,0,.1);color:#065f46;padding:1.25rem}.registerPasskey-module__title___vn2Qu{font-size:1.125rem;font-weight:600;margin-bottom:.5rem}.registerPasskey-module__description___AWmO-{margin-bottom:1rem}.registerPasskey-module__button___D3b4B{background-color:#059669;border:none;border-radius:.5rem;color:#fff;cursor:pointer;font-weight:500;padding:.75rem 1rem;transition:background-color .2s ease;width:100%}.registerPasskey-module__button___D3b4B:hover{background-color:#047857}.registerPasskey-module__message___RiOw-{font-size:.875rem;margin-top:1rem}.registerPasskey-module__success___HP5aX{color:#6ee7b7}.registerPasskey-module__error___hGiqE{color:#f87171}");const Ee=()=>{const{apiHost:r,mode:t}=N(),{validateToken:n}=w(),s=d(),[l,c]=i("idle"),[_,m]=i(""),[u,p]=i(!1),f=k({authMode:t,authHost:r}),y=async(e,o)=>{try{const r=await f("/webAuthn/register/finish",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({attestationResponse:e,metadata:o}),credentials:"include"}),t=await r.json();if(!r.ok)return c("error"),void m("Something went wrong registering passkey.");t?.verified&&await n()}catch(e){console.error(`An error occurred: ${e}`)}};return a(()=>{!async function(){const e=await oe();p(e)}()},[]),e("div",{className:we,children:e("div",{className:ke,children:u?u&&o("div",{className:Ne,children:[e("h2",{className:Se,children:"Secure Your Account with a Passkey"}),e("p",{className:Ce,children:"Your device supports passkeys! Register one to skip passwords forever."}),e("button",{onClick:async()=>{c("loading");const e=prompt("Name this device (e.g., 'MacBook Pro', 'iPhone', 'YubiKey')"),{platform:o,browser:r,deviceInfo:t}=function(){const e=navigator.userAgent.toLowerCase();let o="unknown",r="unknown";return/iphone|ipad|ipod/.test(e)?o="ios":/android/.test(e)?o="android":/mac os/.test(e)?o="mac":/windows/.test(e)?o="windows":/linux/.test(e)&&(o="linux"),/chrome/.test(e)&&(r="chrome"),/safari/.test(e)&&!/chrome/.test(e)&&(r="safari"),/firefox/.test(e)&&(r="firefox"),/edg/.test(e)&&(r="edge"),{platform:o,browser:r,deviceInfo:`${o} • ${r}`}}();try{const n=await f("/webAuthn/register/start",{method:"GET",headers:{"Content-Type":"application/json"},credentials:"include"});if(!n.ok)return c("error"),void m("Something went wrong registering passkey.");const i=await n.json();let a;try{a=await g({optionsJSON:i}),await y(a,{friendlyName:e,platform:o,browser:r,deviceInfo:t})}catch(e){return void(e instanceof h?(console.error(`Error occurred with webAuthn, ${e.name} - ${e.code}-${e.stack}`),c("error"),m(`Error: ${e.name}`)):(console.error("A problem happened.",e),c("error"),m(`Error: ${e}`)))}c("success"),m("Passkey registered successfully."),s("/")}catch(e){console.error(e),c("error"),m("Something went wrong registering passkey.")}},disabled:"loading"===l,className:Te,children:"loading"===l?"Registering...":"Register Passkey"}),_&&e("p",{className:`${Oe} ${"success"===l?Le:Ie}`,children:_})]}):o("div",{className:xe,children:[e("div",{className:Pe}),e("span",{children:"Checking for Passkey Support..."})]})})})};var Me="verifyOTP-module__container___wgoDE",je="verifyOTP-module__card___3cs2p",Ae="verifyOTP-module__title___fZ-1d",Fe="verifyOTP-module__subtitle___dGSu3",Be="verifyOTP-module__error___GEtlG",ze="verifyOTP-module__success___46TjG",Ge="verifyOTP-module__form___jiGG-",Ve="verifyOTP-module__label___Zq5Mi",$e="verifyOTP-module__timer___smq-a",qe="verifyOTP-module__input___yqIXM",Re="verifyOTP-module__resend___PlmkG",Ue="verifyOTP-module__button___8pIuO",De="verifyOTP-module__toggle___wbzVa";C(".verifyOTP-module__container___wgoDE{align-items:center;color:#fff;display:flex;justify-content:center;padding:1rem}.verifyOTP-module__card___3cs2p{background-color:#1f2937;border-radius:.5rem;box-shadow:0 0 10px rgba(0,0,0,.3);max-width:28rem;padding:1.5rem;width:100%}.verifyOTP-module__title___fZ-1d{color:#fff;font-size:1.5rem;font-weight:700;margin-bottom:1rem;text-align:center}.verifyOTP-module__subtitle___dGSu3{color:#9ca3af;font-size:.875rem;margin-bottom:1.5rem;text-align:center}.verifyOTP-module__error___GEtlG{color:#f87171;margin-bottom:1rem;text-align:center}.verifyOTP-module__success___46TjG{color:#34d399;margin-bottom:.75rem;text-align:center}.verifyOTP-module__form___jiGG-{display:flex;flex-direction:column;gap:1rem}.verifyOTP-module__label___Zq5Mi{color:#d1d5db;display:block;font-size:.875rem;margin-bottom:.25rem}.verifyOTP-module__timer___smq-a{color:#facc15;font-size:.875rem}.verifyOTP-module__input___yqIXM{background-color:#374151;border:1px solid #4b5563;border-radius:.375rem;color:#fff;outline:none;padding:.5rem;width:100%}.verifyOTP-module__input___yqIXM:focus{box-shadow:0 0 0 2px #3b82f6}.verifyOTP-module__resend___PlmkG{background:none;border:none;color:#60a5fa;cursor:pointer;font-size:.75rem;margin-top:.25rem;text-decoration:underline}.verifyOTP-module__resend___PlmkG:hover{color:#3b82f6}.verifyOTP-module__button___8pIuO{background-color:#2563eb;border:none;border-radius:.375rem;color:#fff;cursor:pointer;padding:.5rem;transition:background-color .2s;width:100%}.verifyOTP-module__button___8pIuO:hover{background-color:#1d4ed8}.verifyOTP-module__toggle___wbzVa{background:none;border:none;color:#60a5fa;cursor:pointer;font-size:.875rem;margin-top:1.5rem;text-align:center;width:100%}");const Je=()=>{const r=d(),{apiHost:t,mode:n}=N(),[s,l]=i(""),[c,_]=i(""),[m,u]=i(null),[g,h]=i(null),[p,f]=i(""),[y,b]=i(!1),[v,w]=i(""),[x,P]=i(300),[S,C]=i(300),T=k({authMode:n,authHost:t}),O=async()=>{b(!0);try{if(!m){(await T("/otp/verify-phone-otp",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({verificationToken:c}),credentials:"include"})).ok?u(!0):f("Verification failed.")}}catch(e){console.error(e),f("Verification failed.")}b(!1)},L=async()=>{b(!0);try{if(!g){(await T("/otp/verify-email-otp",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({verificationToken:s}),credentials:"include"})).ok?h(!0):f("Verification failed.")}}catch(e){console.error(e),f("Verification failed.")}b(!1)},I=e=>{w(""),"email"===e?((async()=>{f("");const e=await T("/otp/generate-email-otp",{method:"GET",headers:{"Content-Type":"application/json"}}),o=await e.json();e.ok?(w("Verification email has been resent."),o.token&&localStorage.setItem("token",o.token)):f("Failed to send Email code. If this persists, refresh the page and try again.")})(),w("Verification email has been resent.")):((async()=>{f("");const e=await T("/otp/generate-phone-otp",{method:"GET",headers:{"Content-Type":"application/json"}}),o=await e.json();e.ok?(o.token&&localStorage.setItem("token",o.token),w("Verification SMS has been resent.")):f("Failed to send SMS code. If this persists, refresh the page and try again.")})(),w("Verification SMS has been resent."))},E=o=>!0===o?e("span",{className:"text-green-400 ml-2",children:"✅"}):!1===o?e("span",{className:"text-red-400 ml-2",children:"❌"}):null,M=e=>`${Math.floor(e/60).toString().padStart(2,"0")}:${(e%60).toString().padStart(2,"0")}`;return a(()=>{const e=setInterval(()=>{P(e=>e>0?e-1:0)},1e3);return()=>clearInterval(e)},[]),a(()=>{const e=setInterval(()=>{C(e=>e>0?e-1:0)},1e3);return()=>clearInterval(e)},[]),a(()=>{g&&m&&r("/registerPasskey")},[g,m,r]),e("div",{className:Me,children:o("div",{className:je,children:[e("h2",{className:Ae,children:"Verify Your Contact Info"}),e("p",{className:Fe,children:"Enter the codes sent to your email and phone number."}),p&&e("p",{className:Be,children:p}),v&&e("p",{className:ze,children:v}),o("form",{onSubmit:async e=>{if(e.preventDefault(),f(""),6===s.length)if(6===c.length){b(!0);try{L(),O()}catch{f("Unexpected error occurred.")}finally{b(!1)}}else f("Please enter a valid code.");else f("Please enter a valid code.")},className:Ge,children:[o("div",{children:[o("label",{htmlFor:"emailCode",className:Ve,children:["Email Verification Code ",E(g)," -"," ",o("span",{className:$e,children:["Code expires in: ",M(x)]})]}),e("input",{id:"emailCode",type:"text",maxLength:6,value:s,autoComplete:"off",onChange:e=>{l(e.target.value),h(null)},className:qe,required:!0}),e("button",{type:"button",onClick:()=>I("email"),className:Re,children:"Resend code to email"})]}),o("div",{children:[o("label",{htmlFor:"phoneCode",className:Ve,children:["Phone Verification Code ",E(m)," -"," ",o("span",{className:$e,children:["Code expires in: ",M(S)]})]}),e("input",{id:"phoneCode",type:"text",maxLength:6,pattern:"\\d{6}",inputMode:"numeric",value:c,autoComplete:"off",onChange:e=>{_(e.target.value),u(null)},className:qe,required:!0}),e("button",{type:"button",onClick:()=>I("phone"),className:Re,children:"Resend code to phone"})]}),e("button",{type:"submit",className:Ue,children:y?"Verifying...":"Verify & Continue"}),e("button",{type:"button",onClick:()=>r("/login"),className:De,children:"Back to login"})]})]})})},Ke=()=>o(c,{children:[e(_,{path:"/login",element:e(re,{})}),e(_,{path:"/passKeyLogin",element:e(ve,{})}),e(_,{path:"/mfaLogin",element:e(he,{})}),e(_,{path:"/verifyOTP",element:e(Je,{})}),e(_,{path:"/registerPasskey",element:e(Ee,{})}),e(_,{path:"*",element:e(m,{to:"/login",replace:!0})})]});export{S as AuthProvider,Ke as AuthRoutes,N as useAuth};
|
|
1
|
+
import{jsx as e,jsxs as o,Fragment as r}from"react/jsx-runtime";import{createContext as t,useContext as n,useState as i,useEffect as a,useCallback as s,useRef as l}from"react";import{useNavigate as d,Routes as c,Route as _,Navigate as m}from"react-router-dom";import{startAuthentication as u,startRegistration as g,WebAuthnError as h}from"@simplewebauthn/browser";import p,{AsYouType as f,parsePhoneNumberFromString as y}from"libphonenumber-js";const b=t(void 0),v=({value:o,children:r})=>e(b.Provider,{value:o,children:r}),w=()=>{const e=n(b);if(!e)throw new Error("useInternalAuth must be used within InternalAuthProvider");return e},k=e=>{const{authMode:o,authHost:r}=e;return async function(e,t){const n=`${r}${"server"===o?"auth":""}${e.startsWith("/")?e:`/${e}`}`,i={...t,credentials:"include",headers:{"Content-Type":"application/json",...t?.headers}},a=await fetch(n,i);if(a.ok)return a;throw console.warn("Auth fetch failed:",a.status,n),new Error(`Failed to make API call to ${n}`)}},x=()=>e("div",{className:"flex items-center justify-center min-h-screen bg-gray-900",children:e("div",{"data-testid":"loading",className:"w-12 h-12 border-4 border-gray-600 border-t-blue-500 rounded-full animate-spin"})});const P=t(void 0),N=()=>{const e=n(P);if(!e)throw new Error("useAuth must be used within an AuthProvider");return e},S=({children:r,apiHost:t,autoDetectPreviousSignin:n=!0,mode:l="web"})=>{const[d,c]=i(null),[_,m]=i([]),[u,g]=i(!1),[h,p]=i(!0),[f,y]=i(null),{hasSignedInBefore:b,markSignedIn:w}=function(e="seamlessauth_seen"){const[o,r]=i(!1);return a(()=>{try{"true"===localStorage.getItem(e)&&r(!0)}catch{}},[e]),{hasSignedInBefore:o,markSignedIn:()=>{try{localStorage.setItem(e,"true"),r(!0)}catch{}}}}(),[N]=i(l),S=k({authMode:N,authHost:t}),C=s(async()=>{if(d)try{await S("/logout",{method:"GET"})}catch{console.error("Error during logout")}finally{g(!1),c(null),y(null)}},[S,d]),T=async()=>{try{const e=await S("users/me",{method:"GET"});if(e.ok){const{user:o,credentials:r}=await e.json();c(o),m(r),g(!0)}else C()}catch{C()}finally{p(!1)}};return a(()=>{T()},[]),a(()=>{d&&u&&w()},[d,u,w]),h?o("div",{className:"min-h-screen flex items-center justify-center bg-gray-100",children:[e(x,{}),";"]}):e(P.Provider,{value:{user:d,logout:C,deleteUser:async()=>{try{if((await S("/users/delete",{method:"delete"})).ok)return c(null),g(!1),void y(null);throw new Error("Could not delete user.")}catch(e){throw console.error("Something went wrong deleting user:",e),new Error("Could not delete user.")}},isAuthenticated:u,hasRole:e=>d?.roles?.includes(e),apiHost:t,token:f,markSignedIn:w,hasSignedInBefore:!!n&&b,mode:l,credentials:_,updateCredential:async e=>{const o=await S("users/credentials",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({friendlyName:e.friendlyName,id:e.id})});if(o.ok)return o.json();throw new Error("Failed to update credential")},deleteCredential:async e=>{const o=await S("users/credentials",{method:"DELETE",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:e})});if(o.ok)return o.json();throw new Error("Failed to update credential")}},children:e(v,{value:{validateToken:T,setLoading:p},children:r})})};function C(e,o){void 0===o&&(o={});var r=o.insertAt;if(e&&"undefined"!=typeof document){var t=document.head||document.getElementsByTagName("head")[0],n=document.createElement("style");n.type="text/css","top"===r&&t.firstChild?t.insertBefore(n,t.firstChild):t.appendChild(n),n.styleSheet?n.styleSheet.cssText=e:n.appendChild(document.createTextNode(e))}}var T="login-module__container___YggDx",O="login-module__card___Ub-Py",L="login-module__heading___neEqb",I="login-module__message___qSejT",M="login-module__inputGroup___P6qgS",E="login-module__label___mx5vu",j="login-module__input___U07lW",A="login-module__helperText___kDQ4-",F="login-module__error___40zxh",B="login-module__button___0kFBs",z="login-module__toggle___1JiG1",G="login-module__underline___gs-RS",V="login-module__phoneRow___oeNtq",$="login-module__select___rRV1O",q="login-module__phoneInput___2MPQC";C(".login-module__container___YggDx{align-items:center;color:#fff;display:flex;justify-content:center}.login-module__card___Ub-Py{background-color:#1f2937;border-radius:.5rem;box-shadow:0 4px 6px rgba(0,0,0,.1);max-width:28rem;padding:2rem;width:100%}.login-module__heading___neEqb{color:#fff;font-size:1.5rem;font-weight:700;margin-bottom:1.5rem;text-align:center}.login-module__message___qSejT{color:#68d391;text-align:center}.login-module__inputGroup___P6qgS{margin-bottom:1rem}.login-module__label___mx5vu{color:#d1d5db;display:block}.login-module__input___U07lW{background-color:#4b5563;border:1px solid #d1d5db;border-radius:.375rem;margin-top:.25rem;padding:.5rem;width:100%}.login-module__input___U07lW:focus{box-shadow:0 0 0 2px #3b82f6;outline:none}.login-module__helperText___kDQ4-{color:#9ca3af;font-size:.75rem;margin-top:.5rem}.login-module__error___40zxh{color:#f87171;font-size:.875rem}.login-module__button___0kFBs{background-color:#2563eb;border-radius:.375rem;color:#fff;cursor:pointer;margin-top:1rem;padding:.5rem;transition:background-color .3s;width:100%}.login-module__button___0kFBs:hover{background-color:#1d4ed8}.login-module__button___0kFBs:disabled{background-color:#9ca3af;cursor:not-allowed}.login-module__toggle___1JiG1{background:none;border:none;color:#60a5fa;cursor:pointer;font-size:.875rem;margin-top:1.5rem;text-align:center;width:100%}.login-module__underline___gs-RS{text-decoration:underline}.login-module__phoneRow___oeNtq{display:grid;gap:.5rem;grid-template-columns:1fr 3fr;margin-top:.25rem}.login-module__phoneInput___2MPQC,.login-module__select___rRV1O{background-color:#4b5563;border:1px solid #d1d5db;border-radius:.375rem;padding:.5rem;width:100%}@media (max-width:500px){.login-module__phoneRow___oeNtq{grid-template-columns:1fr}}");var R="termsModal-module__overlay___-j6r5",U="termsModal-module__modal___4PxZV",D="termsModal-module__header___B7wxb",J="termsModal-module__title___Sucwt",K="termsModal-module__closeBtn___evIs5",W="termsModal-module__content___5BDhN",H="termsModal-module__link___oPZrU";C(".termsModal-module__overlay___-j6r5{align-items:center;background-color:rgba(0,0,0,.7);display:flex;inset:0;justify-content:center;position:fixed;z-index:999}.termsModal-module__modal___4PxZV{background-color:#1a1a1a;border-radius:8px;box-shadow:0 10px 25px rgba(0,0,0,.4);color:#fff;max-height:80vh;max-width:640px;outline:none;overflow-y:auto;padding:24px;width:100%}.termsModal-module__header___B7wxb{align-items:center;display:flex;justify-content:space-between;margin-bottom:16px}.termsModal-module__title___Sucwt{color:#60a5fa;font-size:1.25rem;font-weight:700}.termsModal-module__closeBtn___evIs5{background:none;border:none;color:#ccc;cursor:pointer;font-size:1.75rem}.termsModal-module__closeBtn___evIs5:hover{color:#fff}.termsModal-module__content___5BDhN{color:#d1d5db;font-size:.9rem;line-height:1.6}.termsModal-module__link___oPZrU{color:#60a5fa;text-decoration:underline}.termsModal-module__link___oPZrU:hover{text-decoration:none}");const Z=({isOpen:r,onClose:t})=>{const n=l(null);return a(()=>{const e=e=>{"Escape"===e.key&&t()};return r&&(document.addEventListener("keydown",e),n.current?.focus()),()=>{document.removeEventListener("keydown",e)}},[r,t]),r?e("div",{className:R,role:"dialog","aria-modal":"true","aria-labelledby":"terms-title",children:o("div",{className:U,tabIndex:-1,ref:n,children:[o("div",{className:D,children:[e("h2",{id:"terms-title",className:J,children:"SMS Terms & Conditions"}),e("button",{onClick:t,className:K,children:"×"})]}),o("div",{className:W,children:[o("p",{children:[e("strong",{children:"Effective Date:"})," June 01, 2025"]}),e("p",{children:"By providing your phone number to SeamlessAuth, a Fells Code LLC product, you agree to receive SMS messages for identity verification, authentication, and account security."}),o("p",{children:[e("strong",{children:"1. Purpose:"})," SMS is used only for account security (OTP, MFA). No marketing messages."]}),o("p",{children:[e("strong",{children:"2. Frequency:"})," Based on login and account activity."]}),o("p",{children:[e("strong",{children:"3. Opt-Out:"})," Contact support@seamlessauth.com to opt out."]}),o("p",{children:[e("strong",{children:"4. Fees:"})," Message and data rates may apply."]}),o("p",{children:[e("strong",{children:"5. Supported Carriers:"})," Most major providers supported, delivery not guaranteed."]}),o("p",{children:[e("strong",{children:"6. Privacy:"})," Your phone number is not shared or sold. See our Privacy Policy."]}),o("p",{children:[e("strong",{children:"7. Changes:"})," Terms may be updated with notice on this page."]}),o("p",{children:["Questions? Email us at"," ",e("a",{className:H,href:"mailto:support@seamlessauth.com",children:"support@seamlessauth.com"}),"."]})]})]})}):null},Y=[{code:"US",name:"United States",dialCode:"+1",flag:"🇺🇸"},{code:"CA",name:"Canada",dialCode:"+1",flag:"🇨🇦"},{code:"GB",name:"United Kingdom",dialCode:"+44",flag:"🇬🇧"},{code:"IN",name:"India",dialCode:"+91",flag:"🇮🇳"},{code:"AU",name:"Australia",dialCode:"+61",flag:"🇦🇺"}];function Q({phone:r,setPhone:t,phoneError:n,setPhoneError:s}){const[l,d]=i(!1),[c,_]=i(Y[0]);a(()=>{const e=function(){try{const e=Intl.DateTimeFormat().resolvedOptions().locale||"en-US",o=e.split("-")[1]?.toUpperCase()||"US";return Y.find(e=>e.code===o)||Y[0]}catch{return Y[0]}}();_(e)},[]);return o("div",{className:M,children:[e("label",{id:"phone",className:E,children:"Phone Number"}),o("div",{className:V,children:[e("select",{value:c.code,onChange:e=>{const o=Y.find(o=>o.code===e.target.value);if(o){_(o);const e=r.replace(/^\+\d+/,""),n=(new f).input(o.dialCode+e);t(n)}},className:$,children:Y.map(e=>o("option",{value:e.code,children:[e.flag," (",e.dialCode,")"]},e.code))}),e("input",{"aria-labelledby":"phone",type:"tel",value:r,onChange:e=>{const o=e.target.value,r=o.startsWith(c.dialCode)?o:c.dialCode+o,i=(new f).input(r);t(i),n&&s("")},onBlur:()=>{if(r){const e=y(r),o=e?.isValid();s(o?"":"Please enter a valid phone number.")}},autoComplete:"off",placeholder:"(555) 123-4567",className:q})]}),o("p",{className:A,children:["By signing up, you agree to our"," ",e("button",{onClick:()=>d(!0),className:G,children:"SMS Terms & Conditions"}),"."]}),n&&e("p",{className:F,children:n}),e(Z,{isOpen:l,onClose:()=>d(!1)})]})}const X=e=>{if("string"!=typeof e)return!1;const o=e.trim();if(o.length<3||o.length>320)return!1;const r=o.split("@");if(2!==r.length)return!1;const[t,n]=r;return!(!/^[A-Za-z0-9._%+-]+$/.test(t)||t.startsWith(".")||t.endsWith(".")||t.includes(".."))&&!(!/^[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/.test(n)||n.startsWith("-")||n.endsWith("-")||n.startsWith(".")||n.endsWith(".")||n.includes(".."))},ee=e=>{const o=p(e);return o?.isValid()||!1};async function oe(){if(window.PublicKeyCredential&&"function"==typeof window.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable)try{return await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()}catch(e){return console.error("Error checking passkey support:",e),!1}return!1}const re=()=>{const t=d(),{apiHost:n,hasSignedInBefore:s,mode:l}=N(),{validateToken:c}=w(),[_,m]=i(""),[g,h]=i(""),[p,f]=i("register"),[y,b]=i(""),[v,x]=i(""),[P,S]=i(""),[C,G]=i(""),[V,$]=i(""),[q,R]=i(!1),U=k({authMode:l,authHost:n});a(()=>{!async function(){const e=await oe();R(e)}(),s&&f("login")},[s]);const D=async()=>{x("");try{if(!(await U("/login",{method:"POST",body:JSON.stringify({identifier:_,passkeyAvailable:q})})).ok)return void x("Failed to send login link. Please try again.");await(async()=>{try{const e=await U("/webAuthn/login/start",{method:"POST"});if(!e.ok)return void console.error("Something went wrong getting webauthn options");const o=await e.json(),r=await u({optionsJSON:o}),n=await U("/webAuthn/login/finish",{method:"POST",body:JSON.stringify({assertionResponse:r})});n.ok||console.error("Failed to verify passkey");const i=await n.json();if("Success"===i.message)return i.mfaLogin?void t("/mfaLogin"):(await c(),void t("/"));console.error("Passkey login failed:",i.message)}catch(e){console.error("Passkey login error:",e)}})()}catch(e){console.error("Unexpected login error",e),x("An unexpected error occured. Try again. If the problem persists, try resetting your password")}};return e("div",{className:T,children:o("div",{className:O,children:[e("h2",{className:L,children:"login"===p?"Sign In":"Create Account"}),q?e(r,{children:o("form",{onSubmit:async e=>{e.preventDefault(),"login"===p&&D(),"register"===p&&(async()=>{x("");try{const e=await U("/registration/register",{method:"POST",body:JSON.stringify({email:g,phone:y})});if(!e.ok)return void x("Failed to register. Please try again.");"Success"===(await e.json()).message&&t("/verifyOTP"),x("An unexpected error occured. Try again. If the problem persists, try resetting your password")}catch(e){console.error("Unexpected login error",e),x("An unexpected error occured. Try again. If the problem persists, try resetting your password")}})()},children:["login"===p&&o("div",{className:M,children:[e("label",{htmlFor:"identifier",className:E,children:"Email Address / Phone Number"}),e("input",{id:"identifier",type:"text",value:_,onChange:e=>{const o=e.target.value;m(o)},autoComplete:"off",placeholder:"Email or Phone Number",className:j,onBlur:()=>{if(_){const e=X(_)||ee(_);$(e?"":"Please enter a valid email or phone number")}},required:!0}),e("p",{className:A,children:"Phone numbers must include a country code e.g. +1"}),V&&e("p",{className:F,children:V})]}),"register"===p&&o(r,{children:[o("div",{className:M,children:[e("label",{htmlFor:"email",className:E,children:"Email Address"}),e("input",{id:"email",type:"email",value:g,onChange:e=>{const o=e.target.value;h(o)},autoComplete:"off",className:j,onBlur:()=>{if(g){const e=X(g);G(e?"":"Please enter a valid email")}},required:!0}),C&&e("p",{className:F,children:C})]}),e(Q,{phone:y,setPhone:b,phoneError:P,setPhoneError:S})]}),e("button",{type:"submit",className:B,disabled:!("login"===p&&_?X(_)||ee(_):X(g)&&ee(y)),children:"login"===p?"Login":"Register"}),v&&e("p",{className:F,children:v}),e("button",{type:"button",onClick:()=>f("login"===p?"register":"login"),className:z,children:"login"===p?"Don't have an account? Create one":"Already have an account? Sign in"})]})}):e("p",{className:I,children:"❌ This device doesn't support passkey login. You must provide or register a passkey."})]})})};var te="mfaLogin-module__container___CDMP9",ne="mfaLogin-module__card___kWS58",ie="mfaLogin-module__title___dZABE",ae="mfaLogin-module__msg___2lh2D",se="mfaLogin-module__buttonGroup___3Corm",le="mfaLogin-module__button___4X2WF",de="mfaLogin-module__selected___lkiW-",ce="mfaLogin-module__codeLabel___iC4bk",_e="mfaLogin-module__countdown___rgtkd",me="mfaLogin-module__input___JP-RF",ue="mfaLogin-module__submit___n4-FT",ge="mfaLogin-module__error___SqfpH";C(".mfaLogin-module__container___CDMP9{align-items:center;color:#fff;display:flex;justify-content:center;padding:1rem}.mfaLogin-module__card___kWS58{background-color:#1f2937;border-radius:1rem;box-shadow:0 4px 20px rgba(0,0,0,.4);display:flex;flex-direction:column;gap:1.5rem;max-width:400px;padding:1.5rem;width:100%}.mfaLogin-module__title___dZABE{color:#fff;font-size:1.5rem;font-weight:600;text-align:center}.mfaLogin-module__msg___2lh2D{color:#4ade80;text-align:center}.mfaLogin-module__buttonGroup___3Corm{display:flex;flex-direction:column;gap:1rem}.mfaLogin-module__button___4X2WF{background-color:#374151;border:1px solid #4b5563;border-radius:.5rem;color:#fff;font-weight:500;padding:.75rem 1rem;text-align:left;transition:background-color .2s}.mfaLogin-module__button___4X2WF:hover{background-color:#4b5563}.mfaLogin-module__selected___lkiW-{background-color:#2563eb;border-color:#3b82f6}.mfaLogin-module__codeLabel___iC4bk{display:block;font-size:.875rem;font-weight:500;margin-bottom:.25rem}.mfaLogin-module__countdown___rgtkd{color:#facc15;font-size:.875rem}.mfaLogin-module__input___JP-RF{background-color:#374151;border:1px solid #4b5563;border-radius:.5rem;color:#fff;font-family:monospace;font-size:1.25rem;letter-spacing:.2em;padding:.75rem 1rem;width:100%}.mfaLogin-module__input___JP-RF:focus{border-color:#3b82f6;box-shadow:0 0 0 2px #3b82f6;outline:none}.mfaLogin-module__submit___n4-FT{background-color:#2563eb;border:1px solid #3b82f6;border-radius:.5rem;color:#fff;cursor:pointer;font-weight:500;padding:.75rem 1rem;transition:background-color .2s}.mfaLogin-module__submit___n4-FT:disabled{background-color:#9ca3af;cursor:not-allowed}.mfaLogin-module__error___SqfpH{color:#f87171;margin-bottom:.5rem;text-align:center}@media (max-width:480px){.mfaLogin-module__card___kWS58{padding:1rem}.mfaLogin-module__input___JP-RF,.mfaLogin-module__submit___n4-FT{font-size:1rem}}");const he=()=>{const{apiHost:t,mode:n}=N(),{validateToken:s}=w(),l=d(),[c,_]=i(""),[m,u]=i(""),[g,h]=i(!1),[p,f]=i(""),[y,b]=i(300),[v,x]=i(null),P=k({authMode:n,authHost:t}),S=async()=>{const e="phone"===v?"otp/verify-login-phone-otp":"otp/verify-login-email-otp";try{if(!(await P(`/${e}`,{method:"POST",body:JSON.stringify({verificationToken:c})})).ok)return void u("Verification failed.");await s(),l("/")}catch(e){console.error("Error verifying OTP",e),u("Verification failed.")}},C=async e=>{u("");const o="phone"===e?"otp/generate-login-phone-otp":"otp/generate-login-email-otp";try{(await P(`/${o}`,{method:"GET"})).ok?f(`Verification ${"phone"===e?"SMS":"email"} has been sent.`):u(`Failed to send ${e} code. If this persists, refresh the page and try again.`)}catch{u(`Failed to send ${e} code. If this persists, refresh the page and try again.`)}};return a(()=>{const e=setInterval(()=>{b(e=>e>0?e-1:0)},1e3);return()=>clearInterval(e)},[]),e("div",{className:te,children:o("div",{className:ne,children:[e("h2",{className:ie,children:"Multi-factor Authentication"}),p&&e("p",{className:ae,children:p}),o("div",{className:se,children:[o("button",{onClick:()=>{x("phone"),C("phone")},className:`${le} ${"phone"===v?de:""}`,children:["Send code to phone: ",e("span",{className:"font-mono",children:"****1234"})]}),o("button",{onClick:()=>{x("email"),C("email")},className:`${le} ${"email"===v?de:""}`,children:["Send code to email: ",e("span",{className:"font-mono",children:"j***@example.com"})]})]}),v&&o(r,{children:[m&&e("p",{className:ge,children:m}),o("label",{htmlFor:"otp",className:ce,children:["Enter the 6-digit code sent to your ",v,". ",e("br",{}),o("span",{className:_e,children:["Code expires in: ",(T=y,`${Math.floor(T/60).toString().padStart(2,"0")}:${(T%60).toString().padStart(2,"0")}`)]})]}),e("input",{id:"otp",type:"text",maxLength:6,className:me,placeholder:"••••••",onChange:e=>_(e.target.value)}),e("button",{onClick:async e=>{e.preventDefault(),u(""),h(!0);try{await S()}catch{u("Unexpected error occurred.")}finally{h(!1)}},className:ue,disabled:!c||c.length<6||g,children:g?"Verifying...":"Verify"})]})]})});var T};var pe="passKeyLogin-module__container___IUKxF",fe="passKeyLogin-module__card___2sKM1",ye="passKeyLogin-module__title___HZxvc",be="passKeyLogin-module__button___FvR4I";C(".passKeyLogin-module__container___IUKxF{align-items:center;color:#fff;display:flex;justify-content:center;padding:1rem}.passKeyLogin-module__card___2sKM1{background-color:#1f2937;border-radius:1rem;box-shadow:0 4px 20px rgba(0,0,0,.4);display:flex;flex-direction:column;gap:1.5rem;max-width:400px;padding:2rem;width:100%}.passKeyLogin-module__title___HZxvc{color:#fff;font-size:1.5rem;font-weight:600;text-align:center}.passKeyLogin-module__button___FvR4I{background-color:#2563eb;border:1px solid #3b82f6;border-radius:.5rem;color:#fff;cursor:pointer;font-weight:500;padding:.75rem 1rem;text-align:center;transition:background-color .2s ease;width:100%}.passKeyLogin-module__button___FvR4I:hover{background-color:#1d4ed8}@media (max-width:480px){.passKeyLogin-module__card___2sKM1{padding:1.25rem}.passKeyLogin-module__button___FvR4I{font-size:1rem}}");const ve=()=>{const r=d(),{apiHost:t,mode:n}=N(),{validateToken:i}=w(),a=k({authMode:n,authHost:t});return e("div",{className:pe,children:o("div",{className:fe,children:[e("h2",{className:ye,children:"Login with Passkey"}),e("button",{onClick:async()=>{try{const e=await a("/webAuthn/login/start",{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include"});if(!e.ok)return void console.error("Something went wrong getting webauthn options");const o=await e.json(),t=await u({optionsJSON:o}),n=await a("/webAuthn/login/finish",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({assertionResponse:t}),credentials:"include"});n.ok||console.error("Failed to verify passkey");const s=await n.json();if("Success"===s.message)return s.mfaLogin&&r("/mfaLogin"),await i(),void r("/");console.error("Passkey login failed")}catch{console.error("Passkey login error")}},className:be,children:"Use Passkey"})]})})};var we="registerPasskey-module__container___jqEh8",ke="registerPasskey-module__card___MJAyC",xe="registerPasskey-module__loading___Q4i1x",Pe="registerPasskey-module__spinner___V1nhd",Ne="registerPasskey-module__supported___ihTih",Se="registerPasskey-module__title___vn2Qu",Ce="registerPasskey-module__description___AWmO-",Te="registerPasskey-module__button___D3b4B",Oe="registerPasskey-module__message___RiOw-",Le="registerPasskey-module__success___HP5aX",Ie="registerPasskey-module__error___hGiqE";C(".registerPasskey-module__container___jqEh8{align-items:center;color:#fff;display:flex;justify-content:center;padding:1rem}.registerPasskey-module__card___MJAyC{background-color:#1f2937;border-radius:1rem;box-shadow:0 4px 20px rgba(0,0,0,.4);max-width:400px;padding:1.5rem;width:100%}.registerPasskey-module__loading___Q4i1x{align-items:center;background-color:#f9fafb;border-radius:.75rem;box-shadow:0 2px 8px rgba(0,0,0,.1);color:#374151;display:flex;font-weight:500;gap:.75rem;justify-content:center;padding:1.5rem}.registerPasskey-module__spinner___V1nhd{animation:registerPasskey-module__spin___oYcsC 1s linear infinite;border-color:#3b82f6 transparent;border-radius:9999px;border-style:solid;border-width:2px;height:1.5rem;width:1.5rem}@keyframes registerPasskey-module__spin___oYcsC{to{transform:rotate(1turn)}}.registerPasskey-module__supported___ihTih{background-color:#ecfdf5;border-radius:.75rem;box-shadow:0 2px 12px rgba(0,0,0,.1);color:#065f46;padding:1.25rem}.registerPasskey-module__title___vn2Qu{font-size:1.125rem;font-weight:600;margin-bottom:.5rem}.registerPasskey-module__description___AWmO-{margin-bottom:1rem}.registerPasskey-module__button___D3b4B{background-color:#059669;border:none;border-radius:.5rem;color:#fff;cursor:pointer;font-weight:500;padding:.75rem 1rem;transition:background-color .2s ease;width:100%}.registerPasskey-module__button___D3b4B:hover{background-color:#047857}.registerPasskey-module__message___RiOw-{font-size:.875rem;margin-top:1rem}.registerPasskey-module__success___HP5aX{color:#6ee7b7}.registerPasskey-module__error___hGiqE{color:#f87171}");const Me=()=>{const{apiHost:r,mode:t}=N(),{validateToken:n}=w(),s=d(),[l,c]=i("idle"),[_,m]=i(""),[u,p]=i(!1),f=k({authMode:t,authHost:r}),y=async(e,o)=>{try{const r=await f("/webAuthn/register/finish",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({attestationResponse:e,metadata:o}),credentials:"include"}),t=await r.json();if(!r.ok)return c("error"),void m("Something went wrong registering passkey.");t?.verified&&await n()}catch(e){console.error(`An error occurred: ${e}`)}};return a(()=>{!async function(){const e=await oe();p(e)}()},[]),e("div",{className:we,children:e("div",{className:ke,children:u?u&&o("div",{className:Ne,children:[e("h2",{className:Se,children:"Secure Your Account with a Passkey"}),e("p",{className:Ce,children:"Your device supports passkeys! Register one to skip passwords forever."}),e("button",{onClick:async()=>{c("loading");const e=prompt("Name this device (e.g., 'MacBook Pro', 'iPhone', 'YubiKey')"),{platform:o,browser:r,deviceInfo:t}=function(){const e=navigator.userAgent.toLowerCase();let o="unknown",r="unknown";return/iphone|ipad|ipod/.test(e)?o="ios":/android/.test(e)?o="android":/mac os/.test(e)?o="mac":/windows/.test(e)?o="windows":/linux/.test(e)&&(o="linux"),/chrome/.test(e)&&(r="chrome"),/safari/.test(e)&&!/chrome/.test(e)&&(r="safari"),/firefox/.test(e)&&(r="firefox"),/edg/.test(e)&&(r="edge"),{platform:o,browser:r,deviceInfo:`${o} • ${r}`}}();try{const n=await f("/webAuthn/register/start",{method:"GET",headers:{"Content-Type":"application/json"},credentials:"include"});if(!n.ok)return c("error"),void m("Something went wrong registering passkey.");const i=await n.json();let a;try{a=await g({optionsJSON:i}),await y(a,{friendlyName:e,platform:o,browser:r,deviceInfo:t})}catch(e){return void(e instanceof h?(console.error(`Error occurred with webAuthn, ${e.name} - ${e.code}-${e.stack}`),c("error"),m(`Error: ${e.name}`)):(console.error("A problem happened.",e),c("error"),m(`Error: ${e}`)))}c("success"),m("Passkey registered successfully."),s("/")}catch(e){console.error(e),c("error"),m("Something went wrong registering passkey.")}},disabled:"loading"===l,className:Te,children:"loading"===l?"Registering...":"Register Passkey"}),_&&e("p",{className:`${Oe} ${"success"===l?Le:Ie}`,children:_})]}):o("div",{className:xe,children:[e("div",{className:Pe}),e("span",{children:"Checking for Passkey Support..."})]})})})};var Ee="verifyOTP-module__container___wgoDE",je="verifyOTP-module__card___3cs2p",Ae="verifyOTP-module__title___fZ-1d",Fe="verifyOTP-module__subtitle___dGSu3",Be="verifyOTP-module__error___GEtlG",ze="verifyOTP-module__success___46TjG",Ge="verifyOTP-module__form___jiGG-",Ve="verifyOTP-module__label___Zq5Mi",$e="verifyOTP-module__timer___smq-a",qe="verifyOTP-module__input___yqIXM",Re="verifyOTP-module__resend___PlmkG",Ue="verifyOTP-module__button___8pIuO",De="verifyOTP-module__toggle___wbzVa";C(".verifyOTP-module__container___wgoDE{align-items:center;color:#fff;display:flex;justify-content:center;padding:1rem}.verifyOTP-module__card___3cs2p{background-color:#1f2937;border-radius:.5rem;box-shadow:0 0 10px rgba(0,0,0,.3);max-width:28rem;padding:1.5rem;width:100%}.verifyOTP-module__title___fZ-1d{color:#fff;font-size:1.5rem;font-weight:700;margin-bottom:1rem;text-align:center}.verifyOTP-module__subtitle___dGSu3{color:#9ca3af;font-size:.875rem;margin-bottom:1.5rem;text-align:center}.verifyOTP-module__error___GEtlG{color:#f87171;margin-bottom:1rem;text-align:center}.verifyOTP-module__success___46TjG{color:#34d399;margin-bottom:.75rem;text-align:center}.verifyOTP-module__form___jiGG-{display:flex;flex-direction:column;gap:1rem}.verifyOTP-module__label___Zq5Mi{color:#d1d5db;display:block;font-size:.875rem;margin-bottom:.25rem}.verifyOTP-module__timer___smq-a{color:#facc15;font-size:.875rem}.verifyOTP-module__input___yqIXM{background-color:#374151;border:1px solid #4b5563;border-radius:.375rem;color:#fff;outline:none;padding:.5rem;width:100%}.verifyOTP-module__input___yqIXM:focus{box-shadow:0 0 0 2px #3b82f6}.verifyOTP-module__resend___PlmkG{background:none;border:none;color:#60a5fa;cursor:pointer;font-size:.75rem;margin-top:.25rem;text-decoration:underline}.verifyOTP-module__resend___PlmkG:hover{color:#3b82f6}.verifyOTP-module__button___8pIuO{background-color:#2563eb;border:none;border-radius:.375rem;color:#fff;cursor:pointer;padding:.5rem;transition:background-color .2s;width:100%}.verifyOTP-module__button___8pIuO:hover{background-color:#1d4ed8}.verifyOTP-module__toggle___wbzVa{background:none;border:none;color:#60a5fa;cursor:pointer;font-size:.875rem;margin-top:1.5rem;text-align:center;width:100%}");const Je=()=>{const r=d(),{apiHost:t,mode:n}=N(),[s,l]=i(""),[c,_]=i(""),[m,u]=i(null),[g,h]=i(null),[p,f]=i(""),[y,b]=i(!1),[v,w]=i(""),[x,P]=i(300),[S,C]=i(300),T=k({authMode:n,authHost:t}),O=async()=>{b(!0);try{if(!m){(await T("/otp/verify-phone-otp",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({verificationToken:c}),credentials:"include"})).ok?u(!0):f("Verification failed.")}}catch(e){console.error(e),f("Verification failed.")}b(!1)},L=async()=>{b(!0);try{if(!g){(await T("/otp/verify-email-otp",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({verificationToken:s}),credentials:"include"})).ok?h(!0):f("Verification failed.")}}catch(e){console.error(e),f("Verification failed.")}b(!1)},I=e=>{w(""),"email"===e?((async()=>{f("");const e=await T("/otp/generate-email-otp",{method:"GET",headers:{"Content-Type":"application/json"}}),o=await e.json();e.ok?(w("Verification email has been resent."),o.token&&localStorage.setItem("token",o.token)):f("Failed to send Email code. If this persists, refresh the page and try again.")})(),w("Verification email has been resent.")):((async()=>{f("");const e=await T("/otp/generate-phone-otp",{method:"GET",headers:{"Content-Type":"application/json"}}),o=await e.json();e.ok?(o.token&&localStorage.setItem("token",o.token),w("Verification SMS has been resent.")):f("Failed to send SMS code. If this persists, refresh the page and try again.")})(),w("Verification SMS has been resent."))},M=o=>!0===o?e("span",{className:"text-green-400 ml-2",children:"✅"}):!1===o?e("span",{className:"text-red-400 ml-2",children:"❌"}):null,E=e=>`${Math.floor(e/60).toString().padStart(2,"0")}:${(e%60).toString().padStart(2,"0")}`;return a(()=>{const e=setInterval(()=>{P(e=>e>0?e-1:0)},1e3);return()=>clearInterval(e)},[]),a(()=>{const e=setInterval(()=>{C(e=>e>0?e-1:0)},1e3);return()=>clearInterval(e)},[]),a(()=>{g&&m&&r("/registerPasskey")},[g,m,r]),e("div",{className:Ee,children:o("div",{className:je,children:[e("h2",{className:Ae,children:"Verify Your Contact Info"}),e("p",{className:Fe,children:"Enter the codes sent to your email and phone number."}),p&&e("p",{className:Be,children:p}),v&&e("p",{className:ze,children:v}),o("form",{onSubmit:async e=>{if(e.preventDefault(),f(""),6===s.length)if(6===c.length){b(!0);try{L(),O()}catch{f("Unexpected error occurred.")}finally{b(!1)}}else f("Please enter a valid code.");else f("Please enter a valid code.")},className:Ge,children:[o("div",{children:[o("label",{htmlFor:"emailCode",className:Ve,children:["Email Verification Code ",M(g)," -"," ",o("span",{className:$e,children:["Code expires in: ",E(x)]})]}),e("input",{id:"emailCode",type:"text",maxLength:6,value:s,autoComplete:"off",onChange:e=>{l(e.target.value),h(null)},className:qe,required:!0}),e("button",{type:"button",onClick:()=>I("email"),className:Re,children:"Resend code to email"})]}),o("div",{children:[o("label",{htmlFor:"phoneCode",className:Ve,children:["Phone Verification Code ",M(m)," -"," ",o("span",{className:$e,children:["Code expires in: ",E(S)]})]}),e("input",{id:"phoneCode",type:"text",maxLength:6,pattern:"\\d{6}",inputMode:"numeric",value:c,autoComplete:"off",onChange:e=>{_(e.target.value),u(null)},className:qe,required:!0}),e("button",{type:"button",onClick:()=>I("phone"),className:Re,children:"Resend code to phone"})]}),e("button",{type:"submit",className:Ue,children:y?"Verifying...":"Verify & Continue"}),e("button",{type:"button",onClick:()=>r("/login"),className:De,children:"Back to login"})]})]})})},Ke=()=>o(c,{children:[e(_,{path:"/login",element:e(re,{})}),e(_,{path:"/passKeyLogin",element:e(ve,{})}),e(_,{path:"/mfaLogin",element:e(he,{})}),e(_,{path:"/verifyOTP",element:e(Je,{})}),e(_,{path:"/registerPasskey",element:e(Me,{})}),e(_,{path:"*",element:e(m,{to:"/login",replace:!0})})]});export{S as AuthProvider,Ke as AuthRoutes,N as useAuth};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|