authrix
Version:
Lightweight, flexible authentication library for Node.js and TypeScript.
1 lines • 9.21 kB
JavaScript
import {a as a$3}from'./chunk-BHP666OX.mjs';import {a as a$2}from'./chunk-A4X5QZSX.mjs';import {a as a$1}from'./chunk-YS4LLLFP.mjs';import {b,f,d as d$1,c}from'./chunk-5VQXQYKM.mjs';import {d,a,c as c$1,b as b$2}from'./chunk-5NOQNI5F.mjs';import {b as b$1}from'./chunk-GACMQPPZ.mjs';var C=new Map,W=3,B=60*60*1e3;function z(i){let e=Date.now(),r=C.get(i);return r?e-r.lastAttempt>B?(C.set(i,{count:1,lastAttempt:e}),true):r.count<W?(r.count++,r.lastAttempt=e,true):false:(C.set(i,{count:1,lastAttempt:e}),true)}async function F(i,e){let r=i.split("@")[0].toLowerCase().replace(/[^a-z0-9]/g,""),n=r,a=1;for(;e.findUserByUsername;)try{if(!await e.findUserByUsername(n))break;n=`${r}${a}`,a++;}catch{break}return n}async function Y(i,e,r={}){let{requireEmailVerification:n=false,autoSignin:a$3=true,includeUserProfile:m=true,customUserData:p={},skipPasswordValidation:l=false,generateUsername:w=false,username:u,firstName:D,lastName:N,fullName:y,profilePicture:S,requesterIp:t}=r;if(!i?.trim())throw new b("Email is required");if(!e?.trim())throw new b("Password is required");let d$1=i.toLowerCase().trim();if(!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(d$1))throw new b("Invalid email format");if(l){if(e.length<6)throw new b("Password must be at least 6 characters long")}else {let b$1=[d$1.split("@")[0]],V=d(e,{},b$1);if(!V.isValid)throw new b(`Password validation failed: ${V.errors.join(", ")}`)}let v=t?`${d$1}|${t}`:d$1;if(!z(v))throw new b("Too many signup attempts. Please try again later.");let c=b$1.db;if(!c)throw new Error("Database not configured. Make sure initAuth() is called before using authentication functions.");try{if(await c.findUserByEmail(d$1))throw new f("An account with this email already exists");let V=await a(e,{skipValidation:l,identifier:d$1}),U={email:d$1,password:V,emailVerified:!n,createdAt:new Date,authMethod:"password",authProvider:"password",...p};typeof u=="string"&&u.trim()&&(U.username=u.trim()),typeof D=="string"&&D.trim()&&(U.firstName=D.trim()),typeof N=="string"&&N.trim()&&(U.lastName=N.trim()),typeof y=="string"&&y.trim()&&(U.fullName=y.trim()),typeof S=="string"&&S.trim()&&(U.profilePicture=S.trim()),w&&!U.username&&(U.username=await F(d$1,c)),n||(U.emailVerifiedAt=new Date);let s=await c.createUser(U),k={id:s.id,email:s.email};s.username&&(k.username=s.username),s.emailVerified&&(k.emailVerified=s.emailVerified);let o=a$1(k),x={id:s.id,email:s.email,createdAt:s.createdAt};return m&&(s.username&&(x.username=s.username),s.firstName&&(x.firstName=s.firstName),s.lastName&&(x.lastName=s.lastName),s.fullName&&(x.fullName=s.fullName),s.profilePicture&&(x.profilePicture=s.profilePicture),typeof s.emailVerified=="boolean"&&(x.emailVerified=s.emailVerified,s.emailVerified&&s.emailVerifiedAt instanceof Date&&(x.emailVerifiedAt=s.emailVerifiedAt))),{user:x,token:o,cookieOptions:{httpOnly:!0,secure:b$1.forceSecureCookies||process.env.NODE_ENV==="production",maxAge:1e3*60*60*24*7,sameSite:"lax",path:"/"},isNewUser:!0,requiresEmailVerification:n}}catch(b){throw a$2.debug("Signup failed",{email:d$1,error:b instanceof Error?b.message:"Unknown error"}),b}}var E=new Map;function H(i,e=5,r=15){let n=Date.now(),a=E.get(i);return a?a.lockedUntil&&n>a.lockedUntil?(E.set(i,{count:1,lastAttempt:n}),{allowed:true,attemptsRemaining:e-1}):a.lockedUntil&&n<=a.lockedUntil?{allowed:false,attemptsRemaining:0,lockedUntil:new Date(a.lockedUntil)}:n-a.lastAttempt>60*60*1e3?(E.set(i,{count:1,lastAttempt:n}),{allowed:true,attemptsRemaining:e-1}):(a.count++,a.lastAttempt=n,a.count>=e?(a.lockedUntil=n+r*60*1e3,{allowed:false,attemptsRemaining:0,lockedUntil:new Date(a.lockedUntil)}):{allowed:true,attemptsRemaining:e-a.count}):(E.set(i,{count:1,lastAttempt:n}),{allowed:true,attemptsRemaining:e-1})}function X(i){E.delete(i);}async function ne(i,e,r={}){let{rememberMe:n=false,requireEmailVerification:a=false,updateLastLogin:m=true,includeUserProfile:p=true,maxLoginAttempts:l=5,lockoutDuration:w=15}=r;if(!i?.trim())throw new b("Email is required");if(!e?.trim())throw new b("Password is required");let u=i.toLowerCase().trim();if(!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(u))throw new b("Invalid email format");let N=r.requesterIp?`${u}|${r.requesterIp}`:u,y=H(N,l,w);if(!y.allowed){let t=y.lockedUntil?`Account temporarily locked. Try again after ${y.lockedUntil.toLocaleTimeString()}`:"Too many login attempts. Please try again later.";throw a$2.structuredWarn({category:"auth",action:"signin",outcome:"locked",message:t,email:u,attemptsRemaining:0}),new d$1(t)}let S=b$1.db;if(!S)throw new Error("Database not configured. Make sure initAuth() is called before using authentication functions.");try{let t=await S.findUserByEmail(u);if(!t)throw new c("Invalid email or password");let d=!1,P;try{let o=await c$1(e,t.password,{identifier:u,updateHash:!!(b$1.db&&b$1.db.updateUser)});d=o.valid,o.valid&&o.needsRehash&&o.newHash&&(P=o.newHash);}catch(o){o instanceof Error?a$2.structuredWarn({category:"auth",action:"password-verify-fallback",message:"Password verify fallback",error:o instanceof Error?o.message:String(o)}):a$2.structuredWarn({category:"auth",action:"password-verify-fallback",message:"Password verify fallback (unknown error type)"}),d=await b$2(e,t.password,{identifier:u});}if(!d)throw a$2.structuredWarn({category:"auth",action:"signin",outcome:"invalid-credentials",message:"Invalid email or password",email:u,attemptsRemaining:y.attemptsRemaining}),new c("Invalid email or password");if(a&&!t.emailVerified)throw new d$1("Please verify your email address before signing in");if(t.isDisabled)throw new d$1("Account has been disabled. Please contact support.");X(u);let v=t.mustChangePassword||!1,c$2=t;if((m||P)&&S.updateUser)try{let o={};m&&(o.lastLoginAt=new Date,o.loginCount=(t.loginCount||0)+1),P&&(o.password=P,o.passwordChangedAt=new Date),Object.keys(o).length>0&&(c$2=await S.updateUser(t.id,o)||t);}catch(o){a$2.structuredWarn({category:"auth",action:"post-auth-update",outcome:"failed",message:"Failed post-auth update",error:o instanceof Error?o.message:String(o)});}let b={id:t.id,email:t.email};t.username&&(b.username=t.username),t.emailVerified&&(b.emailVerified=t.emailVerified);let V=a$1(b),s=n?1e3*60*60*24*30:b$1.sessionMaxAgeMs,k={id:c$2.id,email:c$2.email};return p&&(c$2.username&&(k.username=c$2.username),c$2.firstName&&(k.firstName=c$2.firstName),c$2.lastName&&(k.lastName=c$2.lastName),typeof c$2.emailVerified=="boolean"&&(k.emailVerified=c$2.emailVerified),c$2.lastLoginAt&&(k.lastLoginAt=c$2.lastLoginAt)),{user:k,token:V,cookieOptions:{httpOnly:!0,secure:b$1.forceSecureCookies||process.env.NODE_ENV==="production",maxAge:s,sameSite:"lax",path:"/"},isFirstLogin:!t.lastLoginAt,mustChangePassword:v}}catch(t){let d=t instanceof Error?t.message:"Unknown error";throw t instanceof d$1?a$2.structuredWarn({category:"auth",action:"signin",outcome:"forbidden",message:d,email:u,attemptsRemaining:y.attemptsRemaining}):t instanceof c?a$2.structuredWarn({category:"auth",action:"signin",outcome:"unauthorized",message:d,email:u,attemptsRemaining:y.attemptsRemaining}):a$2.error("Signin failed",{email:u,error:d}),t}}function le(i={}){let{invalidateAllSessions:e=false,clearRememberMe:r=true,redirectUrl:n,extraClear:a=[]}=i,m=[{name:b$1.cookieName,options:{httpOnly:true,secure:process.env.NODE_ENV==="production",sameSite:"lax",path:"/",expires:new Date(0)}}];return r&&m.push({name:`${b$1.cookieName}_remember`,options:{httpOnly:true,secure:process.env.NODE_ENV==="production",sameSite:"lax",path:"/",expires:new Date(0)}}),a.forEach(p=>{typeof p=="string"&&p.trim()&&m.push({name:p.trim(),options:{httpOnly:true,secure:process.env.NODE_ENV==="production",sameSite:"lax",path:"/",expires:new Date(0)}});}),{success:true,message:"Logged out successfully",cookiesToClear:m,redirectUrl:n}}async function $(i,e={}){let{requireEmailVerification:r=false,updateLastSeen:n=false,includeUserProfile:a=true}=e;try{if(!i?.trim())return null;let m=a$3(i);if(!m?.id)return null;let p=b$1.db;if(!p)return a$2.structuredWarn({category:"session",action:"validation",outcome:"skipped",message:"Database not configured for session validation"}),null;let l=await p.findUserById(m.id);if(!l||r&&!l.emailVerified)return null;if(n&&p.updateUser)try{await p.updateUser(l.id,{lastLoginAt:new Date});}catch(u){a$2.structuredWarn({category:"session",action:"update-last-login",outcome:"failed",message:"Failed to update last login timestamp",error:u instanceof Error?u.message:String(u)});}let w={id:l.id,email:l.email,createdAt:l.createdAt};return a&&(l.username&&(w.username=l.username),l.firstName&&(w.firstName=l.firstName),l.lastName&&(w.lastName=l.lastName),typeof l.emailVerified=="boolean"&&(w.emailVerified=l.emailVerified),l.lastLoginAt&&(w.lastLoginAt=l.lastLoginAt)),w}catch(m){return a$2.debug("Session validation error",m),null}}async function ge(i,e){return await $(i,e)!==null}async function pe(i,e={}){let r=await $(i,e);if(!r)return {user:null};try{if(b$1.rollingSessionEnabled){let n=a$3(i);if(n.exp){let a=Math.floor(Date.now()/1e3),m=n.exp-a;if(m>0&&m<=b$1.rollingSessionThresholdSeconds){let p=a$1({id:r.id,email:r.email});return {user:r,refreshedToken:p}}}}}catch{}return {user:r}}export{Y as a,ne as b,le as c,$ as d,ge as e,pe as f};