authrix
Version:
Lightweight, flexible authentication library for Node.js and TypeScript.
1 lines • 5.85 kB
JavaScript
import {b,g}from'./chunk-5VQXQYKM.mjs';import {b as b$1,a}from'./chunk-GACMQPPZ.mjs';import v from'crypto';var x=6,h=10,E=3,w=5,C=60*60*1e3,y=new Map;function F(t=x){if(t<4||t>12)throw new b("Code length must be between 4 and 12 characters");let r="";for(let e=0;e<t;e++)r+=v.randomInt(0,10).toString();return r}async function U(t){try{return (await import('bcryptjs')).hash(t,12)}catch{throw new g("Failed to hash verification code")}}async function D(t,r){try{return (await import('bcryptjs')).compare(t,r)}catch{return false}}function S(t){let r=Date.now(),e=y.get(t);if(!e)return y.set(t,{count:1,lastAttempt:r}),{allowed:true,attemptsRemaining:w-1};if(e.blockedUntil&&r<e.blockedUntil)return {allowed:false,attemptsRemaining:0,blockedUntil:new Date(e.blockedUntil)};if(r-e.lastAttempt>C)return y.set(t,{count:1,lastAttempt:r}),{allowed:true,attemptsRemaining:w-1};if(e.count<w)return e.count++,e.lastAttempt=r,{allowed:true,attemptsRemaining:w-e.count};let i=Math.min(60*60*1e3,15*60*1e3*Math.pow(2,e.count-w));return e.blockedUntil=r+i,{allowed:false,attemptsRemaining:0,blockedUntil:new Date(e.blockedUntil)}}async function T(t,r={}){let e=b$1.db;if(!e||!("storeTwoFactorCode"in e))throw new g("Database adapter does not support 2FA. Please use an adapter that implements storeTwoFactorCode.");let{codeLength:i=x,expiryMinutes:a=h,maxAttempts:n=E,type:o="email_verification",metadata:s={}}=r;if(!t?.trim())throw new b("User ID is required");let p=s.email||s.phone||t,d=S(p);if(!d.allowed){let c=d.blockedUntil?`Too many verification code requests. Try again after ${d.blockedUntil.toLocaleTimeString()}`:"Too many verification code requests. Please try again later.";throw new b(c)}try{let c=F(i),g=await U(c),b=new Date(Date.now()+a*60*1e3),A=v.randomUUID(),R={id:A,userId:t,code:"",hashedCode:g,type:o,expiresAt:b,createdAt:new Date,attempts:0,isUsed:!1,metadata:{...s,generatedAt:new Date().toISOString(),ipAddress:s.ipAddress,userAgent:s.userAgent}};return await e.storeTwoFactorCode(R),{code:c,codeId:A,expiresAt:b,attemptsRemaining:d.attemptsRemaining}}catch{throw new g("Failed to generate verification code")}}async function L(t,r,e){let i=b$1.db;if(!i||!("getTwoFactorCode"in i)||!("updateTwoFactorCode"in i))throw new g("Database adapter does not support 2FA operations.");if(!t?.trim()||!r?.trim())return {isValid:false,isExpired:false,attemptsRemaining:0,error:"Code ID and verification code are required"};try{let a=await i.getTwoFactorCode(t);if(!a)return {isValid:!1,isExpired:!1,attemptsRemaining:0,error:"Invalid verification code"};if(e&&a.userId!==e)return {isValid:!1,isExpired:!1,attemptsRemaining:0,error:"Invalid verification code"};if(a.isUsed)return {isValid:!1,isExpired:!1,attemptsRemaining:0,error:"Verification code has already been used"};if(new Date>a.expiresAt)return {isValid:!1,isExpired:!0,attemptsRemaining:0,error:"Verification code has expired"};let n=E;if(a.attempts>=n)return {isValid:!1,isExpired:!1,attemptsRemaining:0,error:"Maximum verification attempts exceeded"};let o=a.attempts+1;return await i.updateTwoFactorCode(t,{attempts:o,lastAttemptAt:new Date}),await D(r,a.hashedCode)?(await i.updateTwoFactorCode(t,{isUsed:!0,usedAt:new Date}),{isValid:!0,isExpired:!1,attemptsRemaining:n-o,metadata:a.metadata}):{isValid:!1,isExpired:!1,attemptsRemaining:n-o,error:"Invalid verification code"}}catch{return {isValid:false,isExpired:false,attemptsRemaining:0,error:"An error occurred during verification"}}}async function N(){let t=b$1.db,r=0;if(t&&"cleanupExpiredTwoFactorCodes"in t)try{r=await t.cleanupExpiredTwoFactorCodes();}catch{}let e=Date.now(),i=0;for(let[a,n]of Array.from(y.entries()))(!n.blockedUntil&&e-n.lastAttempt>C||n.blockedUntil&&e>n.blockedUntil)&&(y.delete(a),i++);return {codesDeleted:r,rateLimitEntriesCleared:i}}async function O(t,r){let e=b$1.db;if(!e||!("getUserTwoFactorCodes"in e))return [];try{return await e.getUserTwoFactorCodes(t,r)}catch{return []}}async function V(t,r,e={}){let{serviceName:i="default",subject:a$1="Email Verification Code",template:n,metadata:o}=e;if(!t?.trim())throw new b("Email address is required");if(!r?.trim())throw new b("Verification code is required");let s=a.get(i)||a.getDefault();if(!s)throw new g(`Email service '${i}' not configured. Please register an email service.`);try{await s.sendVerificationEmail(t,r,{subject:a$1,template:n,metadata:o});}catch{throw new g("Failed to send verification email")}}async function _(t,r,e={}){let{serviceName:i="default",template:a$1,metadata:n}=e;if(!t?.trim())throw new b("Phone number is required");if(!r?.trim())throw new b("Verification code is required");let o=a.getSMS(i)||a.getDefaultSMS();if(!o)throw new g(`SMS service '${i}' not configured. Please register an SMS service.`);try{await o.sendVerificationSMS(t,r,{template:a$1,metadata:n});}catch{throw new g("Failed to send verification SMS")}}async function q(t,r,e={}){let{serviceName:i,subject:a,template:n,codeLength:o,expiryMinutes:s,metadata:p={}}=e,{code:d,codeId:c,expiresAt:g,attemptsRemaining:b}=await T(t,{type:"email_verification",codeLength:o,expiryMinutes:s,metadata:{...p,email:r}});return await V(r,d,{serviceName:i,subject:a,template:n,metadata:{...p,userId:t,codeId:c}}),{codeId:c,expiresAt:g,attemptsRemaining:b,message:`Verification code sent to ${r}. Code expires in ${s||h} minutes.`}}async function H(t,r,e={}){let{serviceName:i,template:a,codeLength:n,expiryMinutes:o,metadata:s={}}=e,{code:p,codeId:d,expiresAt:c,attemptsRemaining:g}=await T(t,{type:"phone_verification",codeLength:n,expiryMinutes:o,metadata:{...s,phone:r}});return await _(r,p,{serviceName:i,template:a,metadata:{...s,userId:t,codeId:d}}),{codeId:d,expiresAt:c,attemptsRemaining:g,message:`Verification code sent to ${r}. Code expires in ${o||h} minutes.`}}export{F as a,U as b,D as c,T as d,L as e,N as f,O as g,V as h,_ as i,q as j,H as k};