@sqrzro/server 2.0.0-bz.65 → 2.0.0-bz.67

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.
@@ -1,3 +1,3 @@
1
- 'use strict';var drizzleOrm=require('drizzle-orm'),postgresJs=require('drizzle-orm/postgres-js'),ge=require('postgres'),pgCore=require('drizzle-orm/pg-core'),server=require('next/server'),H=require('joi'),otplib=require('otplib'),Be=require('qrcode'),adapterDrizzle=require('@lucia-auth/adapter-drizzle'),utility=require('@sqrzro/utility'),lucia=require('lucia'),headers=require('next/headers'),pathToRegexp=require('path-to-regexp'),redis=require('redis'),re=require('bcryptjs');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var ge__default=/*#__PURE__*/_interopDefault(ge);var H__default=/*#__PURE__*/_interopDefault(H);var Be__default=/*#__PURE__*/_interopDefault(Be);var re__default=/*#__PURE__*/_interopDefault(re);function be(){if(!process.env.DATABASE_URL)throw new Error("DATABASE_URL is not defined");return postgresJs.drizzle(ge__default.default(process.env.DATABASE_URL,{prepare:!1}))}var n=globalThis.szdb??be();process.env.VERCEL_ENV||(globalThis.szdb=n);var Ae=10,Se=pgCore.pgEnum("mfaType",["TOTP","HARDWARE"]),Pe=pgCore.pgEnum("scope",["ANON","MFA","AUTHED"]),S=pgCore.pgSchema("auth"),s=S.table("user_credentials",{id:pgCore.text("id").primaryKey(),email:pgCore.text("email").notNull(),password:pgCore.text("password"),role:pgCore.integer("role").notNull().default(Ae),deletedAt:pgCore.timestamp("deletedAt")},e=>({unique:pgCore.uniqueIndex().on(e.email,e.role)})),C=S.table("sessions",{id:pgCore.text("id").primaryKey(),userId:pgCore.text("userId").notNull().references(()=>s.id,{onDelete:"cascade"}),scope:Pe("scope").notNull().default("ANON"),expiresAt:pgCore.timestamp("expiresAt").notNull()}),p=S.table("resets",{id:pgCore.text("id").primaryKey(),userId:pgCore.text("userId").notNull().references(()=>s.id,{onDelete:"cascade"}),expiresAt:pgCore.timestamp("expiresAt").notNull()}),u=S.table("mfas",{id:pgCore.text("id").primaryKey(),name:pgCore.text("name").notNull(),userId:pgCore.text("userId").notNull().references(()=>s.id,{onDelete:"cascade"}),type:Se("type").notNull().default("TOTP"),secret:pgCore.text("secret").notNull(),verifiedAt:pgCore.timestamp("verifiedAt")}),h=S.table("client_credentials",{id:pgCore.text("id").primaryKey(),alias:pgCore.text("alias").notNull().unique(),secret:pgCore.text("secret").notNull().unique()});var N=class extends Error{messages;constructor(r){super(JSON.stringify(r)),this.messages=r,this.name="ValidationError";}},c=N;var xe={"alternatives.all":"","alternatives.any":"","alternatives.match":"","alternatives.one":"","alternatives.types":"","any.custom":"","any.default":"","any.failover":"","any.invalid":"","any.only":"","any.ref":"","any.required":"{{#label}} is required","any.unknown":"","array.base":"","array.excludes":"","array.includesRequiredBoth":"","array.includesRequiredKnowns":"","array.includesRequiredUnknowns":"","array.includes":"","array.length":"","array.max":"","array.min":"","array.orderedLength":"","array.sort":"","array.sort.mismatching":"","array.sort.unsupported":"","array.sparse":"","array.unique":"","array.hasKnown":"","array.hasUnknown":"","binary.base":"","binary.length":"","binary.max":"","binary.min":"","boolean.base":"","date.base":"","date.format":"","date.greater":"","date.less":"","date.max":"","date.min":"","date.strict":"","function.arity":"","function.class":"","function.maxArity":"","function.minArity":"","number.base":"{{#label}} should be a number","number.greater":"","number.infinity":"","number.integer":"","number.less":"","number.max":"","number.min":"{{#label}} should be greater than or equal to {{#limit}}","number.multiple":"","number.negative":"","number.port":"","number.positive":"","number.precision":"","number.unsafe":"","object.unknown":"","object.and":"","object.assert":"","object.base":"","object.length":"","object.max":"","object.min":"","object.missing":"","object.nand":"","object.pattern.match":"","object.refType":"","object.regex":"","object.rename.multiple":"","object.rename.override":"","object.schema":"","object.instance":"","object.with":"","object.without":"","object.xor":"","object.oxor":"","string.alphanum":"","string.base64":"","string.base":"","string.creditCard":"","string.dataUri":"","string.domain":"","string.email":"","string.empty":"{{#label}} is required","string.guid":"","string.hexAlign":"","string.hex":"","string.hostname":"","string.ipVersion":"","string.ip":"","string.isoDate":"","string.isoDuration":"","string.length":"","string.lowercase":"","string.max":"","string.min":"","string.normalize":"","string.pattern.base":"{{#label}} is not in the correct format","string.pattern.name":"","string.pattern.invert.base":"","string.pattern.invert.name":"","string.token":"","string.trim":"","string.uppercase":"","string.uri":"","string.uriCustomScheme":"","string.uriRelativeOnly":"","symbol.base":"","symbol.map":""},V=xe;function Fe(){return Object.entries(V).reduce((e,[r,t])=>t?{...e,[r]:t}:e,{})}function Ee(e){let r=e.details.reduce((t,o)=>({...t,[o.path.join(".")]:o.message.replace(/"/gu,"")}),{});return new c(r)}async function z(e,r,t){try{return [await r.validateAsync(e,{abortEarly:!1,messages:t||Fe(),stripUnknown:!0}),null]}catch(o){return o instanceof H__default.default.ValidationError?[null,Ee(o)]:o instanceof Error?[null,o]:[null,new Error("Unknown validation error occured")]}}function f(e){return H__default.default.object(e)}function J(e){return {cause:e.cause,message:e.message,name:e.name,stack:e.stack}}function Re(e){return !!Object.prototype.hasOwnProperty.call(e,"fn")}async function y(e){let r={...e.formData};if(e.request){let[o,i]=await z(e.formData,e.request);if(i!==null)return i instanceof c&&e.onValidationError?.(i),[null,J(i)];r=o;}if(!Re(e))return await e.onSuccess?.(r),[r,null];let t=null;try{t=await e.fn(r);}catch(o){if(o instanceof c)return e.onValidationError?.(o),[null,J(o)];throw o instanceof Error?o:new Error("The function supplied to submitForm encountered an unknown error")}if(!t)throw new Error("NO_MODEL");return await e.onSuccess?.(t),[t,null]}var ve=f({token:H__default.default.string().pattern(/^[0-9]{6}$/u).required()}),k=ve;var P=null;function Oe(e){return e.includes("localhost")||e.includes("127.0.0.1")}async function W(){if(!process.env.REDIS_URL)throw new Error("REDIS_URL is not defined. Access to the cache is not possible.");return P||(P=redis.createClient({socket:{tls:!Oe(process.env.REDIS_URL)},url:process.env.REDIS_URL}),await P.connect(),P)}async function $(e){return (await W()).get(e)}async function B(e,r){await(await W()).set(e,r);}async function M(){let e=process.env.SZ_ORIGIN;if(e)return e;let r=(await headers.headers()).get("x-origin");if(r)return r;let t=(await headers.headers()).get("x-forwarded-proto"),o=(await headers.headers()).get("x-forwarded-host");if(t&&o)return `${t}://${o}`;throw new Error("No origin could be determined")}var G="/auth/login",_e=16,R={ANON:{allowedRoute:"/auth/(login|password)",redirectOnUnauth:G},MFA:{allowedRoute:"/auth/mfa",redirectOnUnauth:"/auth/mfa"},AUTHED:{allowedRoute:"*",redirectOnAuth:"/"}},qe={D:"d",H:"h",M:"m",MS:"ms",S:"s",W:"w"};function Le(){if(!process.env.AUTH_SESSION_EXPIRY)return new lucia.TimeSpan(2,"w");let[e,r]=process.env.AUTH_SESSION_EXPIRY.split(/_/u);return new lucia.TimeSpan(Number(e),qe[r])}var Ce=new adapterDrizzle.DrizzlePostgreSQLAdapter(n,C,s),g=new lucia.Lucia(Ce,{getSessionAttributes:e=>({scope:e.scope}),getUserAttributes:e=>({email:e.email,role:e.role,deletedAt:e.deletedAt}),sessionCookie:{attributes:{secure:process.env.APP_ENV==="production"},name:process.env.AUTH_COOKIE_NAME||"auth_session"},sessionExpiresIn:Le()});function b(e="",r=_e){return `${e?`${e}_`:""}${lucia.generateId(r)}`}async function X(e){let r=g.createBlankSessionCookie();return (await headers.cookies()).set(r.name,r.value,r.attributes),g.invalidateSession(e)}async function T(e){return g.invalidateUserSessions(e)}async function v(e,r="ANON"){let t=await g.createSession(e,{scope:r}),o=g.createSessionCookie(t.id);return (await headers.cookies()).set(o.name,o.value,o.attributes),!0}async function U(){return (await headers.cookies()).get(g.sessionCookieName)?.value??null}async function tt(){return !!await U()}function Ve(e,r){let t=Array.isArray(r)?r:[r];return t[0]?t.includes(e):x().includes(e)}async function Y(e){let r=await U();if(!r)return null;let{user:t}=await g.validateSession(r);return !t||t.deletedAt||!Ve(t.role,e)?null:utility.pick(t,["id","email","role"])}function He(e,r){return r?r==="*"?!0:pathToRegexp.match(r)(e)!==!1:!1}async function Z(){let e=await $(`${await M()}:scopes`);return e?JSON.parse(e):R}async function Q(e){return (await Z())[e]}async function ze(e){let r={ANON:{...R.ANON,...e?.ANON},MFA:{...R.MFA,...e?.MFA},AUTHED:{...R.AUTHED,...e?.AUTHED}};return B(`${await M()}:scopes`,JSON.stringify(r))}async function Je(e,r){let t=await Z(),{session:o,user:i}=await g.validateSession(e),a=t[o&&x().includes(i?.role)?o.scope:"ANON"];return {email:i?.email||null,redirect:He(r,a.allowedRoute)?null:a.redirectOnUnauth||G}}async function ot(e,r){let t=e.nextUrl.searchParams.get("id")||"",o=e.nextUrl.searchParams.get("pathname")||"/";return await ze(r),server.NextResponse.json(await Je(t,o))}function w(){return process.env.AUTH_MFA_ENABLED!=="false"}async function ft(e,r){if(!w())throw new Error("MFA is not enabled. Cannot generate MFA secret.");if(!r)return null;let[t]=await n.select().from(s).where(drizzleOrm.eq(s.email,r)).limit(1);if(!t)return null;let o=otplib.authenticator.generateSecret(),i=otplib.authenticator.keyuri(r,e,o);return await n.delete(u).where(drizzleOrm.and(drizzleOrm.eq(u.userId,t.id),drizzleOrm.isNull(u.verifiedAt))),await n.insert(u).values({id:b(),name:"Default",secret:o,userId:t.id}),new Promise((a,m)=>{Be__default.default.toDataURL(i,{rendererOpts:{quality:1},margin:0,scale:2},(D,pe)=>{D&&m(D),a(pe);});})}async function gt(e){if(!w())return !1;let[r]=await n.select().from(u).where(drizzleOrm.and(drizzleOrm.eq(u.userId,e.id),drizzleOrm.isNotNull(u.verifiedAt))).limit(1);return !!r}async function Ke(e){w()&&await n.update(u).set({verifiedAt:new Date}).where(drizzleOrm.eq(u.userId,e));}async function Ge(e,r){if(!w())return !1;let[t]=await n.select().from(u).where(drizzleOrm.eq(u.userId,e)).limit(1);return t?otplib.authenticator.check(r,t.secret):!1}async function bt(e){let r=[n.delete(u).where(drizzleOrm.eq(u.userId,e)),T(e)];return await Promise.all(r),!0}async function Xe(e){if(!w())throw new c({token:"MFA is not enabled"});let r=await Y();if(!r)throw new c({token:"User not found"});if(!await Ge(r.id,e.token))throw new c({token:"Invalid token"});return await Ke(r.id),v(r.id,"AUTHED")}async function wt(e){return w()?await y({fn:Xe,formData:e,request:k}):[null,new Error("MFA is not enabled")]}var Ye=12,te={min:8,upper:1,lower:1,number:1,symbol:1};function Ze(e,r){return e.length>=r}function Qe(e,r){return e.replace(/[^A-Z]/gu,"").length>=r}function er(e,r){return e.replace(/[^a-z]/gu,"").length>=r}function rr(e,r){return e.replace(/[^0-9]/gu,"").length>=r}function tr(e,r){return e.replace(/[^$]/gu,"").length>=r}var or={min:Ze,upper:Qe,lower:er,number:rr,symbol:tr};async function F(e){return await re__default.default.hash(e,Ye)}async function O(e,r){return !e||!r?!1:await re__default.default.compare(e,r)}async function nr(e,r=te){let o=Object.entries(r).reduce((i,[a,m])=>(i[a]=or[a](e,m),i),{});return Promise.resolve(o)}async function oe(e,r=te){let t=await nr(e,r);return Promise.resolve(Object.values(t).every(Boolean))}var sr=f({email:H__default.default.string().email({minDomainSegments:2,tlds:!1}).required(),password:H__default.default.string().min(8).required()}),se=sr;var ar=f({email:H__default.default.string().max(60).email({minDomainSegments:2,tlds:!1}).required().messages({"any.required":"Please provide your email address, so we can send you a reset link","string.empty":"Please provide your email address, so we can send you a reset link","string.email":"Please make sure your email address is valid","string.max":"Please make sure your email address is valid"})}),ie=ar;var lr={lower:1,min:8,number:1,upper:1};async function ur(e,r){return await oe(e,lr)?e:r.message({external:"Please make sure your password is complex enough, to keep your account secure"})}var cr=f({password:H__default.default.string().external(ur).required().messages({"any.required":"Please provide your new password","string.empty":"Please provide your new password"}),token:H__default.default.string().pattern(/[a-z0-9]{40}/u)}),le=cr;var fr=40,gr=36e5;async function Ht(){let e=await U();e&&await X(e);}function x(){let e=process.env.AUTH_ROLE;if(!e)throw new Error("AUTH_ROLE is not defined. Authentication will not be possible.");return [Number(e)]}function br(){let e=x();return Math.max(...e)}async function ue(e){return await v(e,w()?"MFA":"AUTHED"),(await Q("AUTHED"))?.redirectOnAuth||null}async function ce(e,r){let t=[drizzleOrm.eq(s.email,e),drizzleOrm.isNull(s.deletedAt)];r?t.push(drizzleOrm.eq(s.role,r)):t.push(drizzleOrm.lte(s.role,br()));let[o]=await n.select().from(s).where(drizzleOrm.and(...t)).limit(1);return o}async function wr({email:e,password:r}){if(!process.env.AUTH_ROLE)throw new Error("AUTH_ROLE is not defined. Authentication will not be possible.");let t=await ce(e,Number(process.env.AUTH_ROLE));if(!t?.password||!await O(r,t.password))throw new c({email:"",password:""});let o=await ue(t.id);if(!o)throw new c({email:"",password:""});return o}async function zt(e,r){return await y({fn:wr,formData:e,onSuccess:async()=>{await r?.();},request:se})}async function Jt({email:e,password:r,role:t}){let o=r?await F(r):null,[i]=await n.insert(s).values({id:b(),email:e,password:o,role:t}).returning();return i}async function me(e,r,t){let[o]=await n.select().from(s).where(drizzleOrm.and(drizzleOrm.eq(s.email,e),drizzleOrm.eq(s.role,r))).limit(1);return o?(await n.update(s).set({deletedAt:t}).where(drizzleOrm.eq(s.id,o.id)),!0):!1}async function Wt(e,r){return me(e,r,new Date)}async function $t(e,r){return me(e,r,null)}async function hr(e){let r=await ce(e);if(!r)return null;await n.delete(p).where(drizzleOrm.eq(p.userId,r.id));let t=b("",fr);return await n.insert(p).values({id:t,userId:r.id,expiresAt:new Date(new Date().getTime()+gr)}),t}async function Bt(e,r){async function t(i){let a=await hr(i.email);return a?r(i.email,a):!0}return await y({fn:t,formData:e,request:ie})}async function yr(e,r){let[t]=await n.select().from(p).where(drizzleOrm.eq(p.id,e)).limit(1);if(!t)throw new Error("PASSWORD_RESET_TOKEN_NOT_FOUND");if(await n.delete(p).where(drizzleOrm.eq(p.id,e)),t.expiresAt<new Date)throw new Error("PASSWORD_RESET_TOKEN_EXPIRED");return await T(t.userId),await n.update(s).set({password:await F(r)}).where(drizzleOrm.and(drizzleOrm.eq(s.id,t.userId),drizzleOrm.inArray(s.role,x()))),t.userId}async function Kt(e,r){async function t(i){let a=await yr(i.token,i.password),m=await ue(a);if(!m)throw new Error("COULD_NOT_CREATE_SESSION");return m}return await y({fn:t,formData:e,onSuccess:r,request:le})}var Ar=16,Sr=64;async function ro(e){let[r]=await n.select().from(h).where(drizzleOrm.eq(h.id,e)).limit(1);return r}async function to({alias:e,id:r,secret:t}){let[o]=await n.insert(h).values({alias:e,id:r||b("",Ar),secret:await F(t||b("",Sr))}).returning();return o}async function oo(e){let{headers:r}=e,t=r.get("authorization");if(!t)return null;let o=Buffer.from(t.replace("Basic ",""),"base64").toString("utf-8").replace(/:$/u,""),[i,...a]=o.split("-"),[m]=await n.select().from(h).where(drizzleOrm.eq(h.id,i)).limit(1);return m&&await O(a.join(""),m.secret)?m:null}
2
- exports.MFARequest=k;exports.checkMFAEnabled=w;exports.checkPasswordComplexity=oe;exports.checkRouteAllowed=He;exports.checkSessionExists=tt;exports.checkUserHasMFA=gt;exports.createUserSession=v;exports.deleteMFA=bt;exports.deleteUser=Wt;exports.generateID=b;exports.generateMFA=ft;exports.getAllowedRoles=x;exports.getClientByID=ro;exports.getMaximumRole=br;exports.getPasswordComplexity=nr;exports.getScopeByID=Q;exports.getScopes=Z;exports.getSessionID=U;exports.getSessionUser=Y;exports.getUserByEmail=ce;exports.handleClientAuth=oo;exports.handleLoginForm=zt;exports.handleLogout=Ht;exports.handleMFA=Xe;exports.handleMFAForm=wt;exports.handlePasswordForm=Bt;exports.handlePasswordResetWithTokenForm=Kt;exports.handleSession=ot;exports.hashPassword=F;exports.invalidateSession=X;exports.invalidateUserSessions=T;exports.lucia=g;exports.registerClient=to;exports.registerUser=Jt;exports.setScopes=ze;exports.undeleteUser=$t;exports.verifyPassword=O;//# sourceMappingURL=index.cjs.map
1
+ 'use strict';var drizzleOrm=require('drizzle-orm'),postgresJs=require('drizzle-orm/postgres-js'),be=require('postgres'),pgCore=require('drizzle-orm/pg-core'),server=require('next/server'),H=require('joi'),otplib=require('otplib'),Ke=require('qrcode'),adapterDrizzle=require('@lucia-auth/adapter-drizzle'),utility=require('@sqrzro/utility'),lucia=require('lucia'),headers=require('next/headers'),pathToRegexp=require('path-to-regexp'),redis=require('redis'),re=require('bcryptjs');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var be__default=/*#__PURE__*/_interopDefault(be);var H__default=/*#__PURE__*/_interopDefault(H);var Ke__default=/*#__PURE__*/_interopDefault(Ke);var re__default=/*#__PURE__*/_interopDefault(re);function we(){if(!process.env.DATABASE_URL)throw new Error("DATABASE_URL is not defined");return postgresJs.drizzle(be__default.default(process.env.DATABASE_URL,{prepare:!1}))}var n=globalThis.szdb??we();process.env.VERCEL_ENV||(globalThis.szdb=n);var Pe=10,Se=pgCore.pgEnum("mfaType",["TOTP","HARDWARE"]),xe=pgCore.pgEnum("scope",["ANON","MFA","AUTHED"]),P=pgCore.pgSchema("auth"),i=P.table("user_credentials",{id:pgCore.text("id").primaryKey(),email:pgCore.text("email").notNull(),password:pgCore.text("password"),role:pgCore.integer("role").notNull().default(Pe),deletedAt:pgCore.timestamp("deletedAt")},e=>({unique:pgCore.uniqueIndex().on(e.email,e.role)})),C=P.table("sessions",{id:pgCore.text("id").primaryKey(),userId:pgCore.text("userId").notNull().references(()=>i.id,{onDelete:"cascade"}),scope:xe("scope").notNull().default("ANON"),expiresAt:pgCore.timestamp("expiresAt").notNull()}),p=P.table("resets",{id:pgCore.text("id").primaryKey(),userId:pgCore.text("userId").notNull().references(()=>i.id,{onDelete:"cascade"}),expiresAt:pgCore.timestamp("expiresAt").notNull()}),u=P.table("mfas",{id:pgCore.text("id").primaryKey(),name:pgCore.text("name").notNull(),userId:pgCore.text("userId").notNull().references(()=>i.id,{onDelete:"cascade"}),type:Se("type").notNull().default("TOTP"),secret:pgCore.text("secret").notNull(),verifiedAt:pgCore.timestamp("verifiedAt")}),h=P.table("client_credentials",{id:pgCore.text("id").primaryKey(),alias:pgCore.text("alias").notNull().unique(),secret:pgCore.text("secret").notNull().unique()});var N=class extends Error{messages;constructor(r){super(JSON.stringify(r)),this.messages=r,this.name="ValidationError";}},c=N;var Fe={"alternatives.all":"","alternatives.any":"","alternatives.match":"","alternatives.one":"","alternatives.types":"","any.custom":"","any.default":"","any.failover":"","any.invalid":"","any.only":"","any.ref":"","any.required":"{{#label}} is required","any.unknown":"","array.base":"","array.excludes":"","array.includesRequiredBoth":"","array.includesRequiredKnowns":"","array.includesRequiredUnknowns":"","array.includes":"","array.length":"","array.max":"","array.min":"","array.orderedLength":"","array.sort":"","array.sort.mismatching":"","array.sort.unsupported":"","array.sparse":"","array.unique":"","array.hasKnown":"","array.hasUnknown":"","binary.base":"","binary.length":"","binary.max":"","binary.min":"","boolean.base":"","date.base":"","date.format":"","date.greater":"","date.less":"","date.max":"","date.min":"","date.strict":"","function.arity":"","function.class":"","function.maxArity":"","function.minArity":"","number.base":"{{#label}} should be a number","number.greater":"","number.infinity":"","number.integer":"","number.less":"","number.max":"","number.min":"{{#label}} should be greater than or equal to {{#limit}}","number.multiple":"","number.negative":"","number.port":"","number.positive":"","number.precision":"","number.unsafe":"","object.unknown":"","object.and":"","object.assert":"","object.base":"","object.length":"","object.max":"","object.min":"","object.missing":"","object.nand":"","object.pattern.match":"","object.refType":"","object.regex":"","object.rename.multiple":"","object.rename.override":"","object.schema":"","object.instance":"","object.with":"","object.without":"","object.xor":"","object.oxor":"","string.alphanum":"","string.base64":"","string.base":"","string.creditCard":"","string.dataUri":"","string.domain":"","string.email":"","string.empty":"{{#label}} is required","string.guid":"","string.hexAlign":"","string.hex":"","string.hostname":"","string.ipVersion":"","string.ip":"","string.isoDate":"","string.isoDuration":"","string.length":"","string.lowercase":"","string.max":"","string.min":"","string.normalize":"","string.pattern.base":"{{#label}} is not in the correct format","string.pattern.name":"","string.pattern.invert.base":"","string.pattern.invert.name":"","string.token":"","string.trim":"","string.uppercase":"","string.uri":"","string.uriCustomScheme":"","string.uriRelativeOnly":"","symbol.base":"","symbol.map":""},V=Fe;function Ee(){return Object.entries(V).reduce((e,[r,t])=>t?{...e,[r]:t}:e,{})}function Re(e){let r=e.details.reduce((t,o)=>({...t,[o.path.join(".")]:o.message.replace(/"/gu,"")}),{});return new c(r)}async function z(e,r,t){try{return [await r.validateAsync(e,{abortEarly:!1,messages:t||Ee(),stripUnknown:!0}),null]}catch(o){return o instanceof H__default.default.ValidationError?[null,Re(o)]:o instanceof Error?[null,o]:[null,new Error("Unknown validation error occured")]}}function f(e){return H__default.default.object(e)}function J(e){return {cause:e.cause,message:e.message,name:e.name,stack:e.stack}}function Te(e){return !!Object.prototype.hasOwnProperty.call(e,"fn")}async function y(e){let r={...e.formData};if(e.request){let[o,s]=await z(e.formData,e.request);if(s!==null)return s instanceof c&&e.onValidationError?.(s),[null,J(s)];r=o;}if(!Te(e))return await e.onSuccess?.(r),[r,null];let t=null;try{t=await e.fn(r);}catch(o){if(o instanceof c)return e.onValidationError?.(o),[null,J(o)];throw o instanceof Error?o:new Error("The function supplied to submitForm encountered an unknown error")}if(!t)throw new Error("NO_MODEL");return await e.onSuccess?.(t),[t,null]}var Ue=f({token:H__default.default.string().pattern(/^[0-9]{6}$/u).required()}),k=Ue;var S=null;function De(e){return e.includes("localhost")||e.includes("127.0.0.1")}async function W(){if(!process.env.REDIS_URL)throw new Error("REDIS_URL is not defined. Access to the cache is not possible.");return S||(S=redis.createClient({socket:{tls:!De(process.env.REDIS_URL)},url:process.env.REDIS_URL}),await S.connect(),S)}async function $(e){return (await W()).get(e)}async function B(e,r){await(await W()).set(e,r);}async function M(){let e=process.env.SZ_ORIGIN;if(e)return e;let r=(await headers.headers()).get("x-origin");if(r)return r;let t=(await headers.headers()).get("x-forwarded-proto"),o=(await headers.headers()).get("x-forwarded-host");if(t&&o)return `${t}://${o}`;throw new Error("No origin could be determined")}var G="/auth/login",qe=16,R={ANON:{allowedRoute:"/auth/(login|password)",redirectOnUnauth:G},MFA:{allowedRoute:"/auth/mfa",redirectOnUnauth:"/auth/mfa"},AUTHED:{allowedRoute:"*",redirectOnAuth:"/"}},Le={D:"d",H:"h",M:"m",MS:"ms",S:"s",W:"w"};function Ce(){if(!process.env.AUTH_SESSION_EXPIRY)return new lucia.TimeSpan(2,"w");let[e,r]=process.env.AUTH_SESSION_EXPIRY.split(/_/u);return new lucia.TimeSpan(Number(e),Le[r])}var Ve=new adapterDrizzle.DrizzlePostgreSQLAdapter(n,C,i),g=new lucia.Lucia(Ve,{getSessionAttributes:e=>({scope:e.scope}),getUserAttributes:e=>({email:e.email,role:e.role,deletedAt:e.deletedAt}),sessionCookie:{attributes:{secure:process.env.APP_ENV==="production"},name:process.env.AUTH_COOKIE_NAME||"auth_session"},sessionExpiresIn:Ce()});function b(e="",r=qe){return `${e?`${e}_`:""}${lucia.generateId(r)}`}async function X(e){let r=g.createBlankSessionCookie();return (await headers.cookies()).set(r.name,r.value,r.attributes),g.invalidateSession(e)}async function T(e){return g.invalidateUserSessions(e)}async function v(e,r="ANON"){let t=await g.createSession(e,{scope:r}),o=g.createSessionCookie(t.id);return (await headers.cookies()).set(o.name,o.value,o.attributes),!0}async function U(){return (await headers.cookies()).get(g.sessionCookieName)?.value??null}async function tt(){return !!await U()}function He(e,r){let t=Array.isArray(r)?r:[r];return t[0]?t.includes(e):x().includes(e)}async function Y(e){let r=await U();if(!r)return null;let{user:t}=await g.validateSession(r);return !t||t.deletedAt||!He(t.role,e)?null:utility.pick(t,["id","email","role"])}function ze(e,r){return r?r==="*"?!0:pathToRegexp.match(r)(e)!==!1:!1}async function Z(){let e=await $(`${await M()}:scopes`);return e?JSON.parse(e):R}async function Q(e){return (await Z())[e]}async function Je(e){let r={ANON:{...R.ANON,...e?.ANON},MFA:{...R.MFA,...e?.MFA},AUTHED:{...R.AUTHED,...e?.AUTHED}};return B(`${await M()}:scopes`,JSON.stringify(r))}async function We(e,r){let t=await Z(),{session:o,user:s}=await g.validateSession(e),a=t[o&&x().includes(s?.role)?o.scope:"ANON"];return {email:s?.email||null,redirect:ze(r,a.allowedRoute)?null:a.redirectOnUnauth||G}}async function ot(e,r){let t=e.nextUrl.searchParams.get("id")||"",o=e.nextUrl.searchParams.get("pathname")||"/";return await Je(r),server.NextResponse.json(await We(t,o))}function w(){return process.env.AUTH_MFA_ENABLED!=="false"}async function ft(e,r){if(!w())throw new Error("MFA is not enabled. Cannot generate MFA secret.");if(!r)return null;let[t]=await n.select().from(i).where(drizzleOrm.eq(i.email,r)).limit(1);if(!t)return null;let o=otplib.authenticator.generateSecret(),s=otplib.authenticator.keyuri(r,e,o);return await n.delete(u).where(drizzleOrm.and(drizzleOrm.eq(u.userId,t.id),drizzleOrm.isNull(u.verifiedAt))),await n.insert(u).values({id:b(),name:"Default",secret:o,userId:t.id}),new Promise((a,m)=>{Ke__default.default.toDataURL(s,{rendererOpts:{quality:1},margin:0,scale:2},(D,fe)=>{D&&m(D),a(fe);});})}async function gt(e){if(!w())return !1;let[r]=await n.select().from(u).where(drizzleOrm.and(drizzleOrm.eq(u.userId,e.id),drizzleOrm.isNotNull(u.verifiedAt))).limit(1);return !!r}async function Ge(e){w()&&await n.update(u).set({verifiedAt:new Date}).where(drizzleOrm.eq(u.userId,e));}async function Xe(e,r){if(!w())return !1;let[t]=await n.select().from(u).where(drizzleOrm.eq(u.userId,e)).limit(1);return t?otplib.authenticator.check(r,t.secret):!1}async function bt(e){let r=[n.delete(u).where(drizzleOrm.eq(u.userId,e)),T(e)];return await Promise.all(r),!0}async function Ye(e){if(!w())throw new c({token:"MFA is not enabled"});let r=await Y();if(!r)throw new c({token:"User not found"});if(!await Xe(r.id,e.token))throw new c({token:"Invalid token"});return await Ge(r.id),v(r.id,"AUTHED")}async function wt(e){return w()?await y({fn:Ye,formData:e,request:k}):[null,new Error("MFA is not enabled")]}var Ze=12,te={min:8,upper:1,lower:1,number:1,symbol:1};function Qe(e,r){return e.length>=r}function er(e,r){return e.replace(/[^A-Z]/gu,"").length>=r}function rr(e,r){return e.replace(/[^a-z]/gu,"").length>=r}function tr(e,r){return e.replace(/[^0-9]/gu,"").length>=r}function or(e,r){return e.replace(/[^$]/gu,"").length>=r}var nr={min:Qe,upper:er,lower:rr,number:tr,symbol:or};async function F(e){return await re__default.default.hash(e,Ze)}async function O(e,r){return !e||!r?!1:await re__default.default.compare(e,r)}async function sr(e,r=te){let o=Object.entries(r).reduce((s,[a,m])=>(s[a]=nr[a](e,m),s),{});return Promise.resolve(o)}async function oe(e,r=te){let t=await sr(e,r);return Promise.resolve(Object.values(t).every(Boolean))}var ir=f({email:H__default.default.string().email({minDomainSegments:2,tlds:!1}).required(),password:H__default.default.string().min(8).required()}),se=ir;var lr=f({email:H__default.default.string().max(60).email({minDomainSegments:2,tlds:!1}).required().messages({"any.required":"Please provide your email address, so we can send you a reset link","string.empty":"Please provide your email address, so we can send you a reset link","string.email":"Please make sure your email address is valid","string.max":"Please make sure your email address is valid"})}),ie=lr;var ur={lower:1,min:8,number:1,upper:1};async function cr(e,r){return await oe(e,ur)?e:r.message({external:"Please make sure your password is complex enough, to keep your account secure"})}var mr=f({password:H__default.default.string().external(cr).required().messages({"any.required":"Please provide your new password","string.empty":"Please provide your new password"}),token:H__default.default.string().pattern(/[a-z0-9]{40}/u)}),le=mr;var gr=40,br=36e5;async function Ht(){let e=await U();e&&await X(e);}function x(){let e=process.env.AUTH_ROLE;if(!e)throw new Error("AUTH_ROLE is not defined. Authentication will not be possible.");return [Number(e)]}function ue(){let e=x();return Math.max(...e)}async function ce(e){return await v(e,w()?"MFA":"AUTHED"),(await Q("AUTHED"))?.redirectOnAuth||null}async function me(e,r){console.log("[--] getUserByEmail",e,r,ue());let t=[drizzleOrm.eq(i.email,e),drizzleOrm.isNull(i.deletedAt)];r?t.push(drizzleOrm.eq(i.role,r)):t.push(drizzleOrm.lte(i.role,ue()));let[o]=await n.select().from(i).where(drizzleOrm.and(...t)).limit(1);return console.log("[--] user",o),o}async function wr({email:e,password:r}){if(!process.env.AUTH_ROLE)throw new Error("AUTH_ROLE is not defined. Authentication will not be possible.");let t=await me(e,Number(process.env.AUTH_ROLE));if(!t?.password||!await O(r,t.password))throw new c({email:"",password:""});let o=await ce(t.id);if(!o)throw new c({email:"",password:""});return o}async function zt(e,r){return await y({fn:wr,formData:e,onSuccess:async()=>{await r?.();},request:se})}async function Jt({email:e,password:r,role:t}){let o=r?await F(r):null,[s]=await n.insert(i).values({id:b(),email:e,password:o,role:t}).returning();return s}async function de(e,r,t){let[o]=await n.select().from(i).where(drizzleOrm.and(drizzleOrm.eq(i.email,e),drizzleOrm.eq(i.role,r))).limit(1);return o?(await n.update(i).set({deletedAt:t}).where(drizzleOrm.eq(i.id,o.id)),!0):!1}async function Wt(e,r){return de(e,r,new Date)}async function $t(e,r){return de(e,r,null)}async function hr(e){console.log("[--] createPasswordResetToken",e);let r=await me(e);if(console.log("[--] user",r),!r)return null;await n.delete(p).where(drizzleOrm.eq(p.userId,r.id));let t=b("",gr);return await n.insert(p).values({id:t,userId:r.id,expiresAt:new Date(new Date().getTime()+br)}),t}async function Bt(e,r){console.log("[--] handlePasswordForm",e);async function t(s){console.log("[--] mutateFn",s);let a=await hr(s.email);return console.log("[--] token",a),a?r(s.email,a):!0}return await y({fn:t,formData:e,request:ie})}async function yr(e,r){let[t]=await n.select().from(p).where(drizzleOrm.eq(p.id,e)).limit(1);if(!t)throw new Error("PASSWORD_RESET_TOKEN_NOT_FOUND");if(await n.delete(p).where(drizzleOrm.eq(p.id,e)),t.expiresAt<new Date)throw new Error("PASSWORD_RESET_TOKEN_EXPIRED");return await T(t.userId),await n.update(i).set({password:await F(r)}).where(drizzleOrm.and(drizzleOrm.eq(i.id,t.userId),drizzleOrm.inArray(i.role,x()))),t.userId}async function Kt(e,r){async function t(s){let a=await yr(s.token,s.password),m=await ce(a);if(!m)throw new Error("COULD_NOT_CREATE_SESSION");return m}return await y({fn:t,formData:e,onSuccess:r,request:le})}var Ar=16,Pr=64;async function ro(e){let[r]=await n.select().from(h).where(drizzleOrm.eq(h.id,e)).limit(1);return r}async function to({alias:e,id:r,secret:t}){let[o]=await n.insert(h).values({alias:e,id:r||b("",Ar),secret:await F(t||b("",Pr))}).returning();return o}async function oo(e){let{headers:r}=e,t=r.get("authorization");if(!t)return null;let o=Buffer.from(t.replace("Basic ",""),"base64").toString("utf-8").replace(/:$/u,""),[s,...a]=o.split("-"),[m]=await n.select().from(h).where(drizzleOrm.eq(h.id,s)).limit(1);return m&&await O(a.join(""),m.secret)?m:null}
2
+ exports.MFARequest=k;exports.checkMFAEnabled=w;exports.checkPasswordComplexity=oe;exports.checkRouteAllowed=ze;exports.checkSessionExists=tt;exports.checkUserHasMFA=gt;exports.createUserSession=v;exports.deleteMFA=bt;exports.deleteUser=Wt;exports.generateID=b;exports.generateMFA=ft;exports.getAllowedRoles=x;exports.getClientByID=ro;exports.getMaximumRole=ue;exports.getPasswordComplexity=sr;exports.getScopeByID=Q;exports.getScopes=Z;exports.getSessionID=U;exports.getSessionUser=Y;exports.getUserByEmail=me;exports.handleClientAuth=oo;exports.handleLoginForm=zt;exports.handleLogout=Ht;exports.handleMFA=Ye;exports.handleMFAForm=wt;exports.handlePasswordForm=Bt;exports.handlePasswordResetWithTokenForm=Kt;exports.handleSession=ot;exports.hashPassword=F;exports.invalidateSession=X;exports.invalidateUserSessions=T;exports.lucia=g;exports.registerClient=to;exports.registerUser=Jt;exports.setScopes=Je;exports.undeleteUser=$t;exports.verifyPassword=O;//# sourceMappingURL=index.cjs.map
3
3
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/database/DatabaseService.ts","../../src/database/schema.ts","../../src/forms/ValidationError.ts","../../src/forms/ValidationService.ts","../../src/forms/lang.ts","../../src/forms/FormService.ts","../../src/auth/MFARequest.ts","../../src/cache/CacheService.ts","../../src/url/URLService.ts","../../src/auth/SessionService.ts","../../src/auth/MFAService.ts","../../src/auth/PasswordService.ts","../../src/auth/LoginRequest.ts","../../src/auth/PasswordRequest.ts","../../src/auth/PasswordResetWithTokenRequest.ts","../../src/auth/AuthService.ts","../../src/auth/ClientService.ts"],"names":["createSingleton","drizzle","postgres","db","DEFAULT_ROLE","mfaType","pgEnum","scope","authSchema","pgSchema","authUserTable","text","integer","timestamp","table","uniqueIndex","authSessionTable","authResetTable","authMFATable","authClientTable","ValidationError","messages","ValidationError_default","lang_default","getErrorMessages","acc","key","value","transformErrors","error","cur","validateSchema","formData","validation","err","Joi","createSchema","schema","serializeError","hasFn","args","submitForm","data","validated","validationError","model","MFARequest","MFARequest_default","client","isLocalhost","url","getClient","createClient","getFromCache","setToCache","getOrigin","envOrigin","origin","headers","proto","host","DEFAULT_REDIRECT","ID_LENGTH","DEFAULT_SCOPES","timespanMap","getSessionExpiry","TimeSpan","unit","adapter","DrizzlePostgreSQLAdapter","lucia","Lucia","attributes","generateID","prefix","length","generateId","invalidateSession","id","cookie","cookies","invalidateUserSessions","createUserSession","session","sessionCookie","getSessionID","checkSessionExists","checkUserRole","userRole","targetRoles","targetRolesArray","getAllowedRoles","getSessionUser","roles","sessionID","user","pick","checkRouteAllowed","pathname","route","match","getScopes","scopes","getScopeByID","setScopes","customScopes","validateSessionFromID","handleSession","request","NextResponse","checkMFAEnabled","generateMFA","name","email","eq","secret","authenticator","otpauth","and","isNull","resolve","reject","qrcode","checkUserHasMFA","mfa","isNotNull","markAsVerified","userID","validateUserToken","token","deleteMFA","promises","handleMFA","handleMFAForm","PW_SALT_ROUNDS","PASSWORD_RULES","checkPasswordMin","password","checkPasswordUpper","checkPasswordLower","checkPasswordNumber","checkPasswordSymbol","PASSWORD_FUNCTIONS","hashPassword","bcrypt","verifyPassword","encrypted","getPasswordComplexity","rules","validity","rule","checkPasswordComplexity","LoginRequest","LoginRequest_default","PasswordRequest","PasswordRequest_default","passwordComplexity","passwordIsComplex","helpers","PasswordResetWithTokenRequest","PasswordResetWithTokenRequest_default","RESET_TOKEN_LENGTH","RESET_TOKEN_EXPIRY","handleLogout","role","getMaximumRole","handleUserSession","getUserByEmail","conditions","lte","loginUser","handleLoginForm","onSuccess","registerUser","hash","updateDeletedAt","deletedAt","deleteUser","undeleteUser","createPasswordResetToken","handlePasswordForm","mailFn","mutateFn","validatePasswordResetToken","result","inArray","handlePasswordResetWithTokenForm","SECRET_LENGTH","getClientByID","registerClient","alias","handleClientAuth","header","auth"],"mappings":"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","file":"index.cjs","sourcesContent":["import { drizzle } from 'drizzle-orm/postgres-js';\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\nimport postgres from 'postgres';\n\ndeclare global {\n var szdb: ReturnType<typeof createSingleton> | undefined; // eslint-disable-line no-var, vars-on-top\n}\n\nfunction createSingleton(): PostgresJsDatabase {\n if (!process.env.DATABASE_URL) {\n throw new Error('DATABASE_URL is not defined');\n }\n return drizzle(postgres(process.env.DATABASE_URL, { prepare: false }));\n}\n\nexport const db = globalThis.szdb ?? createSingleton();\n\nif (!process.env.VERCEL_ENV) {\n globalThis.szdb = db;\n}\n","/* istanbul ignore file */\n\nimport { integer, pgEnum, pgSchema, text, timestamp, uniqueIndex } from 'drizzle-orm/pg-core';\n\nconst DEFAULT_ROLE = 10;\n\nexport const mfaType = pgEnum('mfaType', ['TOTP', 'HARDWARE']);\nexport const scope = pgEnum('scope', ['ANON', 'MFA', 'AUTHED']);\n\nexport type Scope = (typeof scope.enumValues)[number];\n\nexport const authSchema = pgSchema('auth');\n\nexport const authUserTable = authSchema.table(\n 'user_credentials',\n {\n id: text('id').primaryKey(),\n email: text('email').notNull(),\n password: text('password'),\n role: integer('role').notNull().default(DEFAULT_ROLE),\n deletedAt: timestamp('deletedAt'),\n },\n (table) => ({\n unique: uniqueIndex().on(table.email, table.role),\n })\n);\n\nexport type AuthUser = typeof authUserTable.$inferSelect;\n\nexport const authSessionTable = authSchema.table('sessions', {\n id: text('id').primaryKey(),\n userId: text('userId')\n .notNull()\n .references(() => authUserTable.id, { onDelete: 'cascade' }),\n scope: scope('scope').notNull().default('ANON'),\n expiresAt: timestamp('expiresAt').notNull(),\n});\n\nexport type AuthSession = typeof authSessionTable.$inferSelect;\n\nexport const authResetTable = authSchema.table('resets', {\n id: text('id').primaryKey(),\n userId: text('userId')\n .notNull()\n .references(() => authUserTable.id, { onDelete: 'cascade' }),\n expiresAt: timestamp('expiresAt').notNull(),\n});\n\nexport type AuthReset = typeof authResetTable.$inferSelect;\n\nexport const authMFATable = authSchema.table('mfas', {\n id: text('id').primaryKey(),\n name: text('name').notNull(),\n userId: text('userId')\n .notNull()\n .references(() => authUserTable.id, { onDelete: 'cascade' }),\n type: mfaType('type').notNull().default('TOTP'),\n secret: text('secret').notNull(),\n verifiedAt: timestamp('verifiedAt'),\n});\n\nexport type AuthMFA = typeof authMFATable.$inferSelect;\n\nexport const authClientTable = authSchema.table('client_credentials', {\n id: text('id').primaryKey(),\n alias: text('alias').notNull().unique(),\n secret: text('secret').notNull().unique(),\n});\n\nexport type AuthClient = typeof authClientTable.$inferSelect;\n","class ValidationError extends Error {\n public messages: Record<string, string>;\n\n public constructor(messages: Record<string, string>) {\n super(JSON.stringify(messages));\n\n this.messages = messages;\n this.name = 'ValidationError';\n }\n}\n\nexport default ValidationError;\n","import type { Errorable } from '@sqrzro/interfaces';\nimport Joi from 'joi';\n\nimport lang from './lang';\nimport ValidationError from './ValidationError';\n\nexport function validate(): typeof Joi {\n return Joi;\n}\n\nexport type ValidationCustomHelpers<V = any> = Joi.CustomHelpers<V>; // eslint-disable-line @typescript-eslint/no-explicit-any\nexport type ValidationExternalHelpers<V = any> = Joi.ExternalHelpers<V>; // eslint-disable-line @typescript-eslint/no-explicit-any\nexport type ValidationErrorReport = Joi.ErrorReport;\n\nexport function getDefaultErrorMessages(): Record<string, string> {\n return lang;\n}\n\nfunction getErrorMessages(): Record<string, string> {\n return Object.entries(lang).reduce((acc, [key, value]) => {\n if (!value) {\n return acc;\n }\n return {\n ...acc,\n [key]: value,\n };\n }, {});\n}\n\nfunction transformErrors(error: Joi.ValidationError): ValidationError {\n const messages = error.details.reduce(\n (acc, cur) => ({\n ...acc,\n [cur.path.join('.')]: cur.message.replace(/\"/gu, ''),\n }),\n {}\n );\n return new ValidationError(messages);\n}\n\n/**\n * This function takes FormData and a schema. It then attempts to transform the FormData into an\n * object that matches `T`. This is because the FormData object is not typed and we want to be able\n * to validate it properly typed.\n *\n * Once transformed, the object is validated against the schema. This will result in either a\n * properly typed `T` object or an array of validation errors.\n * @param formData\n * @param validation\n * @returns\n */\nexport async function validateSchema<T>(\n formData: Partial<T>,\n validation: Joi.ObjectSchema<T>,\n messages?: Record<string, string>\n): Promise<Errorable<T>> {\n try {\n const validated = await validation.validateAsync(formData, {\n abortEarly: false,\n messages: messages || getErrorMessages(),\n stripUnknown: true,\n });\n\n return [validated, null];\n } catch (err) {\n if (err instanceof Joi.ValidationError) {\n return [null, transformErrors(err)];\n }\n\n if (err instanceof Error) {\n return [null, err];\n }\n\n return [null, new Error('Unknown validation error occured')];\n }\n}\n\nexport function createSchema<T>(schema: Joi.SchemaMap<T, true>): Joi.ObjectSchema<T> {\n return Joi.object<T>(schema);\n}\n\nexport function extendSchema<T, U extends T>(\n schema: Joi.ObjectSchema<T>,\n appends: Joi.PartialSchemaMap<U>\n): Joi.ObjectSchema<U> {\n return schema.append<U>(appends);\n}\n","const messages: Record<string, string> = {\n 'alternatives.all': '',\n 'alternatives.any': '',\n 'alternatives.match': '',\n 'alternatives.one': '',\n 'alternatives.types': '',\n 'any.custom': '',\n 'any.default': '',\n 'any.failover': '',\n 'any.invalid': '',\n 'any.only': '',\n 'any.ref': '',\n 'any.required': '{{#label}} is required',\n 'any.unknown': '',\n 'array.base': '',\n 'array.excludes': '',\n 'array.includesRequiredBoth': '',\n 'array.includesRequiredKnowns': '',\n 'array.includesRequiredUnknowns': '',\n 'array.includes': '',\n 'array.length': '',\n 'array.max': '',\n 'array.min': '',\n 'array.orderedLength': '',\n 'array.sort': '',\n 'array.sort.mismatching': '',\n 'array.sort.unsupported': '',\n 'array.sparse': '',\n 'array.unique': '',\n 'array.hasKnown': '',\n 'array.hasUnknown': '',\n 'binary.base': '',\n 'binary.length': '',\n 'binary.max': '',\n 'binary.min': '',\n 'boolean.base': '',\n 'date.base': '',\n 'date.format': '',\n 'date.greater': '',\n 'date.less': '',\n 'date.max': '',\n 'date.min': '',\n 'date.strict': '',\n 'function.arity': '',\n 'function.class': '',\n 'function.maxArity': '',\n 'function.minArity': '',\n 'number.base': '{{#label}} should be a number',\n 'number.greater': '',\n 'number.infinity': '',\n 'number.integer': '',\n 'number.less': '',\n 'number.max': '',\n 'number.min': '{{#label}} should be greater than or equal to {{#limit}}',\n 'number.multiple': '',\n 'number.negative': '',\n 'number.port': '',\n 'number.positive': '',\n 'number.precision': '',\n 'number.unsafe': '',\n 'object.unknown': '',\n 'object.and': '',\n 'object.assert': '',\n 'object.base': '',\n 'object.length': '',\n 'object.max': '',\n 'object.min': '',\n 'object.missing': '',\n 'object.nand': '',\n 'object.pattern.match': '',\n 'object.refType': '',\n 'object.regex': '',\n 'object.rename.multiple': '',\n 'object.rename.override': '',\n 'object.schema': '',\n 'object.instance': '',\n 'object.with': '',\n 'object.without': '',\n 'object.xor': '',\n 'object.oxor': '',\n 'string.alphanum': '',\n 'string.base64': '',\n 'string.base': '',\n 'string.creditCard': '',\n 'string.dataUri': '',\n 'string.domain': '',\n 'string.email': '',\n 'string.empty': '{{#label}} is required',\n 'string.guid': '',\n 'string.hexAlign': '',\n 'string.hex': '',\n 'string.hostname': '',\n 'string.ipVersion': '',\n 'string.ip': '',\n 'string.isoDate': '',\n 'string.isoDuration': '',\n 'string.length': '',\n 'string.lowercase': '',\n 'string.max': '',\n 'string.min': '',\n 'string.normalize': '',\n 'string.pattern.base': '{{#label}} is not in the correct format',\n 'string.pattern.name': '',\n 'string.pattern.invert.base': '',\n 'string.pattern.invert.name': '',\n 'string.token': '',\n 'string.trim': '',\n 'string.uppercase': '',\n 'string.uri': '',\n 'string.uriCustomScheme': '',\n 'string.uriRelativeOnly': '',\n 'symbol.base': '',\n 'symbol.map': '',\n};\n\nexport default messages;\n","/* eslint-disable max-statements */\n\nimport type { SerializedError, SerializedErrorable } from '@sqrzro/interfaces';\nimport type Joi from 'joi';\nimport { NextResponse } from 'next/server';\n\nimport ValidationError from './ValidationError';\nimport { validateSchema } from './ValidationService';\n\nfunction serializeError(err: Error): SerializedError {\n return {\n cause: err.cause,\n message: err.message,\n name: err.name,\n stack: err.stack,\n };\n}\n\ninterface SubmitFormArgs<F extends object> {\n formData: F;\n onSuccess?: (model: F) => Promise<void> | void;\n onValidationError?: (error: ValidationError) => void;\n request?: Joi.ObjectSchema<F>;\n}\n\ninterface SubmitFormArgsWithFn<F extends object, M> extends Omit<SubmitFormArgs<F>, 'onSuccess'> {\n fn: (data: F) => Promise<M | null>;\n onSuccess?: (model: M) => Promise<void> | void;\n}\n\nfunction hasFn<F extends object, M>(\n args: SubmitFormArgs<F> | SubmitFormArgsWithFn<F, M>\n): args is SubmitFormArgsWithFn<F, M> {\n return Boolean(Object.prototype.hasOwnProperty.call(args, 'fn'));\n}\n\nexport async function submitForm<F extends object>(\n args: SubmitFormArgs<F>\n): Promise<SerializedErrorable<F>>;\nexport async function submitForm<F extends object, M>(\n args: SubmitFormArgsWithFn<F, M>\n): Promise<SerializedErrorable<M>>;\n\nexport async function submitForm<F extends object, M>(\n args: SubmitFormArgs<F> | SubmitFormArgsWithFn<F, M>\n): Promise<[F, null] | [M, null] | [null, SerializedError]> {\n let data = { ...args.formData };\n\n if (args.request) {\n const [validated, validationError] = await validateSchema<F>(args.formData, args.request);\n\n if (validationError !== null) {\n if (validationError instanceof ValidationError) {\n args.onValidationError?.(validationError);\n }\n\n return [null, serializeError(validationError)];\n }\n\n data = validated;\n }\n\n if (!hasFn(args)) {\n await args.onSuccess?.(data);\n return [data, null];\n }\n\n let model: Awaited<M> | null = null;\n\n try {\n model = await args.fn(data);\n } catch (err: unknown) {\n if (err instanceof ValidationError) {\n args.onValidationError?.(err);\n return [null, serializeError(err)];\n }\n if (err instanceof Error) {\n throw err;\n }\n throw new Error('The function supplied to submitForm encountered an unknown error');\n }\n\n if (!model) {\n throw new Error('NO_MODEL');\n }\n\n await args.onSuccess?.(model);\n return [model, null];\n}\n\nexport async function submitAPIRequest<F extends object, M>(\n args: SubmitFormArgsWithFn<F, M>\n): Promise<[M, null] | [null, NextResponse]> {\n const [response, error] = await submitForm<F, M>(args);\n\n if (error !== null) {\n if (error.name === 'ValidationError') {\n try {\n const errors = JSON.parse(error.message) as Record<string, string>;\n return [null, NextResponse.json(errors, { status: 422 })];\n } catch (err) {\n return [\n null,\n NextResponse.json({ message: 'An unknown error occured' }, { status: 500 }),\n ];\n }\n }\n return [null, NextResponse.json({ message: error.message }, { status: 500 })];\n }\n\n return [response, null];\n}\n","/* eslint-disable @typescript-eslint/no-magic-numbers */\n\nimport Joi from 'joi';\n\nimport { createSchema } from '../forms/ValidationService';\nimport type { MFAFormFields } from './interfaces';\n\nconst MFARequest = createSchema<MFAFormFields>({\n token: Joi.string()\n .pattern(/^[0-9]{6}$/u)\n .required(),\n});\n\nexport default MFARequest;\n","import { createClient } from 'redis';\n\nlet client: ReturnType<typeof createClient> | null = null;\n\nfunction isLocalhost(url: string): boolean {\n return url.includes('localhost') || url.includes('127.0.0.1');\n}\n\nasync function getClient(): Promise<ReturnType<typeof createClient>> {\n if (!process.env.REDIS_URL) {\n throw new Error('REDIS_URL is not defined. Access to the cache is not possible.');\n }\n\n if (client) {\n return client;\n }\n\n client = createClient({\n socket: {\n tls: !isLocalhost(process.env.REDIS_URL),\n },\n url: process.env.REDIS_URL,\n });\n\n await client.connect();\n return client;\n}\n\nexport async function getFromCache(key: string): Promise<string | null> {\n return (await getClient()).get(key);\n}\n\nexport async function setToCache(key: string, value: string): Promise<void> {\n await (await getClient()).set(key, value);\n}\n","import { headers } from 'next/headers';\n\n/**\n * Uses a number of methods to determine the current origin.\n *\n * First, it checks if an `x-origin` header. This will have been set by the `handleMiddleware`\n * function, further up the chain. For more information on how it is being set, see the\n * `middleware` documentation.\n *\n * There are some situations where middleware is not being applied, such as API routes (because the\n * redirection is not necessary, and API routes handle their own authentication). In these cases,\n * this function tries to piece together the origin from the `x-forwarded-proto` and\n * `x-forwarded-host` headers.\n *\n * Finally, if the origin cannot be determined, an error is thrown.\n *\n * @returns The origin of the current request.\n */\nexport async function getOrigin(): Promise<string> {\n const envOrigin = process.env.SZ_ORIGIN;\n\n if (envOrigin) {\n return envOrigin;\n }\n\n const origin = (await headers()).get('x-origin');\n\n if (origin) {\n return origin;\n }\n\n const proto = (await headers()).get('x-forwarded-proto');\n const host = (await headers()).get('x-forwarded-host');\n\n if (proto && host) {\n return `${proto}://${host}`;\n }\n\n throw new Error('No origin could be determined');\n}\n\nexport async function getPathname(): Promise<string> {\n const pathname = (await headers()).get('x-pathname');\n\n if (pathname) {\n return pathname;\n }\n\n throw new Error(\n 'No pathname could be determined. Please make sure middleware is being applied to the current request.'\n );\n}\n\n/**\n * Builds a URL from the current origin and a given pathname. For more information on how the origin\n * is determined, see the `getOrigin` function. This function then just concatenates the origin and\n * the pathname, and performs some cleanup to ensure the URL is valid.\n *\n * @param pathname\n * @returns The URL, with the origin and pathname combined.\n */\nexport async function makeURL(pathname?: string): Promise<string> {\n const origin = await getOrigin();\n\n if (!pathname) {\n return origin;\n }\n\n const isSecure = origin.startsWith('https://');\n\n const protocol = isSecure ? 'https://' : 'http://';\n const originWithoutProtocol = origin.replace(/^https?:\\/\\//u, '');\n\n const cleanURL = `${originWithoutProtocol}/${pathname}`.replace(/\\/+/gu, '/');\n return `${protocol}${cleanURL}`;\n}\n\n/**\n * @deprecated Use `makeURL` instead.\n */\nexport async function getURL(pathname?: string): Promise<string> {\n return makeURL(pathname);\n}\n","import { DrizzlePostgreSQLAdapter } from '@lucia-auth/adapter-drizzle';\nimport { pick } from '@sqrzro/utility';\nimport { Lucia, TimeSpan, generateId } from 'lucia';\nimport { cookies } from 'next/headers';\nimport { NextResponse } from 'next/server';\nimport type { NextRequest } from 'next/server';\nimport { match } from 'path-to-regexp';\n\nimport { getAllowedRoles } from './AuthService';\n\nimport { db } from '../database/DatabaseService';\nimport { authSessionTable, authUserTable } from '../database/schema';\nimport type { Scope } from '../database/schema';\n\nimport { getFromCache, setToCache } from '../cache/CacheService';\nimport { getOrigin } from '../url/URLService';\n\nconst DEFAULT_REDIRECT = '/auth/login';\nconst ID_LENGTH = 16;\n\ntype TimeSpanUnit = 'd' | 'h' | 'm' | 'ms' | 's' | 'w';\n\ninterface ScopeData {\n allowedRoute?: string;\n redirectOnAuth?: string;\n redirectOnUnauth?: string;\n}\n\nexport type ScopeObject = Record<Scope, ScopeData>;\n\ninterface DatabaseSessionAttributes {\n scope: Scope;\n}\n\ninterface DatabaseUserAttributes {\n email: string;\n role: number;\n deletedAt?: Date | null;\n}\n\ndeclare module 'lucia' {\n interface Register {\n Lucia: typeof lucia;\n DatabaseSessionAttributes: DatabaseSessionAttributes;\n DatabaseUserAttributes: DatabaseUserAttributes;\n }\n}\n\nconst DEFAULT_SCOPES: ScopeObject = {\n ANON: {\n allowedRoute: '/auth/(login|password)',\n redirectOnUnauth: DEFAULT_REDIRECT,\n },\n MFA: {\n allowedRoute: '/auth/mfa',\n redirectOnUnauth: '/auth/mfa',\n },\n AUTHED: {\n allowedRoute: '*',\n redirectOnAuth: '/',\n },\n};\n\n/* eslint-disable id-length */\nconst timespanMap: Record<string, TimeSpanUnit> = {\n D: 'd',\n H: 'h',\n M: 'm',\n MS: 'ms',\n S: 's',\n W: 'w',\n};\n/* eslint-enable id-length */\n\nfunction getSessionExpiry(): TimeSpan {\n if (!process.env.AUTH_SESSION_EXPIRY) {\n return new TimeSpan(2, 'w');\n }\n\n const [value, unit] = process.env.AUTH_SESSION_EXPIRY.split(/_/u);\n return new TimeSpan(Number(value), timespanMap[unit]);\n}\n\nconst adapter = new DrizzlePostgreSQLAdapter(db, authSessionTable, authUserTable);\n\nexport const lucia = new Lucia(adapter, {\n getSessionAttributes: (attributes: DatabaseSessionAttributes): DatabaseSessionAttributes => ({\n scope: attributes.scope,\n }),\n getUserAttributes: (attributes: DatabaseUserAttributes): DatabaseUserAttributes => ({\n email: attributes.email,\n role: attributes.role,\n deletedAt: attributes.deletedAt,\n }),\n sessionCookie: {\n attributes: {\n secure: process.env.APP_ENV === 'production',\n },\n name: process.env.AUTH_COOKIE_NAME || 'auth_session',\n },\n sessionExpiresIn: getSessionExpiry(),\n});\n\nexport function generateID<T extends string = string>(prefix = '', length = ID_LENGTH): T {\n return `${prefix ? `${prefix}_` : ''}${generateId(length)}` as T;\n}\n\nexport async function invalidateSession(id: string): Promise<void> {\n const cookie = lucia.createBlankSessionCookie();\n (await cookies()).set(cookie.name, cookie.value, cookie.attributes);\n\n return lucia.invalidateSession(id);\n}\n\nexport async function invalidateUserSessions(id: string): Promise<void> {\n return lucia.invalidateUserSessions(id);\n}\n\nexport async function createUserSession(id: string, scope: Scope = 'ANON'): Promise<boolean> {\n const session = await lucia.createSession(id, { scope });\n const sessionCookie = lucia.createSessionCookie(session.id);\n (await cookies()).set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);\n\n return true;\n}\n\nexport async function getSessionID(): Promise<string | null> {\n return (await cookies()).get(lucia.sessionCookieName)?.value ?? null;\n}\n\nexport async function checkSessionExists(): Promise<boolean> {\n return Boolean(await getSessionID());\n}\n\nfunction checkUserRole(userRole: number, targetRoles?: number[] | number): boolean {\n const targetRolesArray = Array.isArray(targetRoles) ? targetRoles : [targetRoles];\n\n if (targetRolesArray[0]) {\n return targetRolesArray.includes(userRole);\n }\n\n return getAllowedRoles().includes(userRole);\n}\n\nexport async function getSessionUser(roles?: number[] | number): Promise<{\n id: string;\n email: string;\n role: number;\n} | null> {\n const sessionID = await getSessionID();\n\n if (!sessionID) {\n return null;\n }\n\n const { user } = await lucia.validateSession(sessionID);\n\n if (!user || user.deletedAt || !checkUserRole(user.role, roles)) {\n return null;\n }\n\n return pick(user, ['id', 'email', 'role']);\n}\n\nexport function checkRouteAllowed(pathname: string, route?: string): boolean {\n if (!route) {\n return false;\n }\n\n if (route === '*') {\n return true;\n }\n\n return match(route)(pathname) !== false;\n}\n\nexport async function getScopes(): Promise<ScopeObject> {\n const scopes = await getFromCache(`${await getOrigin()}:scopes`);\n return scopes ? (JSON.parse(scopes) as ScopeObject) : DEFAULT_SCOPES;\n}\n\nexport async function getScopeByID(id: Scope): Promise<ScopeData> {\n const scopes = await getScopes();\n return scopes[id];\n}\n\nexport async function setScopes(customScopes?: Partial<ScopeObject>): Promise<void> {\n const scopes = {\n ANON: {\n ...DEFAULT_SCOPES.ANON,\n ...customScopes?.ANON,\n },\n MFA: {\n ...DEFAULT_SCOPES.MFA,\n ...customScopes?.MFA,\n },\n AUTHED: {\n ...DEFAULT_SCOPES.AUTHED,\n ...customScopes?.AUTHED,\n },\n };\n\n return setToCache(`${await getOrigin()}:scopes`, JSON.stringify(scopes));\n}\n\nasync function validateSessionFromID(\n sessionID: string,\n pathname: string\n): Promise<{ redirect: string | null; email: string | null }> {\n const scopes = await getScopes();\n const { session, user } = await lucia.validateSession(sessionID);\n\n const scope =\n scopes[session && getAllowedRoles().includes(user?.role) ? session.scope : 'ANON'];\n\n return {\n email: user?.email || null,\n redirect: checkRouteAllowed(pathname, scope.allowedRoute)\n ? null\n : scope.redirectOnUnauth || DEFAULT_REDIRECT,\n };\n}\n\nexport async function handleSession(\n request: NextRequest,\n customScopes?: Partial<ScopeObject>\n): Promise<NextResponse> {\n const sessionID = request.nextUrl.searchParams.get('id') || '';\n const pathname = request.nextUrl.searchParams.get('pathname') || '/';\n\n await setScopes(customScopes);\n\n return NextResponse.json(await validateSessionFromID(sessionID, pathname));\n}\n","import type { Errorable } from '@sqrzro/interfaces';\nimport { and, eq, isNotNull, isNull } from 'drizzle-orm';\nimport { authenticator } from 'otplib';\nimport qrcode from 'qrcode';\n\nimport { db } from '../database/DatabaseService';\nimport { authMFATable, authUserTable } from '../database/schema';\n\nimport { submitForm } from '../forms/FormService';\nimport ValidationError from '../forms/ValidationError';\n\nimport MFARequest from './MFARequest';\nimport {\n createUserSession,\n generateID,\n getSessionUser,\n invalidateUserSessions,\n} from './SessionService';\nimport type { MFAFormFields, UserObject } from './interfaces';\n\nexport function checkMFAEnabled(): boolean {\n return process.env.AUTH_MFA_ENABLED !== 'false';\n}\n\nexport async function generateMFA(name: string, email?: string): Promise<string | null> {\n if (!checkMFAEnabled()) {\n throw new Error('MFA is not enabled. Cannot generate MFA secret.');\n }\n\n if (!email) {\n return null;\n }\n\n const [user] = await db\n .select()\n .from(authUserTable)\n .where(eq(authUserTable.email, email))\n .limit(1);\n\n if (!user) {\n return null;\n }\n\n const secret = authenticator.generateSecret();\n const otpauth = authenticator.keyuri(email, name, secret);\n\n // Delete all the unverified MFA entries for this user\n\n await db\n .delete(authMFATable)\n .where(and(eq(authMFATable.userId, user.id), isNull(authMFATable.verifiedAt)));\n\n // Add the new MFA entry\n\n await db.insert(authMFATable).values({\n id: generateID(),\n name: 'Default',\n secret,\n userId: user.id,\n });\n\n return new Promise((resolve, reject) => {\n qrcode.toDataURL(\n otpauth,\n { rendererOpts: { quality: 1 }, margin: 0, scale: 2 },\n (err, data) => {\n if (err) {\n reject(err);\n }\n resolve(data);\n }\n );\n });\n}\n\nexport async function checkUserHasMFA(user: UserObject): Promise<boolean> {\n if (!checkMFAEnabled()) {\n return false;\n }\n\n const [mfa] = await db\n .select()\n .from(authMFATable)\n .where(and(eq(authMFATable.userId, user.id), isNotNull(authMFATable.verifiedAt)))\n .limit(1);\n\n return Boolean(mfa);\n}\n\nasync function markAsVerified(userID: string): Promise<void> {\n if (!checkMFAEnabled()) {\n return;\n }\n\n await db\n .update(authMFATable)\n .set({ verifiedAt: new Date() })\n .where(eq(authMFATable.userId, userID));\n}\n\nasync function validateUserToken(userID: string, token: string): Promise<boolean> {\n if (!checkMFAEnabled()) {\n return false;\n }\n\n const [mfa] = await db\n .select()\n .from(authMFATable)\n .where(eq(authMFATable.userId, userID))\n .limit(1);\n\n if (!mfa) {\n return false;\n }\n\n return authenticator.check(token, mfa.secret);\n}\n\nexport async function deleteMFA(userID: string): Promise<boolean> {\n const promises = [\n db.delete(authMFATable).where(eq(authMFATable.userId, userID)),\n invalidateUserSessions(userID),\n ];\n\n await Promise.all(promises);\n return true;\n}\n\nexport async function handleMFA(data: MFAFormFields): Promise<boolean> {\n if (!checkMFAEnabled()) {\n throw new ValidationError({ token: 'MFA is not enabled' });\n }\n\n const user = await getSessionUser();\n\n if (!user) {\n throw new ValidationError({ token: 'User not found' });\n }\n\n const isValid = await validateUserToken(user.id, data.token);\n\n if (!isValid) {\n throw new ValidationError({ token: 'Invalid token' });\n }\n\n await markAsVerified(user.id);\n return createUserSession(user.id, 'AUTHED');\n}\n\nexport async function handleMFAForm(formData: MFAFormFields): Promise<Errorable<boolean>> {\n if (!checkMFAEnabled()) {\n return [null, new Error('MFA is not enabled')];\n }\n\n const response = await submitForm<MFAFormFields, boolean>({\n fn: handleMFA,\n formData,\n request: MFARequest,\n });\n\n return response;\n}\n","import bcrypt from 'bcryptjs';\n\nconst PW_SALT_ROUNDS = 12;\n\ntype PasswordRule = 'lower' | 'min' | 'number' | 'symbol' | 'upper';\n\nexport type PasswordRuleObject = Partial<Record<PasswordRule, number>>;\ntype PasswordValidityObject = Record<PasswordRule, boolean>;\n\nconst PASSWORD_RULES: PasswordRuleObject = {\n min: 8,\n upper: 1,\n lower: 1,\n number: 1,\n symbol: 1,\n};\n\nfunction checkPasswordMin(password: string, value: number): boolean {\n return password.length >= value;\n}\n\nfunction checkPasswordUpper(password: string, value: number): boolean {\n return password.replace(/[^A-Z]/gu, '').length >= value;\n}\n\nfunction checkPasswordLower(password: string, value: number): boolean {\n return password.replace(/[^a-z]/gu, '').length >= value;\n}\n\nfunction checkPasswordNumber(password: string, value: number): boolean {\n return password.replace(/[^0-9]/gu, '').length >= value;\n}\n\nfunction checkPasswordSymbol(password: string, value: number): boolean {\n return password.replace(/[^$]/gu, '').length >= value;\n}\n\nconst PASSWORD_FUNCTIONS: Record<PasswordRule, (password: string, value: number) => boolean> = {\n min: checkPasswordMin,\n upper: checkPasswordUpper,\n lower: checkPasswordLower,\n number: checkPasswordNumber,\n symbol: checkPasswordSymbol,\n};\n\nexport async function hashPassword(password: string): Promise<string> {\n const hash = await bcrypt.hash(password, PW_SALT_ROUNDS);\n return hash;\n}\n\nexport async function verifyPassword(data?: string, encrypted?: string): Promise<boolean> {\n if (!data || !encrypted) {\n return false;\n }\n\n const verified = await bcrypt.compare(data, encrypted);\n return verified;\n}\n\nexport async function getPasswordComplexity(\n password: string,\n rules: Partial<PasswordRuleObject> = PASSWORD_RULES\n): Promise<Partial<PasswordValidityObject>> {\n const entries = Object.entries(rules) as [PasswordRule, number][];\n\n const validity = entries.reduce<Partial<PasswordValidityObject>>((acc, [rule, value]) => {\n acc[rule] = PASSWORD_FUNCTIONS[rule](password, value);\n return acc;\n }, {});\n\n return Promise.resolve(validity);\n}\n\nexport async function checkPasswordComplexity(\n password: string,\n rules: Partial<PasswordRuleObject> = PASSWORD_RULES\n): Promise<Partial<boolean>> {\n const validity = await getPasswordComplexity(password, rules);\n return Promise.resolve(Object.values(validity).every(Boolean));\n}\n","/* eslint-disable @typescript-eslint/no-magic-numbers */\n\nimport Joi from 'joi';\n\nimport { createSchema } from '../forms/ValidationService';\nimport type { LoginFormFields } from './interfaces';\n\nconst LoginRequest = createSchema<LoginFormFields>({\n email: Joi.string().email({ minDomainSegments: 2, tlds: false }).required(),\n password: Joi.string().min(8).required(),\n});\n\nexport default LoginRequest;\n","/* eslint-disable @typescript-eslint/no-magic-numbers */\n\nimport Joi from 'joi';\n\nimport { createSchema } from '../forms/ValidationService';\nimport type { PasswordFormFields } from './interfaces';\n\nconst PasswordRequest = createSchema<PasswordFormFields>({\n email: Joi.string().max(60).email({ minDomainSegments: 2, tlds: false }).required().messages({\n 'any.required': 'Please provide your email address, so we can send you a reset link',\n 'string.empty': 'Please provide your email address, so we can send you a reset link',\n 'string.email': 'Please make sure your email address is valid',\n 'string.max': 'Please make sure your email address is valid',\n }),\n});\n\nexport default PasswordRequest;\n","import Joi from 'joi';\n\nimport { checkPasswordComplexity } from './PasswordService';\nimport type { PasswordRuleObject } from './PasswordService';\nimport type { ValidationCustomHelpers } from '../forms/ValidationService';\n\nimport { createSchema } from '../forms/ValidationService';\nimport type { PasswordResetWithTokenFormFields } from './interfaces';\n\nconst passwordComplexity: PasswordRuleObject = {\n lower: 1,\n min: 8,\n number: 1,\n upper: 1,\n};\n\nasync function passwordIsComplex(\n value: string,\n helpers: ValidationCustomHelpers\n): Promise<Error | string> {\n if (!(await checkPasswordComplexity(value, passwordComplexity))) {\n return helpers.message({\n external:\n 'Please make sure your password is complex enough, to keep your account secure',\n });\n }\n return value;\n}\n\nconst PasswordResetWithTokenRequest = createSchema<PasswordResetWithTokenFormFields>({\n password: Joi.string().external(passwordIsComplex).required().messages({\n 'any.required': 'Please provide your new password',\n 'string.empty': 'Please provide your new password',\n }),\n token: Joi.string().pattern(/[a-z0-9]{40}/u),\n});\n\nexport default PasswordResetWithTokenRequest;\n","import type { Errorable } from '@sqrzro/interfaces';\nimport { and, eq, inArray, isNull, lte } from 'drizzle-orm';\n\nimport { db } from '../database/DatabaseService';\nimport { authResetTable, authUserTable } from '../database/schema';\n\nimport { submitForm } from '../forms/FormService';\nimport ValidationError from '../forms/ValidationError';\n\nimport { checkMFAEnabled } from './MFAService';\nimport { hashPassword, verifyPassword } from './PasswordService';\nimport {\n createUserSession,\n generateID,\n getScopeByID,\n getSessionID,\n invalidateSession,\n invalidateUserSessions,\n} from './SessionService';\n\nimport LoginRequest from './LoginRequest';\nimport PasswordRequest from './PasswordRequest';\nimport PasswordResetWithTokenRequest from './PasswordResetWithTokenRequest';\n\nimport type {\n LoginFormFields,\n PasswordFormFields,\n PasswordResetWithTokenFormFields,\n UserObject,\n} from './interfaces';\n\nconst RESET_TOKEN_LENGTH = 40;\n\n// Set expiry to 1 hour (in ms)\nconst RESET_TOKEN_EXPIRY = 3600000;\n\nexport async function handleLogout(): Promise<void> {\n const id = await getSessionID();\n\n if (id) {\n await invalidateSession(id);\n }\n}\n\ninterface LoginUserArgs {\n email: string;\n password: string;\n role?: number;\n token?: string;\n}\n\nexport function getAllowedRoles(): number[] {\n const role = process.env.AUTH_ROLE;\n\n if (!role) {\n throw new Error('AUTH_ROLE is not defined. Authentication will not be possible.');\n }\n\n return [Number(role)];\n}\n\nexport function getMaximumRole(): number {\n const roles = getAllowedRoles();\n return Math.max(...roles);\n}\n\nasync function handleUserSession(userID: string): Promise<string | null> {\n await createUserSession(userID, checkMFAEnabled() ? 'MFA' : 'AUTHED');\n\n const scope = await getScopeByID('AUTHED');\n return scope?.redirectOnAuth || null;\n}\n\nexport async function getUserByEmail(email: string, role?: number): Promise<UserObject | null> {\n const conditions = [eq(authUserTable.email, email), isNull(authUserTable.deletedAt)];\n\n if (role) {\n conditions.push(eq(authUserTable.role, role));\n } else {\n conditions.push(lte(authUserTable.role, getMaximumRole()));\n }\n\n const [user] = await db\n .select()\n .from(authUserTable)\n .where(and(...conditions))\n .limit(1);\n\n return user;\n}\n\nasync function loginUser({ email, password }: LoginUserArgs): Promise<string> {\n if (!process.env.AUTH_ROLE) {\n throw new Error('AUTH_ROLE is not defined. Authentication will not be possible.');\n }\n\n const user = await getUserByEmail(email, Number(process.env.AUTH_ROLE));\n\n if (!user?.password || !(await verifyPassword(password, user.password))) {\n throw new ValidationError({ email: '', password: '' });\n }\n\n const session = await handleUserSession(user.id);\n\n if (!session) {\n throw new ValidationError({ email: '', password: '' });\n }\n\n return session;\n}\n\nexport async function handleLoginForm(\n formData: LoginFormFields,\n onSuccess?: () => Promise<void>\n): Promise<Errorable<string>> {\n const response = await submitForm<LoginFormFields, string>({\n fn: loginUser,\n formData,\n onSuccess: async () => {\n await onSuccess?.();\n },\n request: LoginRequest,\n });\n\n return response;\n}\n\ninterface RegisterUserArgs {\n email: string;\n password?: string;\n role?: number;\n}\n\nexport async function registerUser({\n email,\n password,\n role,\n}: RegisterUserArgs): Promise<UserObject | null> {\n const hash = password ? await hashPassword(password) : null;\n\n const [user] = await db\n .insert(authUserTable)\n .values({ id: generateID(), email, password: hash, role })\n .returning();\n\n return user;\n}\n\nasync function updateDeletedAt(\n email: string,\n role: number,\n deletedAt: Date | null\n): Promise<boolean> {\n const [user] = await db\n .select()\n .from(authUserTable)\n .where(and(eq(authUserTable.email, email), eq(authUserTable.role, role)))\n .limit(1);\n\n if (!user) {\n return false;\n }\n\n await db.update(authUserTable).set({ deletedAt }).where(eq(authUserTable.id, user.id));\n\n return true;\n}\n\nexport async function deleteUser(email: string, role: number): Promise<boolean> {\n return updateDeletedAt(email, role, new Date());\n}\n\nexport async function undeleteUser(email: string, role: number): Promise<boolean> {\n return updateDeletedAt(email, role, null);\n}\n\nasync function createPasswordResetToken(email: string): Promise<string | null> {\n const user = await getUserByEmail(email);\n\n if (!user) {\n return null;\n }\n\n await db.delete(authResetTable).where(eq(authResetTable.userId, user.id));\n\n const id = generateID('', RESET_TOKEN_LENGTH);\n\n await db.insert(authResetTable).values({\n id,\n userId: user.id,\n expiresAt: new Date(new Date().getTime() + RESET_TOKEN_EXPIRY),\n });\n\n return id;\n}\n\nexport async function handlePasswordForm(\n formData: PasswordFormFields,\n mailFn: (email: string, token: string) => Promise<boolean>\n): Promise<Errorable<boolean>> {\n async function mutateFn(data: PasswordFormFields): Promise<boolean> {\n const token = await createPasswordResetToken(data.email);\n\n if (!token) {\n // Return true, even though the email doesn't exist (to prevent user enumeration)\n return true;\n }\n\n return mailFn(data.email, token);\n }\n\n const response = await submitForm<PasswordFormFields, boolean>({\n fn: mutateFn,\n formData,\n request: PasswordRequest,\n });\n\n return response;\n}\n\nasync function validatePasswordResetToken(token: string, password: string): Promise<string> {\n const [result] = await db\n .select()\n .from(authResetTable)\n .where(eq(authResetTable.id, token))\n .limit(1);\n\n if (!result) {\n throw new Error('PASSWORD_RESET_TOKEN_NOT_FOUND');\n }\n\n await db.delete(authResetTable).where(eq(authResetTable.id, token));\n\n if (result.expiresAt < new Date()) {\n throw new Error('PASSWORD_RESET_TOKEN_EXPIRED');\n }\n\n await invalidateUserSessions(result.userId);\n\n await db\n .update(authUserTable)\n .set({ password: await hashPassword(password) })\n .where(\n and(eq(authUserTable.id, result.userId), inArray(authUserTable.role, getAllowedRoles()))\n );\n\n return result.userId;\n}\n\nexport async function handlePasswordResetWithTokenForm(\n formData: PasswordResetWithTokenFormFields,\n onSuccess?: (model: string) => Promise<void>\n): Promise<Errorable<string>> {\n async function mutateFn(data: PasswordResetWithTokenFormFields): Promise<string> {\n const userID = await validatePasswordResetToken(data.token, data.password);\n const session = await handleUserSession(userID);\n\n if (!session) {\n throw new Error('COULD_NOT_CREATE_SESSION');\n }\n\n return session;\n }\n\n const response = await submitForm({\n fn: mutateFn,\n formData,\n onSuccess,\n request: PasswordResetWithTokenRequest,\n });\n\n return response;\n}\n","import type { NextRequest } from 'next/server';\nimport { eq } from 'drizzle-orm';\n\nimport { db } from '../database/DatabaseService';\nimport { authClientTable } from '../database/schema';\nimport type { AuthClient } from '../database/schema';\n\nimport { hashPassword, verifyPassword } from './PasswordService';\nimport { generateID } from './SessionService';\n\nconst ID_LENGTH = 16;\nconst SECRET_LENGTH = 64;\n\nexport async function getClientByID(id: string): Promise<AuthClient | null> {\n const [client] = await db\n .select()\n .from(authClientTable)\n .where(eq(authClientTable.id, id))\n .limit(1);\n\n return client;\n}\n\ninterface RegisterClientArgs {\n alias: string;\n id?: string;\n secret?: string;\n}\n\nexport async function registerClient({\n alias,\n id,\n secret,\n}: RegisterClientArgs): Promise<AuthClient | null> {\n const [client] = await db\n .insert(authClientTable)\n .values({\n alias,\n id: id || generateID('', ID_LENGTH),\n secret: await hashPassword(secret || generateID('', SECRET_LENGTH)),\n })\n .returning();\n\n return client;\n}\n\nexport async function handleClientAuth(request: NextRequest): Promise<AuthClient | null> {\n const { headers } = request;\n const header = headers.get('authorization');\n\n if (!header) {\n return null;\n }\n\n const auth = Buffer.from(header.replace('Basic ', ''), 'base64')\n .toString('utf-8')\n .replace(/:$/u, '');\n\n const [id, ...secret] = auth.split('-');\n\n const [client] = await db\n .select()\n .from(authClientTable)\n .where(eq(authClientTable.id, id))\n .limit(1);\n\n if (!client) {\n return null;\n }\n\n const isVerified = await verifyPassword(secret.join(''), client.secret);\n return isVerified ? client : null;\n}\n"]}
1
+ {"version":3,"sources":["../../src/database/DatabaseService.ts","../../src/database/schema.ts","../../src/forms/ValidationError.ts","../../src/forms/lang.ts","../../src/forms/ValidationService.ts","../../src/forms/FormService.ts","../../src/auth/MFARequest.ts","../../src/cache/CacheService.ts","../../src/url/URLService.ts","../../src/auth/SessionService.ts","../../src/auth/MFAService.ts","../../src/auth/PasswordService.ts","../../src/auth/LoginRequest.ts","../../src/auth/PasswordRequest.ts","../../src/auth/PasswordResetWithTokenRequest.ts","../../src/auth/AuthService.ts","../../src/auth/ClientService.ts"],"names":["createSingleton","drizzle","postgres","db","DEFAULT_ROLE","mfaType","pgEnum","scope","authSchema","pgSchema","authUserTable","text","integer","timestamp","table","uniqueIndex","authSessionTable","authResetTable","authMFATable","authClientTable","ValidationError","messages","ValidationError_default","lang_default","getErrorMessages","acc","key","value","transformErrors","error","cur","validateSchema","formData","validation","err","Joi","createSchema","schema","serializeError","hasFn","args","submitForm","data","validated","validationError","model","MFARequest","MFARequest_default","client","isLocalhost","url","getClient","createClient","getFromCache","setToCache","getOrigin","envOrigin","origin","headers","proto","host","DEFAULT_REDIRECT","ID_LENGTH","DEFAULT_SCOPES","timespanMap","getSessionExpiry","TimeSpan","unit","adapter","DrizzlePostgreSQLAdapter","lucia","Lucia","attributes","generateID","prefix","length","generateId","invalidateSession","id","cookie","cookies","invalidateUserSessions","createUserSession","session","sessionCookie","getSessionID","checkSessionExists","checkUserRole","userRole","targetRoles","targetRolesArray","getAllowedRoles","getSessionUser","roles","sessionID","user","pick","checkRouteAllowed","pathname","route","match","getScopes","scopes","getScopeByID","setScopes","customScopes","validateSessionFromID","handleSession","request","NextResponse","checkMFAEnabled","generateMFA","name","email","eq","secret","authenticator","otpauth","and","isNull","resolve","reject","qrcode","checkUserHasMFA","mfa","isNotNull","markAsVerified","userID","validateUserToken","token","deleteMFA","promises","handleMFA","handleMFAForm","PW_SALT_ROUNDS","PASSWORD_RULES","checkPasswordMin","password","checkPasswordUpper","checkPasswordLower","checkPasswordNumber","checkPasswordSymbol","PASSWORD_FUNCTIONS","hashPassword","bcrypt","verifyPassword","encrypted","getPasswordComplexity","rules","validity","rule","checkPasswordComplexity","LoginRequest","LoginRequest_default","PasswordRequest","PasswordRequest_default","passwordComplexity","passwordIsComplex","helpers","PasswordResetWithTokenRequest","PasswordResetWithTokenRequest_default","RESET_TOKEN_LENGTH","RESET_TOKEN_EXPIRY","handleLogout","role","getMaximumRole","handleUserSession","getUserByEmail","conditions","lte","loginUser","handleLoginForm","onSuccess","registerUser","hash","updateDeletedAt","deletedAt","deleteUser","undeleteUser","createPasswordResetToken","handlePasswordForm","mailFn","mutateFn","validatePasswordResetToken","result","inArray","handlePasswordResetWithTokenForm","SECRET_LENGTH","getClientByID","registerClient","alias","handleClientAuth","header","auth"],"mappings":"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","file":"index.cjs","sourcesContent":["import { drizzle } from 'drizzle-orm/postgres-js';\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\nimport postgres from 'postgres';\n\ndeclare global {\n var szdb: ReturnType<typeof createSingleton> | undefined; // eslint-disable-line no-var, vars-on-top\n}\n\nfunction createSingleton(): PostgresJsDatabase {\n if (!process.env.DATABASE_URL) {\n throw new Error('DATABASE_URL is not defined');\n }\n return drizzle(postgres(process.env.DATABASE_URL, { prepare: false }));\n}\n\nexport const db = globalThis.szdb ?? createSingleton();\n\nif (!process.env.VERCEL_ENV) {\n globalThis.szdb = db;\n}\n","/* istanbul ignore file */\n\nimport { integer, pgEnum, pgSchema, text, timestamp, uniqueIndex } from 'drizzle-orm/pg-core';\n\nconst DEFAULT_ROLE = 10;\n\nexport const mfaType = pgEnum('mfaType', ['TOTP', 'HARDWARE']);\nexport const scope = pgEnum('scope', ['ANON', 'MFA', 'AUTHED']);\n\nexport type Scope = (typeof scope.enumValues)[number];\n\nexport const authSchema = pgSchema('auth');\n\nexport const authUserTable = authSchema.table(\n 'user_credentials',\n {\n id: text('id').primaryKey(),\n email: text('email').notNull(),\n password: text('password'),\n role: integer('role').notNull().default(DEFAULT_ROLE),\n deletedAt: timestamp('deletedAt'),\n },\n (table) => ({\n unique: uniqueIndex().on(table.email, table.role),\n })\n);\n\nexport type AuthUser = typeof authUserTable.$inferSelect;\n\nexport const authSessionTable = authSchema.table('sessions', {\n id: text('id').primaryKey(),\n userId: text('userId')\n .notNull()\n .references(() => authUserTable.id, { onDelete: 'cascade' }),\n scope: scope('scope').notNull().default('ANON'),\n expiresAt: timestamp('expiresAt').notNull(),\n});\n\nexport type AuthSession = typeof authSessionTable.$inferSelect;\n\nexport const authResetTable = authSchema.table('resets', {\n id: text('id').primaryKey(),\n userId: text('userId')\n .notNull()\n .references(() => authUserTable.id, { onDelete: 'cascade' }),\n expiresAt: timestamp('expiresAt').notNull(),\n});\n\nexport type AuthReset = typeof authResetTable.$inferSelect;\n\nexport const authMFATable = authSchema.table('mfas', {\n id: text('id').primaryKey(),\n name: text('name').notNull(),\n userId: text('userId')\n .notNull()\n .references(() => authUserTable.id, { onDelete: 'cascade' }),\n type: mfaType('type').notNull().default('TOTP'),\n secret: text('secret').notNull(),\n verifiedAt: timestamp('verifiedAt'),\n});\n\nexport type AuthMFA = typeof authMFATable.$inferSelect;\n\nexport const authClientTable = authSchema.table('client_credentials', {\n id: text('id').primaryKey(),\n alias: text('alias').notNull().unique(),\n secret: text('secret').notNull().unique(),\n});\n\nexport type AuthClient = typeof authClientTable.$inferSelect;\n","class ValidationError extends Error {\n public messages: Record<string, string>;\n\n public constructor(messages: Record<string, string>) {\n super(JSON.stringify(messages));\n\n this.messages = messages;\n this.name = 'ValidationError';\n }\n}\n\nexport default ValidationError;\n","const messages: Record<string, string> = {\n 'alternatives.all': '',\n 'alternatives.any': '',\n 'alternatives.match': '',\n 'alternatives.one': '',\n 'alternatives.types': '',\n 'any.custom': '',\n 'any.default': '',\n 'any.failover': '',\n 'any.invalid': '',\n 'any.only': '',\n 'any.ref': '',\n 'any.required': '{{#label}} is required',\n 'any.unknown': '',\n 'array.base': '',\n 'array.excludes': '',\n 'array.includesRequiredBoth': '',\n 'array.includesRequiredKnowns': '',\n 'array.includesRequiredUnknowns': '',\n 'array.includes': '',\n 'array.length': '',\n 'array.max': '',\n 'array.min': '',\n 'array.orderedLength': '',\n 'array.sort': '',\n 'array.sort.mismatching': '',\n 'array.sort.unsupported': '',\n 'array.sparse': '',\n 'array.unique': '',\n 'array.hasKnown': '',\n 'array.hasUnknown': '',\n 'binary.base': '',\n 'binary.length': '',\n 'binary.max': '',\n 'binary.min': '',\n 'boolean.base': '',\n 'date.base': '',\n 'date.format': '',\n 'date.greater': '',\n 'date.less': '',\n 'date.max': '',\n 'date.min': '',\n 'date.strict': '',\n 'function.arity': '',\n 'function.class': '',\n 'function.maxArity': '',\n 'function.minArity': '',\n 'number.base': '{{#label}} should be a number',\n 'number.greater': '',\n 'number.infinity': '',\n 'number.integer': '',\n 'number.less': '',\n 'number.max': '',\n 'number.min': '{{#label}} should be greater than or equal to {{#limit}}',\n 'number.multiple': '',\n 'number.negative': '',\n 'number.port': '',\n 'number.positive': '',\n 'number.precision': '',\n 'number.unsafe': '',\n 'object.unknown': '',\n 'object.and': '',\n 'object.assert': '',\n 'object.base': '',\n 'object.length': '',\n 'object.max': '',\n 'object.min': '',\n 'object.missing': '',\n 'object.nand': '',\n 'object.pattern.match': '',\n 'object.refType': '',\n 'object.regex': '',\n 'object.rename.multiple': '',\n 'object.rename.override': '',\n 'object.schema': '',\n 'object.instance': '',\n 'object.with': '',\n 'object.without': '',\n 'object.xor': '',\n 'object.oxor': '',\n 'string.alphanum': '',\n 'string.base64': '',\n 'string.base': '',\n 'string.creditCard': '',\n 'string.dataUri': '',\n 'string.domain': '',\n 'string.email': '',\n 'string.empty': '{{#label}} is required',\n 'string.guid': '',\n 'string.hexAlign': '',\n 'string.hex': '',\n 'string.hostname': '',\n 'string.ipVersion': '',\n 'string.ip': '',\n 'string.isoDate': '',\n 'string.isoDuration': '',\n 'string.length': '',\n 'string.lowercase': '',\n 'string.max': '',\n 'string.min': '',\n 'string.normalize': '',\n 'string.pattern.base': '{{#label}} is not in the correct format',\n 'string.pattern.name': '',\n 'string.pattern.invert.base': '',\n 'string.pattern.invert.name': '',\n 'string.token': '',\n 'string.trim': '',\n 'string.uppercase': '',\n 'string.uri': '',\n 'string.uriCustomScheme': '',\n 'string.uriRelativeOnly': '',\n 'symbol.base': '',\n 'symbol.map': '',\n};\n\nexport default messages;\n","import type { Errorable } from '@sqrzro/interfaces';\nimport Joi from 'joi';\n\nimport lang from './lang';\nimport ValidationError from './ValidationError';\n\nexport function validate(): typeof Joi {\n return Joi;\n}\n\nexport type ValidationCustomHelpers<V = any> = Joi.CustomHelpers<V>; // eslint-disable-line @typescript-eslint/no-explicit-any\nexport type ValidationExternalHelpers<V = any> = Joi.ExternalHelpers<V>; // eslint-disable-line @typescript-eslint/no-explicit-any\nexport type ValidationErrorReport = Joi.ErrorReport;\n\nexport function getDefaultErrorMessages(): Record<string, string> {\n return lang;\n}\n\nfunction getErrorMessages(): Record<string, string> {\n return Object.entries(lang).reduce((acc, [key, value]) => {\n if (!value) {\n return acc;\n }\n return {\n ...acc,\n [key]: value,\n };\n }, {});\n}\n\nfunction transformErrors(error: Joi.ValidationError): ValidationError {\n const messages = error.details.reduce(\n (acc, cur) => ({\n ...acc,\n [cur.path.join('.')]: cur.message.replace(/\"/gu, ''),\n }),\n {}\n );\n return new ValidationError(messages);\n}\n\n/**\n * This function takes FormData and a schema. It then attempts to transform the FormData into an\n * object that matches `T`. This is because the FormData object is not typed and we want to be able\n * to validate it properly typed.\n *\n * Once transformed, the object is validated against the schema. This will result in either a\n * properly typed `T` object or an array of validation errors.\n * @param formData\n * @param validation\n * @returns\n */\nexport async function validateSchema<T>(\n formData: Partial<T>,\n validation: Joi.ObjectSchema<T>,\n messages?: Record<string, string>\n): Promise<Errorable<T>> {\n try {\n const validated = await validation.validateAsync(formData, {\n abortEarly: false,\n messages: messages || getErrorMessages(),\n stripUnknown: true,\n });\n\n return [validated, null];\n } catch (err) {\n if (err instanceof Joi.ValidationError) {\n return [null, transformErrors(err)];\n }\n\n if (err instanceof Error) {\n return [null, err];\n }\n\n return [null, new Error('Unknown validation error occured')];\n }\n}\n\nexport function createSchema<T>(schema: Joi.SchemaMap<T, true>): Joi.ObjectSchema<T> {\n return Joi.object<T>(schema);\n}\n\nexport function extendSchema<T, U extends T>(\n schema: Joi.ObjectSchema<T>,\n appends: Joi.PartialSchemaMap<U>\n): Joi.ObjectSchema<U> {\n return schema.append<U>(appends);\n}\n","/* eslint-disable max-statements */\n\nimport type { SerializedError, SerializedErrorable } from '@sqrzro/interfaces';\nimport type Joi from 'joi';\nimport { NextResponse } from 'next/server';\n\nimport ValidationError from './ValidationError';\nimport { validateSchema } from './ValidationService';\n\nfunction serializeError(err: Error): SerializedError {\n return {\n cause: err.cause,\n message: err.message,\n name: err.name,\n stack: err.stack,\n };\n}\n\ninterface SubmitFormArgs<F extends object> {\n formData: F;\n onSuccess?: (model: F) => Promise<void> | void;\n onValidationError?: (error: ValidationError) => void;\n request?: Joi.ObjectSchema<F>;\n}\n\ninterface SubmitFormArgsWithFn<F extends object, M> extends Omit<SubmitFormArgs<F>, 'onSuccess'> {\n fn: (data: F) => Promise<M | null>;\n onSuccess?: (model: M) => Promise<void> | void;\n}\n\nfunction hasFn<F extends object, M>(\n args: SubmitFormArgs<F> | SubmitFormArgsWithFn<F, M>\n): args is SubmitFormArgsWithFn<F, M> {\n return Boolean(Object.prototype.hasOwnProperty.call(args, 'fn'));\n}\n\nexport async function submitForm<F extends object>(\n args: SubmitFormArgs<F>\n): Promise<SerializedErrorable<F>>;\nexport async function submitForm<F extends object, M>(\n args: SubmitFormArgsWithFn<F, M>\n): Promise<SerializedErrorable<M>>;\n\nexport async function submitForm<F extends object, M>(\n args: SubmitFormArgs<F> | SubmitFormArgsWithFn<F, M>\n): Promise<[F, null] | [M, null] | [null, SerializedError]> {\n let data = { ...args.formData };\n\n if (args.request) {\n const [validated, validationError] = await validateSchema<F>(args.formData, args.request);\n\n if (validationError !== null) {\n if (validationError instanceof ValidationError) {\n args.onValidationError?.(validationError);\n }\n\n return [null, serializeError(validationError)];\n }\n\n data = validated;\n }\n\n if (!hasFn(args)) {\n await args.onSuccess?.(data);\n return [data, null];\n }\n\n let model: Awaited<M> | null = null;\n\n try {\n model = await args.fn(data);\n } catch (err: unknown) {\n if (err instanceof ValidationError) {\n args.onValidationError?.(err);\n return [null, serializeError(err)];\n }\n if (err instanceof Error) {\n throw err;\n }\n throw new Error('The function supplied to submitForm encountered an unknown error');\n }\n\n if (!model) {\n throw new Error('NO_MODEL');\n }\n\n await args.onSuccess?.(model);\n return [model, null];\n}\n\nexport async function submitAPIRequest<F extends object, M>(\n args: SubmitFormArgsWithFn<F, M>\n): Promise<[M, null] | [null, NextResponse]> {\n const [response, error] = await submitForm<F, M>(args);\n\n if (error !== null) {\n if (error.name === 'ValidationError') {\n try {\n const errors = JSON.parse(error.message) as Record<string, string>;\n return [null, NextResponse.json(errors, { status: 422 })];\n } catch (err) {\n return [\n null,\n NextResponse.json({ message: 'An unknown error occured' }, { status: 500 }),\n ];\n }\n }\n return [null, NextResponse.json({ message: error.message }, { status: 500 })];\n }\n\n return [response, null];\n}\n","/* eslint-disable @typescript-eslint/no-magic-numbers */\n\nimport Joi from 'joi';\n\nimport { createSchema } from '../forms/ValidationService';\nimport type { MFAFormFields } from './interfaces';\n\nconst MFARequest = createSchema<MFAFormFields>({\n token: Joi.string()\n .pattern(/^[0-9]{6}$/u)\n .required(),\n});\n\nexport default MFARequest;\n","import { createClient } from 'redis';\n\nlet client: ReturnType<typeof createClient> | null = null;\n\nfunction isLocalhost(url: string): boolean {\n return url.includes('localhost') || url.includes('127.0.0.1');\n}\n\nasync function getClient(): Promise<ReturnType<typeof createClient>> {\n if (!process.env.REDIS_URL) {\n throw new Error('REDIS_URL is not defined. Access to the cache is not possible.');\n }\n\n if (client) {\n return client;\n }\n\n client = createClient({\n socket: {\n tls: !isLocalhost(process.env.REDIS_URL),\n },\n url: process.env.REDIS_URL,\n });\n\n await client.connect();\n return client;\n}\n\nexport async function getFromCache(key: string): Promise<string | null> {\n return (await getClient()).get(key);\n}\n\nexport async function setToCache(key: string, value: string): Promise<void> {\n await (await getClient()).set(key, value);\n}\n","import { headers } from 'next/headers';\n\n/**\n * Uses a number of methods to determine the current origin.\n *\n * First, it checks if an `x-origin` header. This will have been set by the `handleMiddleware`\n * function, further up the chain. For more information on how it is being set, see the\n * `middleware` documentation.\n *\n * There are some situations where middleware is not being applied, such as API routes (because the\n * redirection is not necessary, and API routes handle their own authentication). In these cases,\n * this function tries to piece together the origin from the `x-forwarded-proto` and\n * `x-forwarded-host` headers.\n *\n * Finally, if the origin cannot be determined, an error is thrown.\n *\n * @returns The origin of the current request.\n */\nexport async function getOrigin(): Promise<string> {\n const envOrigin = process.env.SZ_ORIGIN;\n\n if (envOrigin) {\n return envOrigin;\n }\n\n const origin = (await headers()).get('x-origin');\n\n if (origin) {\n return origin;\n }\n\n const proto = (await headers()).get('x-forwarded-proto');\n const host = (await headers()).get('x-forwarded-host');\n\n if (proto && host) {\n return `${proto}://${host}`;\n }\n\n throw new Error('No origin could be determined');\n}\n\nexport async function getPathname(): Promise<string> {\n const pathname = (await headers()).get('x-pathname');\n\n if (pathname) {\n return pathname;\n }\n\n throw new Error(\n 'No pathname could be determined. Please make sure middleware is being applied to the current request.'\n );\n}\n\n/**\n * Builds a URL from the current origin and a given pathname. For more information on how the origin\n * is determined, see the `getOrigin` function. This function then just concatenates the origin and\n * the pathname, and performs some cleanup to ensure the URL is valid.\n *\n * @param pathname\n * @returns The URL, with the origin and pathname combined.\n */\nexport async function makeURL(pathname?: string): Promise<string> {\n const origin = await getOrigin();\n\n if (!pathname) {\n return origin;\n }\n\n const isSecure = origin.startsWith('https://');\n\n const protocol = isSecure ? 'https://' : 'http://';\n const originWithoutProtocol = origin.replace(/^https?:\\/\\//u, '');\n\n const cleanURL = `${originWithoutProtocol}/${pathname}`.replace(/\\/+/gu, '/');\n return `${protocol}${cleanURL}`;\n}\n\n/**\n * @deprecated Use `makeURL` instead.\n */\nexport async function getURL(pathname?: string): Promise<string> {\n return makeURL(pathname);\n}\n","import { DrizzlePostgreSQLAdapter } from '@lucia-auth/adapter-drizzle';\nimport { pick } from '@sqrzro/utility';\nimport { Lucia, TimeSpan, generateId } from 'lucia';\nimport { cookies } from 'next/headers';\nimport { NextResponse } from 'next/server';\nimport type { NextRequest } from 'next/server';\nimport { match } from 'path-to-regexp';\n\nimport { getAllowedRoles } from './AuthService';\n\nimport { db } from '../database/DatabaseService';\nimport { authSessionTable, authUserTable } from '../database/schema';\nimport type { Scope } from '../database/schema';\n\nimport { getFromCache, setToCache } from '../cache/CacheService';\nimport { getOrigin } from '../url/URLService';\n\nconst DEFAULT_REDIRECT = '/auth/login';\nconst ID_LENGTH = 16;\n\ntype TimeSpanUnit = 'd' | 'h' | 'm' | 'ms' | 's' | 'w';\n\ninterface ScopeData {\n allowedRoute?: string;\n redirectOnAuth?: string;\n redirectOnUnauth?: string;\n}\n\nexport type ScopeObject = Record<Scope, ScopeData>;\n\ninterface DatabaseSessionAttributes {\n scope: Scope;\n}\n\ninterface DatabaseUserAttributes {\n email: string;\n role: number;\n deletedAt?: Date | null;\n}\n\ndeclare module 'lucia' {\n interface Register {\n Lucia: typeof lucia;\n DatabaseSessionAttributes: DatabaseSessionAttributes;\n DatabaseUserAttributes: DatabaseUserAttributes;\n }\n}\n\nconst DEFAULT_SCOPES: ScopeObject = {\n ANON: {\n allowedRoute: '/auth/(login|password)',\n redirectOnUnauth: DEFAULT_REDIRECT,\n },\n MFA: {\n allowedRoute: '/auth/mfa',\n redirectOnUnauth: '/auth/mfa',\n },\n AUTHED: {\n allowedRoute: '*',\n redirectOnAuth: '/',\n },\n};\n\n/* eslint-disable id-length */\nconst timespanMap: Record<string, TimeSpanUnit> = {\n D: 'd',\n H: 'h',\n M: 'm',\n MS: 'ms',\n S: 's',\n W: 'w',\n};\n/* eslint-enable id-length */\n\nfunction getSessionExpiry(): TimeSpan {\n if (!process.env.AUTH_SESSION_EXPIRY) {\n return new TimeSpan(2, 'w');\n }\n\n const [value, unit] = process.env.AUTH_SESSION_EXPIRY.split(/_/u);\n return new TimeSpan(Number(value), timespanMap[unit]);\n}\n\nconst adapter = new DrizzlePostgreSQLAdapter(db, authSessionTable, authUserTable);\n\nexport const lucia = new Lucia(adapter, {\n getSessionAttributes: (attributes: DatabaseSessionAttributes): DatabaseSessionAttributes => ({\n scope: attributes.scope,\n }),\n getUserAttributes: (attributes: DatabaseUserAttributes): DatabaseUserAttributes => ({\n email: attributes.email,\n role: attributes.role,\n deletedAt: attributes.deletedAt,\n }),\n sessionCookie: {\n attributes: {\n secure: process.env.APP_ENV === 'production',\n },\n name: process.env.AUTH_COOKIE_NAME || 'auth_session',\n },\n sessionExpiresIn: getSessionExpiry(),\n});\n\nexport function generateID<T extends string = string>(prefix = '', length = ID_LENGTH): T {\n return `${prefix ? `${prefix}_` : ''}${generateId(length)}` as T;\n}\n\nexport async function invalidateSession(id: string): Promise<void> {\n const cookie = lucia.createBlankSessionCookie();\n (await cookies()).set(cookie.name, cookie.value, cookie.attributes);\n\n return lucia.invalidateSession(id);\n}\n\nexport async function invalidateUserSessions(id: string): Promise<void> {\n return lucia.invalidateUserSessions(id);\n}\n\nexport async function createUserSession(id: string, scope: Scope = 'ANON'): Promise<boolean> {\n const session = await lucia.createSession(id, { scope });\n const sessionCookie = lucia.createSessionCookie(session.id);\n (await cookies()).set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);\n\n return true;\n}\n\nexport async function getSessionID(): Promise<string | null> {\n return (await cookies()).get(lucia.sessionCookieName)?.value ?? null;\n}\n\nexport async function checkSessionExists(): Promise<boolean> {\n return Boolean(await getSessionID());\n}\n\nfunction checkUserRole(userRole: number, targetRoles?: number[] | number): boolean {\n const targetRolesArray = Array.isArray(targetRoles) ? targetRoles : [targetRoles];\n\n if (targetRolesArray[0]) {\n return targetRolesArray.includes(userRole);\n }\n\n return getAllowedRoles().includes(userRole);\n}\n\nexport async function getSessionUser(roles?: number[] | number): Promise<{\n id: string;\n email: string;\n role: number;\n} | null> {\n const sessionID = await getSessionID();\n\n if (!sessionID) {\n return null;\n }\n\n const { user } = await lucia.validateSession(sessionID);\n\n if (!user || user.deletedAt || !checkUserRole(user.role, roles)) {\n return null;\n }\n\n return pick(user, ['id', 'email', 'role']);\n}\n\nexport function checkRouteAllowed(pathname: string, route?: string): boolean {\n if (!route) {\n return false;\n }\n\n if (route === '*') {\n return true;\n }\n\n return match(route)(pathname) !== false;\n}\n\nexport async function getScopes(): Promise<ScopeObject> {\n const scopes = await getFromCache(`${await getOrigin()}:scopes`);\n return scopes ? (JSON.parse(scopes) as ScopeObject) : DEFAULT_SCOPES;\n}\n\nexport async function getScopeByID(id: Scope): Promise<ScopeData> {\n const scopes = await getScopes();\n return scopes[id];\n}\n\nexport async function setScopes(customScopes?: Partial<ScopeObject>): Promise<void> {\n const scopes = {\n ANON: {\n ...DEFAULT_SCOPES.ANON,\n ...customScopes?.ANON,\n },\n MFA: {\n ...DEFAULT_SCOPES.MFA,\n ...customScopes?.MFA,\n },\n AUTHED: {\n ...DEFAULT_SCOPES.AUTHED,\n ...customScopes?.AUTHED,\n },\n };\n\n return setToCache(`${await getOrigin()}:scopes`, JSON.stringify(scopes));\n}\n\nasync function validateSessionFromID(\n sessionID: string,\n pathname: string\n): Promise<{ redirect: string | null; email: string | null }> {\n const scopes = await getScopes();\n const { session, user } = await lucia.validateSession(sessionID);\n\n const scope =\n scopes[session && getAllowedRoles().includes(user?.role) ? session.scope : 'ANON'];\n\n return {\n email: user?.email || null,\n redirect: checkRouteAllowed(pathname, scope.allowedRoute)\n ? null\n : scope.redirectOnUnauth || DEFAULT_REDIRECT,\n };\n}\n\nexport async function handleSession(\n request: NextRequest,\n customScopes?: Partial<ScopeObject>\n): Promise<NextResponse> {\n const sessionID = request.nextUrl.searchParams.get('id') || '';\n const pathname = request.nextUrl.searchParams.get('pathname') || '/';\n\n await setScopes(customScopes);\n\n return NextResponse.json(await validateSessionFromID(sessionID, pathname));\n}\n","import type { Errorable } from '@sqrzro/interfaces';\nimport { and, eq, isNotNull, isNull } from 'drizzle-orm';\nimport { authenticator } from 'otplib';\nimport qrcode from 'qrcode';\n\nimport { db } from '../database/DatabaseService';\nimport { authMFATable, authUserTable } from '../database/schema';\n\nimport { submitForm } from '../forms/FormService';\nimport ValidationError from '../forms/ValidationError';\n\nimport MFARequest from './MFARequest';\nimport {\n createUserSession,\n generateID,\n getSessionUser,\n invalidateUserSessions,\n} from './SessionService';\nimport type { MFAFormFields, UserObject } from './interfaces';\n\nexport function checkMFAEnabled(): boolean {\n return process.env.AUTH_MFA_ENABLED !== 'false';\n}\n\nexport async function generateMFA(name: string, email?: string): Promise<string | null> {\n if (!checkMFAEnabled()) {\n throw new Error('MFA is not enabled. Cannot generate MFA secret.');\n }\n\n if (!email) {\n return null;\n }\n\n const [user] = await db\n .select()\n .from(authUserTable)\n .where(eq(authUserTable.email, email))\n .limit(1);\n\n if (!user) {\n return null;\n }\n\n const secret = authenticator.generateSecret();\n const otpauth = authenticator.keyuri(email, name, secret);\n\n // Delete all the unverified MFA entries for this user\n\n await db\n .delete(authMFATable)\n .where(and(eq(authMFATable.userId, user.id), isNull(authMFATable.verifiedAt)));\n\n // Add the new MFA entry\n\n await db.insert(authMFATable).values({\n id: generateID(),\n name: 'Default',\n secret,\n userId: user.id,\n });\n\n return new Promise((resolve, reject) => {\n qrcode.toDataURL(\n otpauth,\n { rendererOpts: { quality: 1 }, margin: 0, scale: 2 },\n (err, data) => {\n if (err) {\n reject(err);\n }\n resolve(data);\n }\n );\n });\n}\n\nexport async function checkUserHasMFA(user: UserObject): Promise<boolean> {\n if (!checkMFAEnabled()) {\n return false;\n }\n\n const [mfa] = await db\n .select()\n .from(authMFATable)\n .where(and(eq(authMFATable.userId, user.id), isNotNull(authMFATable.verifiedAt)))\n .limit(1);\n\n return Boolean(mfa);\n}\n\nasync function markAsVerified(userID: string): Promise<void> {\n if (!checkMFAEnabled()) {\n return;\n }\n\n await db\n .update(authMFATable)\n .set({ verifiedAt: new Date() })\n .where(eq(authMFATable.userId, userID));\n}\n\nasync function validateUserToken(userID: string, token: string): Promise<boolean> {\n if (!checkMFAEnabled()) {\n return false;\n }\n\n const [mfa] = await db\n .select()\n .from(authMFATable)\n .where(eq(authMFATable.userId, userID))\n .limit(1);\n\n if (!mfa) {\n return false;\n }\n\n return authenticator.check(token, mfa.secret);\n}\n\nexport async function deleteMFA(userID: string): Promise<boolean> {\n const promises = [\n db.delete(authMFATable).where(eq(authMFATable.userId, userID)),\n invalidateUserSessions(userID),\n ];\n\n await Promise.all(promises);\n return true;\n}\n\nexport async function handleMFA(data: MFAFormFields): Promise<boolean> {\n if (!checkMFAEnabled()) {\n throw new ValidationError({ token: 'MFA is not enabled' });\n }\n\n const user = await getSessionUser();\n\n if (!user) {\n throw new ValidationError({ token: 'User not found' });\n }\n\n const isValid = await validateUserToken(user.id, data.token);\n\n if (!isValid) {\n throw new ValidationError({ token: 'Invalid token' });\n }\n\n await markAsVerified(user.id);\n return createUserSession(user.id, 'AUTHED');\n}\n\nexport async function handleMFAForm(formData: MFAFormFields): Promise<Errorable<boolean>> {\n if (!checkMFAEnabled()) {\n return [null, new Error('MFA is not enabled')];\n }\n\n const response = await submitForm<MFAFormFields, boolean>({\n fn: handleMFA,\n formData,\n request: MFARequest,\n });\n\n return response;\n}\n","import bcrypt from 'bcryptjs';\n\nconst PW_SALT_ROUNDS = 12;\n\ntype PasswordRule = 'lower' | 'min' | 'number' | 'symbol' | 'upper';\n\nexport type PasswordRuleObject = Partial<Record<PasswordRule, number>>;\ntype PasswordValidityObject = Record<PasswordRule, boolean>;\n\nconst PASSWORD_RULES: PasswordRuleObject = {\n min: 8,\n upper: 1,\n lower: 1,\n number: 1,\n symbol: 1,\n};\n\nfunction checkPasswordMin(password: string, value: number): boolean {\n return password.length >= value;\n}\n\nfunction checkPasswordUpper(password: string, value: number): boolean {\n return password.replace(/[^A-Z]/gu, '').length >= value;\n}\n\nfunction checkPasswordLower(password: string, value: number): boolean {\n return password.replace(/[^a-z]/gu, '').length >= value;\n}\n\nfunction checkPasswordNumber(password: string, value: number): boolean {\n return password.replace(/[^0-9]/gu, '').length >= value;\n}\n\nfunction checkPasswordSymbol(password: string, value: number): boolean {\n return password.replace(/[^$]/gu, '').length >= value;\n}\n\nconst PASSWORD_FUNCTIONS: Record<PasswordRule, (password: string, value: number) => boolean> = {\n min: checkPasswordMin,\n upper: checkPasswordUpper,\n lower: checkPasswordLower,\n number: checkPasswordNumber,\n symbol: checkPasswordSymbol,\n};\n\nexport async function hashPassword(password: string): Promise<string> {\n const hash = await bcrypt.hash(password, PW_SALT_ROUNDS);\n return hash;\n}\n\nexport async function verifyPassword(data?: string, encrypted?: string): Promise<boolean> {\n if (!data || !encrypted) {\n return false;\n }\n\n const verified = await bcrypt.compare(data, encrypted);\n return verified;\n}\n\nexport async function getPasswordComplexity(\n password: string,\n rules: Partial<PasswordRuleObject> = PASSWORD_RULES\n): Promise<Partial<PasswordValidityObject>> {\n const entries = Object.entries(rules) as [PasswordRule, number][];\n\n const validity = entries.reduce<Partial<PasswordValidityObject>>((acc, [rule, value]) => {\n acc[rule] = PASSWORD_FUNCTIONS[rule](password, value);\n return acc;\n }, {});\n\n return Promise.resolve(validity);\n}\n\nexport async function checkPasswordComplexity(\n password: string,\n rules: Partial<PasswordRuleObject> = PASSWORD_RULES\n): Promise<Partial<boolean>> {\n const validity = await getPasswordComplexity(password, rules);\n return Promise.resolve(Object.values(validity).every(Boolean));\n}\n","/* eslint-disable @typescript-eslint/no-magic-numbers */\n\nimport Joi from 'joi';\n\nimport { createSchema } from '../forms/ValidationService';\nimport type { LoginFormFields } from './interfaces';\n\nconst LoginRequest = createSchema<LoginFormFields>({\n email: Joi.string().email({ minDomainSegments: 2, tlds: false }).required(),\n password: Joi.string().min(8).required(),\n});\n\nexport default LoginRequest;\n","/* eslint-disable @typescript-eslint/no-magic-numbers */\n\nimport Joi from 'joi';\n\nimport { createSchema } from '../forms/ValidationService';\nimport type { PasswordFormFields } from './interfaces';\n\nconst PasswordRequest = createSchema<PasswordFormFields>({\n email: Joi.string().max(60).email({ minDomainSegments: 2, tlds: false }).required().messages({\n 'any.required': 'Please provide your email address, so we can send you a reset link',\n 'string.empty': 'Please provide your email address, so we can send you a reset link',\n 'string.email': 'Please make sure your email address is valid',\n 'string.max': 'Please make sure your email address is valid',\n }),\n});\n\nexport default PasswordRequest;\n","import Joi from 'joi';\n\nimport { checkPasswordComplexity } from './PasswordService';\nimport type { PasswordRuleObject } from './PasswordService';\nimport type { ValidationCustomHelpers } from '../forms/ValidationService';\n\nimport { createSchema } from '../forms/ValidationService';\nimport type { PasswordResetWithTokenFormFields } from './interfaces';\n\nconst passwordComplexity: PasswordRuleObject = {\n lower: 1,\n min: 8,\n number: 1,\n upper: 1,\n};\n\nasync function passwordIsComplex(\n value: string,\n helpers: ValidationCustomHelpers\n): Promise<Error | string> {\n if (!(await checkPasswordComplexity(value, passwordComplexity))) {\n return helpers.message({\n external:\n 'Please make sure your password is complex enough, to keep your account secure',\n });\n }\n return value;\n}\n\nconst PasswordResetWithTokenRequest = createSchema<PasswordResetWithTokenFormFields>({\n password: Joi.string().external(passwordIsComplex).required().messages({\n 'any.required': 'Please provide your new password',\n 'string.empty': 'Please provide your new password',\n }),\n token: Joi.string().pattern(/[a-z0-9]{40}/u),\n});\n\nexport default PasswordResetWithTokenRequest;\n","import type { Errorable } from '@sqrzro/interfaces';\nimport { and, eq, inArray, isNull, lte } from 'drizzle-orm';\n\nimport { db } from '../database/DatabaseService';\nimport { authResetTable, authUserTable } from '../database/schema';\n\nimport { submitForm } from '../forms/FormService';\nimport ValidationError from '../forms/ValidationError';\n\nimport { checkMFAEnabled } from './MFAService';\nimport { hashPassword, verifyPassword } from './PasswordService';\nimport {\n createUserSession,\n generateID,\n getScopeByID,\n getSessionID,\n invalidateSession,\n invalidateUserSessions,\n} from './SessionService';\n\nimport LoginRequest from './LoginRequest';\nimport PasswordRequest from './PasswordRequest';\nimport PasswordResetWithTokenRequest from './PasswordResetWithTokenRequest';\n\nimport type {\n LoginFormFields,\n PasswordFormFields,\n PasswordResetWithTokenFormFields,\n UserObject,\n} from './interfaces';\n\nconst RESET_TOKEN_LENGTH = 40;\n\n// Set expiry to 1 hour (in ms)\nconst RESET_TOKEN_EXPIRY = 3600000;\n\nexport async function handleLogout(): Promise<void> {\n const id = await getSessionID();\n\n if (id) {\n await invalidateSession(id);\n }\n}\n\ninterface LoginUserArgs {\n email: string;\n password: string;\n role?: number;\n token?: string;\n}\n\nexport function getAllowedRoles(): number[] {\n const role = process.env.AUTH_ROLE;\n\n if (!role) {\n throw new Error('AUTH_ROLE is not defined. Authentication will not be possible.');\n }\n\n return [Number(role)];\n}\n\nexport function getMaximumRole(): number {\n const roles = getAllowedRoles();\n return Math.max(...roles);\n}\n\nasync function handleUserSession(userID: string): Promise<string | null> {\n await createUserSession(userID, checkMFAEnabled() ? 'MFA' : 'AUTHED');\n\n const scope = await getScopeByID('AUTHED');\n return scope?.redirectOnAuth || null;\n}\n\nexport async function getUserByEmail(email: string, role?: number): Promise<UserObject | null> {\n console.log('[--] getUserByEmail', email, role, getMaximumRole());\n\n const conditions = [eq(authUserTable.email, email), isNull(authUserTable.deletedAt)];\n\n if (role) {\n conditions.push(eq(authUserTable.role, role));\n } else {\n conditions.push(lte(authUserTable.role, getMaximumRole()));\n }\n\n const [user] = await db\n .select()\n .from(authUserTable)\n .where(and(...conditions))\n .limit(1);\n\n console.log('[--] user', user);\n\n return user;\n}\n\nasync function loginUser({ email, password }: LoginUserArgs): Promise<string> {\n if (!process.env.AUTH_ROLE) {\n throw new Error('AUTH_ROLE is not defined. Authentication will not be possible.');\n }\n\n const user = await getUserByEmail(email, Number(process.env.AUTH_ROLE));\n\n if (!user?.password || !(await verifyPassword(password, user.password))) {\n throw new ValidationError({ email: '', password: '' });\n }\n\n const session = await handleUserSession(user.id);\n\n if (!session) {\n throw new ValidationError({ email: '', password: '' });\n }\n\n return session;\n}\n\nexport async function handleLoginForm(\n formData: LoginFormFields,\n onSuccess?: () => Promise<void>\n): Promise<Errorable<string>> {\n const response = await submitForm<LoginFormFields, string>({\n fn: loginUser,\n formData,\n onSuccess: async () => {\n await onSuccess?.();\n },\n request: LoginRequest,\n });\n\n return response;\n}\n\ninterface RegisterUserArgs {\n email: string;\n password?: string;\n role?: number;\n}\n\nexport async function registerUser({\n email,\n password,\n role,\n}: RegisterUserArgs): Promise<UserObject | null> {\n const hash = password ? await hashPassword(password) : null;\n\n const [user] = await db\n .insert(authUserTable)\n .values({ id: generateID(), email, password: hash, role })\n .returning();\n\n return user;\n}\n\nasync function updateDeletedAt(\n email: string,\n role: number,\n deletedAt: Date | null\n): Promise<boolean> {\n const [user] = await db\n .select()\n .from(authUserTable)\n .where(and(eq(authUserTable.email, email), eq(authUserTable.role, role)))\n .limit(1);\n\n if (!user) {\n return false;\n }\n\n await db.update(authUserTable).set({ deletedAt }).where(eq(authUserTable.id, user.id));\n\n return true;\n}\n\nexport async function deleteUser(email: string, role: number): Promise<boolean> {\n return updateDeletedAt(email, role, new Date());\n}\n\nexport async function undeleteUser(email: string, role: number): Promise<boolean> {\n return updateDeletedAt(email, role, null);\n}\n\nasync function createPasswordResetToken(email: string): Promise<string | null> {\n console.log('[--] createPasswordResetToken', email);\n\n const user = await getUserByEmail(email);\n\n console.log('[--] user', user);\n\n if (!user) {\n return null;\n }\n\n await db.delete(authResetTable).where(eq(authResetTable.userId, user.id));\n\n const id = generateID('', RESET_TOKEN_LENGTH);\n\n await db.insert(authResetTable).values({\n id,\n userId: user.id,\n expiresAt: new Date(new Date().getTime() + RESET_TOKEN_EXPIRY),\n });\n\n return id;\n}\n\nexport async function handlePasswordForm(\n formData: PasswordFormFields,\n mailFn: (email: string, token: string) => Promise<boolean>\n): Promise<Errorable<boolean>> {\n console.log('[--] handlePasswordForm', formData);\n\n async function mutateFn(data: PasswordFormFields): Promise<boolean> {\n console.log('[--] mutateFn', data);\n\n const token = await createPasswordResetToken(data.email);\n\n console.log('[--] token', token);\n\n if (!token) {\n // Return true, even though the email doesn't exist (to prevent user enumeration)\n return true;\n }\n\n return mailFn(data.email, token);\n }\n\n const response = await submitForm<PasswordFormFields, boolean>({\n fn: mutateFn,\n formData,\n request: PasswordRequest,\n });\n\n return response;\n}\n\nasync function validatePasswordResetToken(token: string, password: string): Promise<string> {\n const [result] = await db\n .select()\n .from(authResetTable)\n .where(eq(authResetTable.id, token))\n .limit(1);\n\n if (!result) {\n throw new Error('PASSWORD_RESET_TOKEN_NOT_FOUND');\n }\n\n await db.delete(authResetTable).where(eq(authResetTable.id, token));\n\n if (result.expiresAt < new Date()) {\n throw new Error('PASSWORD_RESET_TOKEN_EXPIRED');\n }\n\n await invalidateUserSessions(result.userId);\n\n await db\n .update(authUserTable)\n .set({ password: await hashPassword(password) })\n .where(\n and(eq(authUserTable.id, result.userId), inArray(authUserTable.role, getAllowedRoles()))\n );\n\n return result.userId;\n}\n\nexport async function handlePasswordResetWithTokenForm(\n formData: PasswordResetWithTokenFormFields,\n onSuccess?: (model: string) => Promise<void>\n): Promise<Errorable<string>> {\n async function mutateFn(data: PasswordResetWithTokenFormFields): Promise<string> {\n const userID = await validatePasswordResetToken(data.token, data.password);\n const session = await handleUserSession(userID);\n\n if (!session) {\n throw new Error('COULD_NOT_CREATE_SESSION');\n }\n\n return session;\n }\n\n const response = await submitForm({\n fn: mutateFn,\n formData,\n onSuccess,\n request: PasswordResetWithTokenRequest,\n });\n\n return response;\n}\n","import type { NextRequest } from 'next/server';\nimport { eq } from 'drizzle-orm';\n\nimport { db } from '../database/DatabaseService';\nimport { authClientTable } from '../database/schema';\nimport type { AuthClient } from '../database/schema';\n\nimport { hashPassword, verifyPassword } from './PasswordService';\nimport { generateID } from './SessionService';\n\nconst ID_LENGTH = 16;\nconst SECRET_LENGTH = 64;\n\nexport async function getClientByID(id: string): Promise<AuthClient | null> {\n const [client] = await db\n .select()\n .from(authClientTable)\n .where(eq(authClientTable.id, id))\n .limit(1);\n\n return client;\n}\n\ninterface RegisterClientArgs {\n alias: string;\n id?: string;\n secret?: string;\n}\n\nexport async function registerClient({\n alias,\n id,\n secret,\n}: RegisterClientArgs): Promise<AuthClient | null> {\n const [client] = await db\n .insert(authClientTable)\n .values({\n alias,\n id: id || generateID('', ID_LENGTH),\n secret: await hashPassword(secret || generateID('', SECRET_LENGTH)),\n })\n .returning();\n\n return client;\n}\n\nexport async function handleClientAuth(request: NextRequest): Promise<AuthClient | null> {\n const { headers } = request;\n const header = headers.get('authorization');\n\n if (!header) {\n return null;\n }\n\n const auth = Buffer.from(header.replace('Basic ', ''), 'base64')\n .toString('utf-8')\n .replace(/:$/u, '');\n\n const [id, ...secret] = auth.split('-');\n\n const [client] = await db\n .select()\n .from(authClientTable)\n .where(eq(authClientTable.id, id))\n .limit(1);\n\n if (!client) {\n return null;\n }\n\n const isVerified = await verifyPassword(secret.join(''), client.secret);\n return isVerified ? client : null;\n}\n"]}
@@ -1,3 +1,3 @@
1
- import {eq,and,isNull,isNotNull,lte,inArray}from'drizzle-orm';import {drizzle}from'drizzle-orm/postgres-js';import ge from'postgres';import {pgEnum,pgSchema,text,integer,timestamp,uniqueIndex}from'drizzle-orm/pg-core';import {NextResponse}from'next/server';import H from'joi';import {authenticator}from'otplib';import Be from'qrcode';import {DrizzlePostgreSQLAdapter}from'@lucia-auth/adapter-drizzle';import {pick}from'@sqrzro/utility';import {Lucia,TimeSpan,generateId}from'lucia';import {cookies,headers}from'next/headers';import {match}from'path-to-regexp';import {createClient}from'redis';import re from'bcryptjs';function be(){if(!process.env.DATABASE_URL)throw new Error("DATABASE_URL is not defined");return drizzle(ge(process.env.DATABASE_URL,{prepare:!1}))}var n=globalThis.szdb??be();process.env.VERCEL_ENV||(globalThis.szdb=n);var Ae=10,Se=pgEnum("mfaType",["TOTP","HARDWARE"]),Pe=pgEnum("scope",["ANON","MFA","AUTHED"]),S=pgSchema("auth"),s=S.table("user_credentials",{id:text("id").primaryKey(),email:text("email").notNull(),password:text("password"),role:integer("role").notNull().default(Ae),deletedAt:timestamp("deletedAt")},e=>({unique:uniqueIndex().on(e.email,e.role)})),C=S.table("sessions",{id:text("id").primaryKey(),userId:text("userId").notNull().references(()=>s.id,{onDelete:"cascade"}),scope:Pe("scope").notNull().default("ANON"),expiresAt:timestamp("expiresAt").notNull()}),p=S.table("resets",{id:text("id").primaryKey(),userId:text("userId").notNull().references(()=>s.id,{onDelete:"cascade"}),expiresAt:timestamp("expiresAt").notNull()}),u=S.table("mfas",{id:text("id").primaryKey(),name:text("name").notNull(),userId:text("userId").notNull().references(()=>s.id,{onDelete:"cascade"}),type:Se("type").notNull().default("TOTP"),secret:text("secret").notNull(),verifiedAt:timestamp("verifiedAt")}),h=S.table("client_credentials",{id:text("id").primaryKey(),alias:text("alias").notNull().unique(),secret:text("secret").notNull().unique()});var N=class extends Error{messages;constructor(r){super(JSON.stringify(r)),this.messages=r,this.name="ValidationError";}},c=N;var xe={"alternatives.all":"","alternatives.any":"","alternatives.match":"","alternatives.one":"","alternatives.types":"","any.custom":"","any.default":"","any.failover":"","any.invalid":"","any.only":"","any.ref":"","any.required":"{{#label}} is required","any.unknown":"","array.base":"","array.excludes":"","array.includesRequiredBoth":"","array.includesRequiredKnowns":"","array.includesRequiredUnknowns":"","array.includes":"","array.length":"","array.max":"","array.min":"","array.orderedLength":"","array.sort":"","array.sort.mismatching":"","array.sort.unsupported":"","array.sparse":"","array.unique":"","array.hasKnown":"","array.hasUnknown":"","binary.base":"","binary.length":"","binary.max":"","binary.min":"","boolean.base":"","date.base":"","date.format":"","date.greater":"","date.less":"","date.max":"","date.min":"","date.strict":"","function.arity":"","function.class":"","function.maxArity":"","function.minArity":"","number.base":"{{#label}} should be a number","number.greater":"","number.infinity":"","number.integer":"","number.less":"","number.max":"","number.min":"{{#label}} should be greater than or equal to {{#limit}}","number.multiple":"","number.negative":"","number.port":"","number.positive":"","number.precision":"","number.unsafe":"","object.unknown":"","object.and":"","object.assert":"","object.base":"","object.length":"","object.max":"","object.min":"","object.missing":"","object.nand":"","object.pattern.match":"","object.refType":"","object.regex":"","object.rename.multiple":"","object.rename.override":"","object.schema":"","object.instance":"","object.with":"","object.without":"","object.xor":"","object.oxor":"","string.alphanum":"","string.base64":"","string.base":"","string.creditCard":"","string.dataUri":"","string.domain":"","string.email":"","string.empty":"{{#label}} is required","string.guid":"","string.hexAlign":"","string.hex":"","string.hostname":"","string.ipVersion":"","string.ip":"","string.isoDate":"","string.isoDuration":"","string.length":"","string.lowercase":"","string.max":"","string.min":"","string.normalize":"","string.pattern.base":"{{#label}} is not in the correct format","string.pattern.name":"","string.pattern.invert.base":"","string.pattern.invert.name":"","string.token":"","string.trim":"","string.uppercase":"","string.uri":"","string.uriCustomScheme":"","string.uriRelativeOnly":"","symbol.base":"","symbol.map":""},V=xe;function Fe(){return Object.entries(V).reduce((e,[r,t])=>t?{...e,[r]:t}:e,{})}function Ee(e){let r=e.details.reduce((t,o)=>({...t,[o.path.join(".")]:o.message.replace(/"/gu,"")}),{});return new c(r)}async function z(e,r,t){try{return [await r.validateAsync(e,{abortEarly:!1,messages:t||Fe(),stripUnknown:!0}),null]}catch(o){return o instanceof H.ValidationError?[null,Ee(o)]:o instanceof Error?[null,o]:[null,new Error("Unknown validation error occured")]}}function f(e){return H.object(e)}function J(e){return {cause:e.cause,message:e.message,name:e.name,stack:e.stack}}function Re(e){return !!Object.prototype.hasOwnProperty.call(e,"fn")}async function y(e){let r={...e.formData};if(e.request){let[o,i]=await z(e.formData,e.request);if(i!==null)return i instanceof c&&e.onValidationError?.(i),[null,J(i)];r=o;}if(!Re(e))return await e.onSuccess?.(r),[r,null];let t=null;try{t=await e.fn(r);}catch(o){if(o instanceof c)return e.onValidationError?.(o),[null,J(o)];throw o instanceof Error?o:new Error("The function supplied to submitForm encountered an unknown error")}if(!t)throw new Error("NO_MODEL");return await e.onSuccess?.(t),[t,null]}var ve=f({token:H.string().pattern(/^[0-9]{6}$/u).required()}),k=ve;var P=null;function Oe(e){return e.includes("localhost")||e.includes("127.0.0.1")}async function W(){if(!process.env.REDIS_URL)throw new Error("REDIS_URL is not defined. Access to the cache is not possible.");return P||(P=createClient({socket:{tls:!Oe(process.env.REDIS_URL)},url:process.env.REDIS_URL}),await P.connect(),P)}async function $(e){return (await W()).get(e)}async function B(e,r){await(await W()).set(e,r);}async function M(){let e=process.env.SZ_ORIGIN;if(e)return e;let r=(await headers()).get("x-origin");if(r)return r;let t=(await headers()).get("x-forwarded-proto"),o=(await headers()).get("x-forwarded-host");if(t&&o)return `${t}://${o}`;throw new Error("No origin could be determined")}var G="/auth/login",_e=16,R={ANON:{allowedRoute:"/auth/(login|password)",redirectOnUnauth:G},MFA:{allowedRoute:"/auth/mfa",redirectOnUnauth:"/auth/mfa"},AUTHED:{allowedRoute:"*",redirectOnAuth:"/"}},qe={D:"d",H:"h",M:"m",MS:"ms",S:"s",W:"w"};function Le(){if(!process.env.AUTH_SESSION_EXPIRY)return new TimeSpan(2,"w");let[e,r]=process.env.AUTH_SESSION_EXPIRY.split(/_/u);return new TimeSpan(Number(e),qe[r])}var Ce=new DrizzlePostgreSQLAdapter(n,C,s),g=new Lucia(Ce,{getSessionAttributes:e=>({scope:e.scope}),getUserAttributes:e=>({email:e.email,role:e.role,deletedAt:e.deletedAt}),sessionCookie:{attributes:{secure:process.env.APP_ENV==="production"},name:process.env.AUTH_COOKIE_NAME||"auth_session"},sessionExpiresIn:Le()});function b(e="",r=_e){return `${e?`${e}_`:""}${generateId(r)}`}async function X(e){let r=g.createBlankSessionCookie();return (await cookies()).set(r.name,r.value,r.attributes),g.invalidateSession(e)}async function T(e){return g.invalidateUserSessions(e)}async function v(e,r="ANON"){let t=await g.createSession(e,{scope:r}),o=g.createSessionCookie(t.id);return (await cookies()).set(o.name,o.value,o.attributes),!0}async function U(){return (await cookies()).get(g.sessionCookieName)?.value??null}async function tt(){return !!await U()}function Ve(e,r){let t=Array.isArray(r)?r:[r];return t[0]?t.includes(e):x().includes(e)}async function Y(e){let r=await U();if(!r)return null;let{user:t}=await g.validateSession(r);return !t||t.deletedAt||!Ve(t.role,e)?null:pick(t,["id","email","role"])}function He(e,r){return r?r==="*"?!0:match(r)(e)!==!1:!1}async function Z(){let e=await $(`${await M()}:scopes`);return e?JSON.parse(e):R}async function Q(e){return (await Z())[e]}async function ze(e){let r={ANON:{...R.ANON,...e?.ANON},MFA:{...R.MFA,...e?.MFA},AUTHED:{...R.AUTHED,...e?.AUTHED}};return B(`${await M()}:scopes`,JSON.stringify(r))}async function Je(e,r){let t=await Z(),{session:o,user:i}=await g.validateSession(e),a=t[o&&x().includes(i?.role)?o.scope:"ANON"];return {email:i?.email||null,redirect:He(r,a.allowedRoute)?null:a.redirectOnUnauth||G}}async function ot(e,r){let t=e.nextUrl.searchParams.get("id")||"",o=e.nextUrl.searchParams.get("pathname")||"/";return await ze(r),NextResponse.json(await Je(t,o))}function w(){return process.env.AUTH_MFA_ENABLED!=="false"}async function ft(e,r){if(!w())throw new Error("MFA is not enabled. Cannot generate MFA secret.");if(!r)return null;let[t]=await n.select().from(s).where(eq(s.email,r)).limit(1);if(!t)return null;let o=authenticator.generateSecret(),i=authenticator.keyuri(r,e,o);return await n.delete(u).where(and(eq(u.userId,t.id),isNull(u.verifiedAt))),await n.insert(u).values({id:b(),name:"Default",secret:o,userId:t.id}),new Promise((a,m)=>{Be.toDataURL(i,{rendererOpts:{quality:1},margin:0,scale:2},(D,pe)=>{D&&m(D),a(pe);});})}async function gt(e){if(!w())return !1;let[r]=await n.select().from(u).where(and(eq(u.userId,e.id),isNotNull(u.verifiedAt))).limit(1);return !!r}async function Ke(e){w()&&await n.update(u).set({verifiedAt:new Date}).where(eq(u.userId,e));}async function Ge(e,r){if(!w())return !1;let[t]=await n.select().from(u).where(eq(u.userId,e)).limit(1);return t?authenticator.check(r,t.secret):!1}async function bt(e){let r=[n.delete(u).where(eq(u.userId,e)),T(e)];return await Promise.all(r),!0}async function Xe(e){if(!w())throw new c({token:"MFA is not enabled"});let r=await Y();if(!r)throw new c({token:"User not found"});if(!await Ge(r.id,e.token))throw new c({token:"Invalid token"});return await Ke(r.id),v(r.id,"AUTHED")}async function wt(e){return w()?await y({fn:Xe,formData:e,request:k}):[null,new Error("MFA is not enabled")]}var Ye=12,te={min:8,upper:1,lower:1,number:1,symbol:1};function Ze(e,r){return e.length>=r}function Qe(e,r){return e.replace(/[^A-Z]/gu,"").length>=r}function er(e,r){return e.replace(/[^a-z]/gu,"").length>=r}function rr(e,r){return e.replace(/[^0-9]/gu,"").length>=r}function tr(e,r){return e.replace(/[^$]/gu,"").length>=r}var or={min:Ze,upper:Qe,lower:er,number:rr,symbol:tr};async function F(e){return await re.hash(e,Ye)}async function O(e,r){return !e||!r?!1:await re.compare(e,r)}async function nr(e,r=te){let o=Object.entries(r).reduce((i,[a,m])=>(i[a]=or[a](e,m),i),{});return Promise.resolve(o)}async function oe(e,r=te){let t=await nr(e,r);return Promise.resolve(Object.values(t).every(Boolean))}var sr=f({email:H.string().email({minDomainSegments:2,tlds:!1}).required(),password:H.string().min(8).required()}),se=sr;var ar=f({email:H.string().max(60).email({minDomainSegments:2,tlds:!1}).required().messages({"any.required":"Please provide your email address, so we can send you a reset link","string.empty":"Please provide your email address, so we can send you a reset link","string.email":"Please make sure your email address is valid","string.max":"Please make sure your email address is valid"})}),ie=ar;var lr={lower:1,min:8,number:1,upper:1};async function ur(e,r){return await oe(e,lr)?e:r.message({external:"Please make sure your password is complex enough, to keep your account secure"})}var cr=f({password:H.string().external(ur).required().messages({"any.required":"Please provide your new password","string.empty":"Please provide your new password"}),token:H.string().pattern(/[a-z0-9]{40}/u)}),le=cr;var fr=40,gr=36e5;async function Ht(){let e=await U();e&&await X(e);}function x(){let e=process.env.AUTH_ROLE;if(!e)throw new Error("AUTH_ROLE is not defined. Authentication will not be possible.");return [Number(e)]}function br(){let e=x();return Math.max(...e)}async function ue(e){return await v(e,w()?"MFA":"AUTHED"),(await Q("AUTHED"))?.redirectOnAuth||null}async function ce(e,r){let t=[eq(s.email,e),isNull(s.deletedAt)];r?t.push(eq(s.role,r)):t.push(lte(s.role,br()));let[o]=await n.select().from(s).where(and(...t)).limit(1);return o}async function wr({email:e,password:r}){if(!process.env.AUTH_ROLE)throw new Error("AUTH_ROLE is not defined. Authentication will not be possible.");let t=await ce(e,Number(process.env.AUTH_ROLE));if(!t?.password||!await O(r,t.password))throw new c({email:"",password:""});let o=await ue(t.id);if(!o)throw new c({email:"",password:""});return o}async function zt(e,r){return await y({fn:wr,formData:e,onSuccess:async()=>{await r?.();},request:se})}async function Jt({email:e,password:r,role:t}){let o=r?await F(r):null,[i]=await n.insert(s).values({id:b(),email:e,password:o,role:t}).returning();return i}async function me(e,r,t){let[o]=await n.select().from(s).where(and(eq(s.email,e),eq(s.role,r))).limit(1);return o?(await n.update(s).set({deletedAt:t}).where(eq(s.id,o.id)),!0):!1}async function Wt(e,r){return me(e,r,new Date)}async function $t(e,r){return me(e,r,null)}async function hr(e){let r=await ce(e);if(!r)return null;await n.delete(p).where(eq(p.userId,r.id));let t=b("",fr);return await n.insert(p).values({id:t,userId:r.id,expiresAt:new Date(new Date().getTime()+gr)}),t}async function Bt(e,r){async function t(i){let a=await hr(i.email);return a?r(i.email,a):!0}return await y({fn:t,formData:e,request:ie})}async function yr(e,r){let[t]=await n.select().from(p).where(eq(p.id,e)).limit(1);if(!t)throw new Error("PASSWORD_RESET_TOKEN_NOT_FOUND");if(await n.delete(p).where(eq(p.id,e)),t.expiresAt<new Date)throw new Error("PASSWORD_RESET_TOKEN_EXPIRED");return await T(t.userId),await n.update(s).set({password:await F(r)}).where(and(eq(s.id,t.userId),inArray(s.role,x()))),t.userId}async function Kt(e,r){async function t(i){let a=await yr(i.token,i.password),m=await ue(a);if(!m)throw new Error("COULD_NOT_CREATE_SESSION");return m}return await y({fn:t,formData:e,onSuccess:r,request:le})}var Ar=16,Sr=64;async function ro(e){let[r]=await n.select().from(h).where(eq(h.id,e)).limit(1);return r}async function to({alias:e,id:r,secret:t}){let[o]=await n.insert(h).values({alias:e,id:r||b("",Ar),secret:await F(t||b("",Sr))}).returning();return o}async function oo(e){let{headers:r}=e,t=r.get("authorization");if(!t)return null;let o=Buffer.from(t.replace("Basic ",""),"base64").toString("utf-8").replace(/:$/u,""),[i,...a]=o.split("-"),[m]=await n.select().from(h).where(eq(h.id,i)).limit(1);return m&&await O(a.join(""),m.secret)?m:null}
2
- export{k as MFARequest,w as checkMFAEnabled,oe as checkPasswordComplexity,He as checkRouteAllowed,tt as checkSessionExists,gt as checkUserHasMFA,v as createUserSession,bt as deleteMFA,Wt as deleteUser,b as generateID,ft as generateMFA,x as getAllowedRoles,ro as getClientByID,br as getMaximumRole,nr as getPasswordComplexity,Q as getScopeByID,Z as getScopes,U as getSessionID,Y as getSessionUser,ce as getUserByEmail,oo as handleClientAuth,zt as handleLoginForm,Ht as handleLogout,Xe as handleMFA,wt as handleMFAForm,Bt as handlePasswordForm,Kt as handlePasswordResetWithTokenForm,ot as handleSession,F as hashPassword,X as invalidateSession,T as invalidateUserSessions,g as lucia,to as registerClient,Jt as registerUser,ze as setScopes,$t as undeleteUser,O as verifyPassword};//# sourceMappingURL=index.js.map
1
+ import {eq,and,isNull,isNotNull,lte,inArray}from'drizzle-orm';import {drizzle}from'drizzle-orm/postgres-js';import be from'postgres';import {pgEnum,pgSchema,text,integer,timestamp,uniqueIndex}from'drizzle-orm/pg-core';import {NextResponse}from'next/server';import H from'joi';import {authenticator}from'otplib';import Ke from'qrcode';import {DrizzlePostgreSQLAdapter}from'@lucia-auth/adapter-drizzle';import {pick}from'@sqrzro/utility';import {Lucia,TimeSpan,generateId}from'lucia';import {cookies,headers}from'next/headers';import {match}from'path-to-regexp';import {createClient}from'redis';import re from'bcryptjs';function we(){if(!process.env.DATABASE_URL)throw new Error("DATABASE_URL is not defined");return drizzle(be(process.env.DATABASE_URL,{prepare:!1}))}var n=globalThis.szdb??we();process.env.VERCEL_ENV||(globalThis.szdb=n);var Pe=10,Se=pgEnum("mfaType",["TOTP","HARDWARE"]),xe=pgEnum("scope",["ANON","MFA","AUTHED"]),P=pgSchema("auth"),i=P.table("user_credentials",{id:text("id").primaryKey(),email:text("email").notNull(),password:text("password"),role:integer("role").notNull().default(Pe),deletedAt:timestamp("deletedAt")},e=>({unique:uniqueIndex().on(e.email,e.role)})),C=P.table("sessions",{id:text("id").primaryKey(),userId:text("userId").notNull().references(()=>i.id,{onDelete:"cascade"}),scope:xe("scope").notNull().default("ANON"),expiresAt:timestamp("expiresAt").notNull()}),p=P.table("resets",{id:text("id").primaryKey(),userId:text("userId").notNull().references(()=>i.id,{onDelete:"cascade"}),expiresAt:timestamp("expiresAt").notNull()}),u=P.table("mfas",{id:text("id").primaryKey(),name:text("name").notNull(),userId:text("userId").notNull().references(()=>i.id,{onDelete:"cascade"}),type:Se("type").notNull().default("TOTP"),secret:text("secret").notNull(),verifiedAt:timestamp("verifiedAt")}),h=P.table("client_credentials",{id:text("id").primaryKey(),alias:text("alias").notNull().unique(),secret:text("secret").notNull().unique()});var N=class extends Error{messages;constructor(r){super(JSON.stringify(r)),this.messages=r,this.name="ValidationError";}},c=N;var Fe={"alternatives.all":"","alternatives.any":"","alternatives.match":"","alternatives.one":"","alternatives.types":"","any.custom":"","any.default":"","any.failover":"","any.invalid":"","any.only":"","any.ref":"","any.required":"{{#label}} is required","any.unknown":"","array.base":"","array.excludes":"","array.includesRequiredBoth":"","array.includesRequiredKnowns":"","array.includesRequiredUnknowns":"","array.includes":"","array.length":"","array.max":"","array.min":"","array.orderedLength":"","array.sort":"","array.sort.mismatching":"","array.sort.unsupported":"","array.sparse":"","array.unique":"","array.hasKnown":"","array.hasUnknown":"","binary.base":"","binary.length":"","binary.max":"","binary.min":"","boolean.base":"","date.base":"","date.format":"","date.greater":"","date.less":"","date.max":"","date.min":"","date.strict":"","function.arity":"","function.class":"","function.maxArity":"","function.minArity":"","number.base":"{{#label}} should be a number","number.greater":"","number.infinity":"","number.integer":"","number.less":"","number.max":"","number.min":"{{#label}} should be greater than or equal to {{#limit}}","number.multiple":"","number.negative":"","number.port":"","number.positive":"","number.precision":"","number.unsafe":"","object.unknown":"","object.and":"","object.assert":"","object.base":"","object.length":"","object.max":"","object.min":"","object.missing":"","object.nand":"","object.pattern.match":"","object.refType":"","object.regex":"","object.rename.multiple":"","object.rename.override":"","object.schema":"","object.instance":"","object.with":"","object.without":"","object.xor":"","object.oxor":"","string.alphanum":"","string.base64":"","string.base":"","string.creditCard":"","string.dataUri":"","string.domain":"","string.email":"","string.empty":"{{#label}} is required","string.guid":"","string.hexAlign":"","string.hex":"","string.hostname":"","string.ipVersion":"","string.ip":"","string.isoDate":"","string.isoDuration":"","string.length":"","string.lowercase":"","string.max":"","string.min":"","string.normalize":"","string.pattern.base":"{{#label}} is not in the correct format","string.pattern.name":"","string.pattern.invert.base":"","string.pattern.invert.name":"","string.token":"","string.trim":"","string.uppercase":"","string.uri":"","string.uriCustomScheme":"","string.uriRelativeOnly":"","symbol.base":"","symbol.map":""},V=Fe;function Ee(){return Object.entries(V).reduce((e,[r,t])=>t?{...e,[r]:t}:e,{})}function Re(e){let r=e.details.reduce((t,o)=>({...t,[o.path.join(".")]:o.message.replace(/"/gu,"")}),{});return new c(r)}async function z(e,r,t){try{return [await r.validateAsync(e,{abortEarly:!1,messages:t||Ee(),stripUnknown:!0}),null]}catch(o){return o instanceof H.ValidationError?[null,Re(o)]:o instanceof Error?[null,o]:[null,new Error("Unknown validation error occured")]}}function f(e){return H.object(e)}function J(e){return {cause:e.cause,message:e.message,name:e.name,stack:e.stack}}function Te(e){return !!Object.prototype.hasOwnProperty.call(e,"fn")}async function y(e){let r={...e.formData};if(e.request){let[o,s]=await z(e.formData,e.request);if(s!==null)return s instanceof c&&e.onValidationError?.(s),[null,J(s)];r=o;}if(!Te(e))return await e.onSuccess?.(r),[r,null];let t=null;try{t=await e.fn(r);}catch(o){if(o instanceof c)return e.onValidationError?.(o),[null,J(o)];throw o instanceof Error?o:new Error("The function supplied to submitForm encountered an unknown error")}if(!t)throw new Error("NO_MODEL");return await e.onSuccess?.(t),[t,null]}var Ue=f({token:H.string().pattern(/^[0-9]{6}$/u).required()}),k=Ue;var S=null;function De(e){return e.includes("localhost")||e.includes("127.0.0.1")}async function W(){if(!process.env.REDIS_URL)throw new Error("REDIS_URL is not defined. Access to the cache is not possible.");return S||(S=createClient({socket:{tls:!De(process.env.REDIS_URL)},url:process.env.REDIS_URL}),await S.connect(),S)}async function $(e){return (await W()).get(e)}async function B(e,r){await(await W()).set(e,r);}async function M(){let e=process.env.SZ_ORIGIN;if(e)return e;let r=(await headers()).get("x-origin");if(r)return r;let t=(await headers()).get("x-forwarded-proto"),o=(await headers()).get("x-forwarded-host");if(t&&o)return `${t}://${o}`;throw new Error("No origin could be determined")}var G="/auth/login",qe=16,R={ANON:{allowedRoute:"/auth/(login|password)",redirectOnUnauth:G},MFA:{allowedRoute:"/auth/mfa",redirectOnUnauth:"/auth/mfa"},AUTHED:{allowedRoute:"*",redirectOnAuth:"/"}},Le={D:"d",H:"h",M:"m",MS:"ms",S:"s",W:"w"};function Ce(){if(!process.env.AUTH_SESSION_EXPIRY)return new TimeSpan(2,"w");let[e,r]=process.env.AUTH_SESSION_EXPIRY.split(/_/u);return new TimeSpan(Number(e),Le[r])}var Ve=new DrizzlePostgreSQLAdapter(n,C,i),g=new Lucia(Ve,{getSessionAttributes:e=>({scope:e.scope}),getUserAttributes:e=>({email:e.email,role:e.role,deletedAt:e.deletedAt}),sessionCookie:{attributes:{secure:process.env.APP_ENV==="production"},name:process.env.AUTH_COOKIE_NAME||"auth_session"},sessionExpiresIn:Ce()});function b(e="",r=qe){return `${e?`${e}_`:""}${generateId(r)}`}async function X(e){let r=g.createBlankSessionCookie();return (await cookies()).set(r.name,r.value,r.attributes),g.invalidateSession(e)}async function T(e){return g.invalidateUserSessions(e)}async function v(e,r="ANON"){let t=await g.createSession(e,{scope:r}),o=g.createSessionCookie(t.id);return (await cookies()).set(o.name,o.value,o.attributes),!0}async function U(){return (await cookies()).get(g.sessionCookieName)?.value??null}async function tt(){return !!await U()}function He(e,r){let t=Array.isArray(r)?r:[r];return t[0]?t.includes(e):x().includes(e)}async function Y(e){let r=await U();if(!r)return null;let{user:t}=await g.validateSession(r);return !t||t.deletedAt||!He(t.role,e)?null:pick(t,["id","email","role"])}function ze(e,r){return r?r==="*"?!0:match(r)(e)!==!1:!1}async function Z(){let e=await $(`${await M()}:scopes`);return e?JSON.parse(e):R}async function Q(e){return (await Z())[e]}async function Je(e){let r={ANON:{...R.ANON,...e?.ANON},MFA:{...R.MFA,...e?.MFA},AUTHED:{...R.AUTHED,...e?.AUTHED}};return B(`${await M()}:scopes`,JSON.stringify(r))}async function We(e,r){let t=await Z(),{session:o,user:s}=await g.validateSession(e),a=t[o&&x().includes(s?.role)?o.scope:"ANON"];return {email:s?.email||null,redirect:ze(r,a.allowedRoute)?null:a.redirectOnUnauth||G}}async function ot(e,r){let t=e.nextUrl.searchParams.get("id")||"",o=e.nextUrl.searchParams.get("pathname")||"/";return await Je(r),NextResponse.json(await We(t,o))}function w(){return process.env.AUTH_MFA_ENABLED!=="false"}async function ft(e,r){if(!w())throw new Error("MFA is not enabled. Cannot generate MFA secret.");if(!r)return null;let[t]=await n.select().from(i).where(eq(i.email,r)).limit(1);if(!t)return null;let o=authenticator.generateSecret(),s=authenticator.keyuri(r,e,o);return await n.delete(u).where(and(eq(u.userId,t.id),isNull(u.verifiedAt))),await n.insert(u).values({id:b(),name:"Default",secret:o,userId:t.id}),new Promise((a,m)=>{Ke.toDataURL(s,{rendererOpts:{quality:1},margin:0,scale:2},(D,fe)=>{D&&m(D),a(fe);});})}async function gt(e){if(!w())return !1;let[r]=await n.select().from(u).where(and(eq(u.userId,e.id),isNotNull(u.verifiedAt))).limit(1);return !!r}async function Ge(e){w()&&await n.update(u).set({verifiedAt:new Date}).where(eq(u.userId,e));}async function Xe(e,r){if(!w())return !1;let[t]=await n.select().from(u).where(eq(u.userId,e)).limit(1);return t?authenticator.check(r,t.secret):!1}async function bt(e){let r=[n.delete(u).where(eq(u.userId,e)),T(e)];return await Promise.all(r),!0}async function Ye(e){if(!w())throw new c({token:"MFA is not enabled"});let r=await Y();if(!r)throw new c({token:"User not found"});if(!await Xe(r.id,e.token))throw new c({token:"Invalid token"});return await Ge(r.id),v(r.id,"AUTHED")}async function wt(e){return w()?await y({fn:Ye,formData:e,request:k}):[null,new Error("MFA is not enabled")]}var Ze=12,te={min:8,upper:1,lower:1,number:1,symbol:1};function Qe(e,r){return e.length>=r}function er(e,r){return e.replace(/[^A-Z]/gu,"").length>=r}function rr(e,r){return e.replace(/[^a-z]/gu,"").length>=r}function tr(e,r){return e.replace(/[^0-9]/gu,"").length>=r}function or(e,r){return e.replace(/[^$]/gu,"").length>=r}var nr={min:Qe,upper:er,lower:rr,number:tr,symbol:or};async function F(e){return await re.hash(e,Ze)}async function O(e,r){return !e||!r?!1:await re.compare(e,r)}async function sr(e,r=te){let o=Object.entries(r).reduce((s,[a,m])=>(s[a]=nr[a](e,m),s),{});return Promise.resolve(o)}async function oe(e,r=te){let t=await sr(e,r);return Promise.resolve(Object.values(t).every(Boolean))}var ir=f({email:H.string().email({minDomainSegments:2,tlds:!1}).required(),password:H.string().min(8).required()}),se=ir;var lr=f({email:H.string().max(60).email({minDomainSegments:2,tlds:!1}).required().messages({"any.required":"Please provide your email address, so we can send you a reset link","string.empty":"Please provide your email address, so we can send you a reset link","string.email":"Please make sure your email address is valid","string.max":"Please make sure your email address is valid"})}),ie=lr;var ur={lower:1,min:8,number:1,upper:1};async function cr(e,r){return await oe(e,ur)?e:r.message({external:"Please make sure your password is complex enough, to keep your account secure"})}var mr=f({password:H.string().external(cr).required().messages({"any.required":"Please provide your new password","string.empty":"Please provide your new password"}),token:H.string().pattern(/[a-z0-9]{40}/u)}),le=mr;var gr=40,br=36e5;async function Ht(){let e=await U();e&&await X(e);}function x(){let e=process.env.AUTH_ROLE;if(!e)throw new Error("AUTH_ROLE is not defined. Authentication will not be possible.");return [Number(e)]}function ue(){let e=x();return Math.max(...e)}async function ce(e){return await v(e,w()?"MFA":"AUTHED"),(await Q("AUTHED"))?.redirectOnAuth||null}async function me(e,r){console.log("[--] getUserByEmail",e,r,ue());let t=[eq(i.email,e),isNull(i.deletedAt)];r?t.push(eq(i.role,r)):t.push(lte(i.role,ue()));let[o]=await n.select().from(i).where(and(...t)).limit(1);return console.log("[--] user",o),o}async function wr({email:e,password:r}){if(!process.env.AUTH_ROLE)throw new Error("AUTH_ROLE is not defined. Authentication will not be possible.");let t=await me(e,Number(process.env.AUTH_ROLE));if(!t?.password||!await O(r,t.password))throw new c({email:"",password:""});let o=await ce(t.id);if(!o)throw new c({email:"",password:""});return o}async function zt(e,r){return await y({fn:wr,formData:e,onSuccess:async()=>{await r?.();},request:se})}async function Jt({email:e,password:r,role:t}){let o=r?await F(r):null,[s]=await n.insert(i).values({id:b(),email:e,password:o,role:t}).returning();return s}async function de(e,r,t){let[o]=await n.select().from(i).where(and(eq(i.email,e),eq(i.role,r))).limit(1);return o?(await n.update(i).set({deletedAt:t}).where(eq(i.id,o.id)),!0):!1}async function Wt(e,r){return de(e,r,new Date)}async function $t(e,r){return de(e,r,null)}async function hr(e){console.log("[--] createPasswordResetToken",e);let r=await me(e);if(console.log("[--] user",r),!r)return null;await n.delete(p).where(eq(p.userId,r.id));let t=b("",gr);return await n.insert(p).values({id:t,userId:r.id,expiresAt:new Date(new Date().getTime()+br)}),t}async function Bt(e,r){console.log("[--] handlePasswordForm",e);async function t(s){console.log("[--] mutateFn",s);let a=await hr(s.email);return console.log("[--] token",a),a?r(s.email,a):!0}return await y({fn:t,formData:e,request:ie})}async function yr(e,r){let[t]=await n.select().from(p).where(eq(p.id,e)).limit(1);if(!t)throw new Error("PASSWORD_RESET_TOKEN_NOT_FOUND");if(await n.delete(p).where(eq(p.id,e)),t.expiresAt<new Date)throw new Error("PASSWORD_RESET_TOKEN_EXPIRED");return await T(t.userId),await n.update(i).set({password:await F(r)}).where(and(eq(i.id,t.userId),inArray(i.role,x()))),t.userId}async function Kt(e,r){async function t(s){let a=await yr(s.token,s.password),m=await ce(a);if(!m)throw new Error("COULD_NOT_CREATE_SESSION");return m}return await y({fn:t,formData:e,onSuccess:r,request:le})}var Ar=16,Pr=64;async function ro(e){let[r]=await n.select().from(h).where(eq(h.id,e)).limit(1);return r}async function to({alias:e,id:r,secret:t}){let[o]=await n.insert(h).values({alias:e,id:r||b("",Ar),secret:await F(t||b("",Pr))}).returning();return o}async function oo(e){let{headers:r}=e,t=r.get("authorization");if(!t)return null;let o=Buffer.from(t.replace("Basic ",""),"base64").toString("utf-8").replace(/:$/u,""),[s,...a]=o.split("-"),[m]=await n.select().from(h).where(eq(h.id,s)).limit(1);return m&&await O(a.join(""),m.secret)?m:null}
2
+ export{k as MFARequest,w as checkMFAEnabled,oe as checkPasswordComplexity,ze as checkRouteAllowed,tt as checkSessionExists,gt as checkUserHasMFA,v as createUserSession,bt as deleteMFA,Wt as deleteUser,b as generateID,ft as generateMFA,x as getAllowedRoles,ro as getClientByID,ue as getMaximumRole,sr as getPasswordComplexity,Q as getScopeByID,Z as getScopes,U as getSessionID,Y as getSessionUser,me as getUserByEmail,oo as handleClientAuth,zt as handleLoginForm,Ht as handleLogout,Ye as handleMFA,wt as handleMFAForm,Bt as handlePasswordForm,Kt as handlePasswordResetWithTokenForm,ot as handleSession,F as hashPassword,X as invalidateSession,T as invalidateUserSessions,g as lucia,to as registerClient,Jt as registerUser,Je as setScopes,$t as undeleteUser,O as verifyPassword};//# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/database/DatabaseService.ts","../../src/database/schema.ts","../../src/forms/ValidationError.ts","../../src/forms/ValidationService.ts","../../src/forms/lang.ts","../../src/forms/FormService.ts","../../src/auth/MFARequest.ts","../../src/cache/CacheService.ts","../../src/url/URLService.ts","../../src/auth/SessionService.ts","../../src/auth/MFAService.ts","../../src/auth/PasswordService.ts","../../src/auth/LoginRequest.ts","../../src/auth/PasswordRequest.ts","../../src/auth/PasswordResetWithTokenRequest.ts","../../src/auth/AuthService.ts","../../src/auth/ClientService.ts"],"names":["createSingleton","drizzle","postgres","db","DEFAULT_ROLE","mfaType","pgEnum","scope","authSchema","pgSchema","authUserTable","text","integer","timestamp","table","uniqueIndex","authSessionTable","authResetTable","authMFATable","authClientTable","ValidationError","messages","ValidationError_default","lang_default","getErrorMessages","acc","key","value","transformErrors","error","cur","validateSchema","formData","validation","err","Joi","createSchema","schema","serializeError","hasFn","args","submitForm","data","validated","validationError","model","MFARequest","MFARequest_default","client","isLocalhost","url","getClient","createClient","getFromCache","setToCache","getOrigin","envOrigin","origin","headers","proto","host","DEFAULT_REDIRECT","ID_LENGTH","DEFAULT_SCOPES","timespanMap","getSessionExpiry","TimeSpan","unit","adapter","DrizzlePostgreSQLAdapter","lucia","Lucia","attributes","generateID","prefix","length","generateId","invalidateSession","id","cookie","cookies","invalidateUserSessions","createUserSession","session","sessionCookie","getSessionID","checkSessionExists","checkUserRole","userRole","targetRoles","targetRolesArray","getAllowedRoles","getSessionUser","roles","sessionID","user","pick","checkRouteAllowed","pathname","route","match","getScopes","scopes","getScopeByID","setScopes","customScopes","validateSessionFromID","handleSession","request","NextResponse","checkMFAEnabled","generateMFA","name","email","eq","secret","authenticator","otpauth","and","isNull","resolve","reject","qrcode","checkUserHasMFA","mfa","isNotNull","markAsVerified","userID","validateUserToken","token","deleteMFA","promises","handleMFA","handleMFAForm","PW_SALT_ROUNDS","PASSWORD_RULES","checkPasswordMin","password","checkPasswordUpper","checkPasswordLower","checkPasswordNumber","checkPasswordSymbol","PASSWORD_FUNCTIONS","hashPassword","bcrypt","verifyPassword","encrypted","getPasswordComplexity","rules","validity","rule","checkPasswordComplexity","LoginRequest","LoginRequest_default","PasswordRequest","PasswordRequest_default","passwordComplexity","passwordIsComplex","helpers","PasswordResetWithTokenRequest","PasswordResetWithTokenRequest_default","RESET_TOKEN_LENGTH","RESET_TOKEN_EXPIRY","handleLogout","role","getMaximumRole","handleUserSession","getUserByEmail","conditions","lte","loginUser","handleLoginForm","onSuccess","registerUser","hash","updateDeletedAt","deletedAt","deleteUser","undeleteUser","createPasswordResetToken","handlePasswordForm","mailFn","mutateFn","validatePasswordResetToken","result","inArray","handlePasswordResetWithTokenForm","SECRET_LENGTH","getClientByID","registerClient","alias","handleClientAuth","header","auth"],"mappings":"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","file":"index.js","sourcesContent":["import { drizzle } from 'drizzle-orm/postgres-js';\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\nimport postgres from 'postgres';\n\ndeclare global {\n var szdb: ReturnType<typeof createSingleton> | undefined; // eslint-disable-line no-var, vars-on-top\n}\n\nfunction createSingleton(): PostgresJsDatabase {\n if (!process.env.DATABASE_URL) {\n throw new Error('DATABASE_URL is not defined');\n }\n return drizzle(postgres(process.env.DATABASE_URL, { prepare: false }));\n}\n\nexport const db = globalThis.szdb ?? createSingleton();\n\nif (!process.env.VERCEL_ENV) {\n globalThis.szdb = db;\n}\n","/* istanbul ignore file */\n\nimport { integer, pgEnum, pgSchema, text, timestamp, uniqueIndex } from 'drizzle-orm/pg-core';\n\nconst DEFAULT_ROLE = 10;\n\nexport const mfaType = pgEnum('mfaType', ['TOTP', 'HARDWARE']);\nexport const scope = pgEnum('scope', ['ANON', 'MFA', 'AUTHED']);\n\nexport type Scope = (typeof scope.enumValues)[number];\n\nexport const authSchema = pgSchema('auth');\n\nexport const authUserTable = authSchema.table(\n 'user_credentials',\n {\n id: text('id').primaryKey(),\n email: text('email').notNull(),\n password: text('password'),\n role: integer('role').notNull().default(DEFAULT_ROLE),\n deletedAt: timestamp('deletedAt'),\n },\n (table) => ({\n unique: uniqueIndex().on(table.email, table.role),\n })\n);\n\nexport type AuthUser = typeof authUserTable.$inferSelect;\n\nexport const authSessionTable = authSchema.table('sessions', {\n id: text('id').primaryKey(),\n userId: text('userId')\n .notNull()\n .references(() => authUserTable.id, { onDelete: 'cascade' }),\n scope: scope('scope').notNull().default('ANON'),\n expiresAt: timestamp('expiresAt').notNull(),\n});\n\nexport type AuthSession = typeof authSessionTable.$inferSelect;\n\nexport const authResetTable = authSchema.table('resets', {\n id: text('id').primaryKey(),\n userId: text('userId')\n .notNull()\n .references(() => authUserTable.id, { onDelete: 'cascade' }),\n expiresAt: timestamp('expiresAt').notNull(),\n});\n\nexport type AuthReset = typeof authResetTable.$inferSelect;\n\nexport const authMFATable = authSchema.table('mfas', {\n id: text('id').primaryKey(),\n name: text('name').notNull(),\n userId: text('userId')\n .notNull()\n .references(() => authUserTable.id, { onDelete: 'cascade' }),\n type: mfaType('type').notNull().default('TOTP'),\n secret: text('secret').notNull(),\n verifiedAt: timestamp('verifiedAt'),\n});\n\nexport type AuthMFA = typeof authMFATable.$inferSelect;\n\nexport const authClientTable = authSchema.table('client_credentials', {\n id: text('id').primaryKey(),\n alias: text('alias').notNull().unique(),\n secret: text('secret').notNull().unique(),\n});\n\nexport type AuthClient = typeof authClientTable.$inferSelect;\n","class ValidationError extends Error {\n public messages: Record<string, string>;\n\n public constructor(messages: Record<string, string>) {\n super(JSON.stringify(messages));\n\n this.messages = messages;\n this.name = 'ValidationError';\n }\n}\n\nexport default ValidationError;\n","import type { Errorable } from '@sqrzro/interfaces';\nimport Joi from 'joi';\n\nimport lang from './lang';\nimport ValidationError from './ValidationError';\n\nexport function validate(): typeof Joi {\n return Joi;\n}\n\nexport type ValidationCustomHelpers<V = any> = Joi.CustomHelpers<V>; // eslint-disable-line @typescript-eslint/no-explicit-any\nexport type ValidationExternalHelpers<V = any> = Joi.ExternalHelpers<V>; // eslint-disable-line @typescript-eslint/no-explicit-any\nexport type ValidationErrorReport = Joi.ErrorReport;\n\nexport function getDefaultErrorMessages(): Record<string, string> {\n return lang;\n}\n\nfunction getErrorMessages(): Record<string, string> {\n return Object.entries(lang).reduce((acc, [key, value]) => {\n if (!value) {\n return acc;\n }\n return {\n ...acc,\n [key]: value,\n };\n }, {});\n}\n\nfunction transformErrors(error: Joi.ValidationError): ValidationError {\n const messages = error.details.reduce(\n (acc, cur) => ({\n ...acc,\n [cur.path.join('.')]: cur.message.replace(/\"/gu, ''),\n }),\n {}\n );\n return new ValidationError(messages);\n}\n\n/**\n * This function takes FormData and a schema. It then attempts to transform the FormData into an\n * object that matches `T`. This is because the FormData object is not typed and we want to be able\n * to validate it properly typed.\n *\n * Once transformed, the object is validated against the schema. This will result in either a\n * properly typed `T` object or an array of validation errors.\n * @param formData\n * @param validation\n * @returns\n */\nexport async function validateSchema<T>(\n formData: Partial<T>,\n validation: Joi.ObjectSchema<T>,\n messages?: Record<string, string>\n): Promise<Errorable<T>> {\n try {\n const validated = await validation.validateAsync(formData, {\n abortEarly: false,\n messages: messages || getErrorMessages(),\n stripUnknown: true,\n });\n\n return [validated, null];\n } catch (err) {\n if (err instanceof Joi.ValidationError) {\n return [null, transformErrors(err)];\n }\n\n if (err instanceof Error) {\n return [null, err];\n }\n\n return [null, new Error('Unknown validation error occured')];\n }\n}\n\nexport function createSchema<T>(schema: Joi.SchemaMap<T, true>): Joi.ObjectSchema<T> {\n return Joi.object<T>(schema);\n}\n\nexport function extendSchema<T, U extends T>(\n schema: Joi.ObjectSchema<T>,\n appends: Joi.PartialSchemaMap<U>\n): Joi.ObjectSchema<U> {\n return schema.append<U>(appends);\n}\n","const messages: Record<string, string> = {\n 'alternatives.all': '',\n 'alternatives.any': '',\n 'alternatives.match': '',\n 'alternatives.one': '',\n 'alternatives.types': '',\n 'any.custom': '',\n 'any.default': '',\n 'any.failover': '',\n 'any.invalid': '',\n 'any.only': '',\n 'any.ref': '',\n 'any.required': '{{#label}} is required',\n 'any.unknown': '',\n 'array.base': '',\n 'array.excludes': '',\n 'array.includesRequiredBoth': '',\n 'array.includesRequiredKnowns': '',\n 'array.includesRequiredUnknowns': '',\n 'array.includes': '',\n 'array.length': '',\n 'array.max': '',\n 'array.min': '',\n 'array.orderedLength': '',\n 'array.sort': '',\n 'array.sort.mismatching': '',\n 'array.sort.unsupported': '',\n 'array.sparse': '',\n 'array.unique': '',\n 'array.hasKnown': '',\n 'array.hasUnknown': '',\n 'binary.base': '',\n 'binary.length': '',\n 'binary.max': '',\n 'binary.min': '',\n 'boolean.base': '',\n 'date.base': '',\n 'date.format': '',\n 'date.greater': '',\n 'date.less': '',\n 'date.max': '',\n 'date.min': '',\n 'date.strict': '',\n 'function.arity': '',\n 'function.class': '',\n 'function.maxArity': '',\n 'function.minArity': '',\n 'number.base': '{{#label}} should be a number',\n 'number.greater': '',\n 'number.infinity': '',\n 'number.integer': '',\n 'number.less': '',\n 'number.max': '',\n 'number.min': '{{#label}} should be greater than or equal to {{#limit}}',\n 'number.multiple': '',\n 'number.negative': '',\n 'number.port': '',\n 'number.positive': '',\n 'number.precision': '',\n 'number.unsafe': '',\n 'object.unknown': '',\n 'object.and': '',\n 'object.assert': '',\n 'object.base': '',\n 'object.length': '',\n 'object.max': '',\n 'object.min': '',\n 'object.missing': '',\n 'object.nand': '',\n 'object.pattern.match': '',\n 'object.refType': '',\n 'object.regex': '',\n 'object.rename.multiple': '',\n 'object.rename.override': '',\n 'object.schema': '',\n 'object.instance': '',\n 'object.with': '',\n 'object.without': '',\n 'object.xor': '',\n 'object.oxor': '',\n 'string.alphanum': '',\n 'string.base64': '',\n 'string.base': '',\n 'string.creditCard': '',\n 'string.dataUri': '',\n 'string.domain': '',\n 'string.email': '',\n 'string.empty': '{{#label}} is required',\n 'string.guid': '',\n 'string.hexAlign': '',\n 'string.hex': '',\n 'string.hostname': '',\n 'string.ipVersion': '',\n 'string.ip': '',\n 'string.isoDate': '',\n 'string.isoDuration': '',\n 'string.length': '',\n 'string.lowercase': '',\n 'string.max': '',\n 'string.min': '',\n 'string.normalize': '',\n 'string.pattern.base': '{{#label}} is not in the correct format',\n 'string.pattern.name': '',\n 'string.pattern.invert.base': '',\n 'string.pattern.invert.name': '',\n 'string.token': '',\n 'string.trim': '',\n 'string.uppercase': '',\n 'string.uri': '',\n 'string.uriCustomScheme': '',\n 'string.uriRelativeOnly': '',\n 'symbol.base': '',\n 'symbol.map': '',\n};\n\nexport default messages;\n","/* eslint-disable max-statements */\n\nimport type { SerializedError, SerializedErrorable } from '@sqrzro/interfaces';\nimport type Joi from 'joi';\nimport { NextResponse } from 'next/server';\n\nimport ValidationError from './ValidationError';\nimport { validateSchema } from './ValidationService';\n\nfunction serializeError(err: Error): SerializedError {\n return {\n cause: err.cause,\n message: err.message,\n name: err.name,\n stack: err.stack,\n };\n}\n\ninterface SubmitFormArgs<F extends object> {\n formData: F;\n onSuccess?: (model: F) => Promise<void> | void;\n onValidationError?: (error: ValidationError) => void;\n request?: Joi.ObjectSchema<F>;\n}\n\ninterface SubmitFormArgsWithFn<F extends object, M> extends Omit<SubmitFormArgs<F>, 'onSuccess'> {\n fn: (data: F) => Promise<M | null>;\n onSuccess?: (model: M) => Promise<void> | void;\n}\n\nfunction hasFn<F extends object, M>(\n args: SubmitFormArgs<F> | SubmitFormArgsWithFn<F, M>\n): args is SubmitFormArgsWithFn<F, M> {\n return Boolean(Object.prototype.hasOwnProperty.call(args, 'fn'));\n}\n\nexport async function submitForm<F extends object>(\n args: SubmitFormArgs<F>\n): Promise<SerializedErrorable<F>>;\nexport async function submitForm<F extends object, M>(\n args: SubmitFormArgsWithFn<F, M>\n): Promise<SerializedErrorable<M>>;\n\nexport async function submitForm<F extends object, M>(\n args: SubmitFormArgs<F> | SubmitFormArgsWithFn<F, M>\n): Promise<[F, null] | [M, null] | [null, SerializedError]> {\n let data = { ...args.formData };\n\n if (args.request) {\n const [validated, validationError] = await validateSchema<F>(args.formData, args.request);\n\n if (validationError !== null) {\n if (validationError instanceof ValidationError) {\n args.onValidationError?.(validationError);\n }\n\n return [null, serializeError(validationError)];\n }\n\n data = validated;\n }\n\n if (!hasFn(args)) {\n await args.onSuccess?.(data);\n return [data, null];\n }\n\n let model: Awaited<M> | null = null;\n\n try {\n model = await args.fn(data);\n } catch (err: unknown) {\n if (err instanceof ValidationError) {\n args.onValidationError?.(err);\n return [null, serializeError(err)];\n }\n if (err instanceof Error) {\n throw err;\n }\n throw new Error('The function supplied to submitForm encountered an unknown error');\n }\n\n if (!model) {\n throw new Error('NO_MODEL');\n }\n\n await args.onSuccess?.(model);\n return [model, null];\n}\n\nexport async function submitAPIRequest<F extends object, M>(\n args: SubmitFormArgsWithFn<F, M>\n): Promise<[M, null] | [null, NextResponse]> {\n const [response, error] = await submitForm<F, M>(args);\n\n if (error !== null) {\n if (error.name === 'ValidationError') {\n try {\n const errors = JSON.parse(error.message) as Record<string, string>;\n return [null, NextResponse.json(errors, { status: 422 })];\n } catch (err) {\n return [\n null,\n NextResponse.json({ message: 'An unknown error occured' }, { status: 500 }),\n ];\n }\n }\n return [null, NextResponse.json({ message: error.message }, { status: 500 })];\n }\n\n return [response, null];\n}\n","/* eslint-disable @typescript-eslint/no-magic-numbers */\n\nimport Joi from 'joi';\n\nimport { createSchema } from '../forms/ValidationService';\nimport type { MFAFormFields } from './interfaces';\n\nconst MFARequest = createSchema<MFAFormFields>({\n token: Joi.string()\n .pattern(/^[0-9]{6}$/u)\n .required(),\n});\n\nexport default MFARequest;\n","import { createClient } from 'redis';\n\nlet client: ReturnType<typeof createClient> | null = null;\n\nfunction isLocalhost(url: string): boolean {\n return url.includes('localhost') || url.includes('127.0.0.1');\n}\n\nasync function getClient(): Promise<ReturnType<typeof createClient>> {\n if (!process.env.REDIS_URL) {\n throw new Error('REDIS_URL is not defined. Access to the cache is not possible.');\n }\n\n if (client) {\n return client;\n }\n\n client = createClient({\n socket: {\n tls: !isLocalhost(process.env.REDIS_URL),\n },\n url: process.env.REDIS_URL,\n });\n\n await client.connect();\n return client;\n}\n\nexport async function getFromCache(key: string): Promise<string | null> {\n return (await getClient()).get(key);\n}\n\nexport async function setToCache(key: string, value: string): Promise<void> {\n await (await getClient()).set(key, value);\n}\n","import { headers } from 'next/headers';\n\n/**\n * Uses a number of methods to determine the current origin.\n *\n * First, it checks if an `x-origin` header. This will have been set by the `handleMiddleware`\n * function, further up the chain. For more information on how it is being set, see the\n * `middleware` documentation.\n *\n * There are some situations where middleware is not being applied, such as API routes (because the\n * redirection is not necessary, and API routes handle their own authentication). In these cases,\n * this function tries to piece together the origin from the `x-forwarded-proto` and\n * `x-forwarded-host` headers.\n *\n * Finally, if the origin cannot be determined, an error is thrown.\n *\n * @returns The origin of the current request.\n */\nexport async function getOrigin(): Promise<string> {\n const envOrigin = process.env.SZ_ORIGIN;\n\n if (envOrigin) {\n return envOrigin;\n }\n\n const origin = (await headers()).get('x-origin');\n\n if (origin) {\n return origin;\n }\n\n const proto = (await headers()).get('x-forwarded-proto');\n const host = (await headers()).get('x-forwarded-host');\n\n if (proto && host) {\n return `${proto}://${host}`;\n }\n\n throw new Error('No origin could be determined');\n}\n\nexport async function getPathname(): Promise<string> {\n const pathname = (await headers()).get('x-pathname');\n\n if (pathname) {\n return pathname;\n }\n\n throw new Error(\n 'No pathname could be determined. Please make sure middleware is being applied to the current request.'\n );\n}\n\n/**\n * Builds a URL from the current origin and a given pathname. For more information on how the origin\n * is determined, see the `getOrigin` function. This function then just concatenates the origin and\n * the pathname, and performs some cleanup to ensure the URL is valid.\n *\n * @param pathname\n * @returns The URL, with the origin and pathname combined.\n */\nexport async function makeURL(pathname?: string): Promise<string> {\n const origin = await getOrigin();\n\n if (!pathname) {\n return origin;\n }\n\n const isSecure = origin.startsWith('https://');\n\n const protocol = isSecure ? 'https://' : 'http://';\n const originWithoutProtocol = origin.replace(/^https?:\\/\\//u, '');\n\n const cleanURL = `${originWithoutProtocol}/${pathname}`.replace(/\\/+/gu, '/');\n return `${protocol}${cleanURL}`;\n}\n\n/**\n * @deprecated Use `makeURL` instead.\n */\nexport async function getURL(pathname?: string): Promise<string> {\n return makeURL(pathname);\n}\n","import { DrizzlePostgreSQLAdapter } from '@lucia-auth/adapter-drizzle';\nimport { pick } from '@sqrzro/utility';\nimport { Lucia, TimeSpan, generateId } from 'lucia';\nimport { cookies } from 'next/headers';\nimport { NextResponse } from 'next/server';\nimport type { NextRequest } from 'next/server';\nimport { match } from 'path-to-regexp';\n\nimport { getAllowedRoles } from './AuthService';\n\nimport { db } from '../database/DatabaseService';\nimport { authSessionTable, authUserTable } from '../database/schema';\nimport type { Scope } from '../database/schema';\n\nimport { getFromCache, setToCache } from '../cache/CacheService';\nimport { getOrigin } from '../url/URLService';\n\nconst DEFAULT_REDIRECT = '/auth/login';\nconst ID_LENGTH = 16;\n\ntype TimeSpanUnit = 'd' | 'h' | 'm' | 'ms' | 's' | 'w';\n\ninterface ScopeData {\n allowedRoute?: string;\n redirectOnAuth?: string;\n redirectOnUnauth?: string;\n}\n\nexport type ScopeObject = Record<Scope, ScopeData>;\n\ninterface DatabaseSessionAttributes {\n scope: Scope;\n}\n\ninterface DatabaseUserAttributes {\n email: string;\n role: number;\n deletedAt?: Date | null;\n}\n\ndeclare module 'lucia' {\n interface Register {\n Lucia: typeof lucia;\n DatabaseSessionAttributes: DatabaseSessionAttributes;\n DatabaseUserAttributes: DatabaseUserAttributes;\n }\n}\n\nconst DEFAULT_SCOPES: ScopeObject = {\n ANON: {\n allowedRoute: '/auth/(login|password)',\n redirectOnUnauth: DEFAULT_REDIRECT,\n },\n MFA: {\n allowedRoute: '/auth/mfa',\n redirectOnUnauth: '/auth/mfa',\n },\n AUTHED: {\n allowedRoute: '*',\n redirectOnAuth: '/',\n },\n};\n\n/* eslint-disable id-length */\nconst timespanMap: Record<string, TimeSpanUnit> = {\n D: 'd',\n H: 'h',\n M: 'm',\n MS: 'ms',\n S: 's',\n W: 'w',\n};\n/* eslint-enable id-length */\n\nfunction getSessionExpiry(): TimeSpan {\n if (!process.env.AUTH_SESSION_EXPIRY) {\n return new TimeSpan(2, 'w');\n }\n\n const [value, unit] = process.env.AUTH_SESSION_EXPIRY.split(/_/u);\n return new TimeSpan(Number(value), timespanMap[unit]);\n}\n\nconst adapter = new DrizzlePostgreSQLAdapter(db, authSessionTable, authUserTable);\n\nexport const lucia = new Lucia(adapter, {\n getSessionAttributes: (attributes: DatabaseSessionAttributes): DatabaseSessionAttributes => ({\n scope: attributes.scope,\n }),\n getUserAttributes: (attributes: DatabaseUserAttributes): DatabaseUserAttributes => ({\n email: attributes.email,\n role: attributes.role,\n deletedAt: attributes.deletedAt,\n }),\n sessionCookie: {\n attributes: {\n secure: process.env.APP_ENV === 'production',\n },\n name: process.env.AUTH_COOKIE_NAME || 'auth_session',\n },\n sessionExpiresIn: getSessionExpiry(),\n});\n\nexport function generateID<T extends string = string>(prefix = '', length = ID_LENGTH): T {\n return `${prefix ? `${prefix}_` : ''}${generateId(length)}` as T;\n}\n\nexport async function invalidateSession(id: string): Promise<void> {\n const cookie = lucia.createBlankSessionCookie();\n (await cookies()).set(cookie.name, cookie.value, cookie.attributes);\n\n return lucia.invalidateSession(id);\n}\n\nexport async function invalidateUserSessions(id: string): Promise<void> {\n return lucia.invalidateUserSessions(id);\n}\n\nexport async function createUserSession(id: string, scope: Scope = 'ANON'): Promise<boolean> {\n const session = await lucia.createSession(id, { scope });\n const sessionCookie = lucia.createSessionCookie(session.id);\n (await cookies()).set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);\n\n return true;\n}\n\nexport async function getSessionID(): Promise<string | null> {\n return (await cookies()).get(lucia.sessionCookieName)?.value ?? null;\n}\n\nexport async function checkSessionExists(): Promise<boolean> {\n return Boolean(await getSessionID());\n}\n\nfunction checkUserRole(userRole: number, targetRoles?: number[] | number): boolean {\n const targetRolesArray = Array.isArray(targetRoles) ? targetRoles : [targetRoles];\n\n if (targetRolesArray[0]) {\n return targetRolesArray.includes(userRole);\n }\n\n return getAllowedRoles().includes(userRole);\n}\n\nexport async function getSessionUser(roles?: number[] | number): Promise<{\n id: string;\n email: string;\n role: number;\n} | null> {\n const sessionID = await getSessionID();\n\n if (!sessionID) {\n return null;\n }\n\n const { user } = await lucia.validateSession(sessionID);\n\n if (!user || user.deletedAt || !checkUserRole(user.role, roles)) {\n return null;\n }\n\n return pick(user, ['id', 'email', 'role']);\n}\n\nexport function checkRouteAllowed(pathname: string, route?: string): boolean {\n if (!route) {\n return false;\n }\n\n if (route === '*') {\n return true;\n }\n\n return match(route)(pathname) !== false;\n}\n\nexport async function getScopes(): Promise<ScopeObject> {\n const scopes = await getFromCache(`${await getOrigin()}:scopes`);\n return scopes ? (JSON.parse(scopes) as ScopeObject) : DEFAULT_SCOPES;\n}\n\nexport async function getScopeByID(id: Scope): Promise<ScopeData> {\n const scopes = await getScopes();\n return scopes[id];\n}\n\nexport async function setScopes(customScopes?: Partial<ScopeObject>): Promise<void> {\n const scopes = {\n ANON: {\n ...DEFAULT_SCOPES.ANON,\n ...customScopes?.ANON,\n },\n MFA: {\n ...DEFAULT_SCOPES.MFA,\n ...customScopes?.MFA,\n },\n AUTHED: {\n ...DEFAULT_SCOPES.AUTHED,\n ...customScopes?.AUTHED,\n },\n };\n\n return setToCache(`${await getOrigin()}:scopes`, JSON.stringify(scopes));\n}\n\nasync function validateSessionFromID(\n sessionID: string,\n pathname: string\n): Promise<{ redirect: string | null; email: string | null }> {\n const scopes = await getScopes();\n const { session, user } = await lucia.validateSession(sessionID);\n\n const scope =\n scopes[session && getAllowedRoles().includes(user?.role) ? session.scope : 'ANON'];\n\n return {\n email: user?.email || null,\n redirect: checkRouteAllowed(pathname, scope.allowedRoute)\n ? null\n : scope.redirectOnUnauth || DEFAULT_REDIRECT,\n };\n}\n\nexport async function handleSession(\n request: NextRequest,\n customScopes?: Partial<ScopeObject>\n): Promise<NextResponse> {\n const sessionID = request.nextUrl.searchParams.get('id') || '';\n const pathname = request.nextUrl.searchParams.get('pathname') || '/';\n\n await setScopes(customScopes);\n\n return NextResponse.json(await validateSessionFromID(sessionID, pathname));\n}\n","import type { Errorable } from '@sqrzro/interfaces';\nimport { and, eq, isNotNull, isNull } from 'drizzle-orm';\nimport { authenticator } from 'otplib';\nimport qrcode from 'qrcode';\n\nimport { db } from '../database/DatabaseService';\nimport { authMFATable, authUserTable } from '../database/schema';\n\nimport { submitForm } from '../forms/FormService';\nimport ValidationError from '../forms/ValidationError';\n\nimport MFARequest from './MFARequest';\nimport {\n createUserSession,\n generateID,\n getSessionUser,\n invalidateUserSessions,\n} from './SessionService';\nimport type { MFAFormFields, UserObject } from './interfaces';\n\nexport function checkMFAEnabled(): boolean {\n return process.env.AUTH_MFA_ENABLED !== 'false';\n}\n\nexport async function generateMFA(name: string, email?: string): Promise<string | null> {\n if (!checkMFAEnabled()) {\n throw new Error('MFA is not enabled. Cannot generate MFA secret.');\n }\n\n if (!email) {\n return null;\n }\n\n const [user] = await db\n .select()\n .from(authUserTable)\n .where(eq(authUserTable.email, email))\n .limit(1);\n\n if (!user) {\n return null;\n }\n\n const secret = authenticator.generateSecret();\n const otpauth = authenticator.keyuri(email, name, secret);\n\n // Delete all the unverified MFA entries for this user\n\n await db\n .delete(authMFATable)\n .where(and(eq(authMFATable.userId, user.id), isNull(authMFATable.verifiedAt)));\n\n // Add the new MFA entry\n\n await db.insert(authMFATable).values({\n id: generateID(),\n name: 'Default',\n secret,\n userId: user.id,\n });\n\n return new Promise((resolve, reject) => {\n qrcode.toDataURL(\n otpauth,\n { rendererOpts: { quality: 1 }, margin: 0, scale: 2 },\n (err, data) => {\n if (err) {\n reject(err);\n }\n resolve(data);\n }\n );\n });\n}\n\nexport async function checkUserHasMFA(user: UserObject): Promise<boolean> {\n if (!checkMFAEnabled()) {\n return false;\n }\n\n const [mfa] = await db\n .select()\n .from(authMFATable)\n .where(and(eq(authMFATable.userId, user.id), isNotNull(authMFATable.verifiedAt)))\n .limit(1);\n\n return Boolean(mfa);\n}\n\nasync function markAsVerified(userID: string): Promise<void> {\n if (!checkMFAEnabled()) {\n return;\n }\n\n await db\n .update(authMFATable)\n .set({ verifiedAt: new Date() })\n .where(eq(authMFATable.userId, userID));\n}\n\nasync function validateUserToken(userID: string, token: string): Promise<boolean> {\n if (!checkMFAEnabled()) {\n return false;\n }\n\n const [mfa] = await db\n .select()\n .from(authMFATable)\n .where(eq(authMFATable.userId, userID))\n .limit(1);\n\n if (!mfa) {\n return false;\n }\n\n return authenticator.check(token, mfa.secret);\n}\n\nexport async function deleteMFA(userID: string): Promise<boolean> {\n const promises = [\n db.delete(authMFATable).where(eq(authMFATable.userId, userID)),\n invalidateUserSessions(userID),\n ];\n\n await Promise.all(promises);\n return true;\n}\n\nexport async function handleMFA(data: MFAFormFields): Promise<boolean> {\n if (!checkMFAEnabled()) {\n throw new ValidationError({ token: 'MFA is not enabled' });\n }\n\n const user = await getSessionUser();\n\n if (!user) {\n throw new ValidationError({ token: 'User not found' });\n }\n\n const isValid = await validateUserToken(user.id, data.token);\n\n if (!isValid) {\n throw new ValidationError({ token: 'Invalid token' });\n }\n\n await markAsVerified(user.id);\n return createUserSession(user.id, 'AUTHED');\n}\n\nexport async function handleMFAForm(formData: MFAFormFields): Promise<Errorable<boolean>> {\n if (!checkMFAEnabled()) {\n return [null, new Error('MFA is not enabled')];\n }\n\n const response = await submitForm<MFAFormFields, boolean>({\n fn: handleMFA,\n formData,\n request: MFARequest,\n });\n\n return response;\n}\n","import bcrypt from 'bcryptjs';\n\nconst PW_SALT_ROUNDS = 12;\n\ntype PasswordRule = 'lower' | 'min' | 'number' | 'symbol' | 'upper';\n\nexport type PasswordRuleObject = Partial<Record<PasswordRule, number>>;\ntype PasswordValidityObject = Record<PasswordRule, boolean>;\n\nconst PASSWORD_RULES: PasswordRuleObject = {\n min: 8,\n upper: 1,\n lower: 1,\n number: 1,\n symbol: 1,\n};\n\nfunction checkPasswordMin(password: string, value: number): boolean {\n return password.length >= value;\n}\n\nfunction checkPasswordUpper(password: string, value: number): boolean {\n return password.replace(/[^A-Z]/gu, '').length >= value;\n}\n\nfunction checkPasswordLower(password: string, value: number): boolean {\n return password.replace(/[^a-z]/gu, '').length >= value;\n}\n\nfunction checkPasswordNumber(password: string, value: number): boolean {\n return password.replace(/[^0-9]/gu, '').length >= value;\n}\n\nfunction checkPasswordSymbol(password: string, value: number): boolean {\n return password.replace(/[^$]/gu, '').length >= value;\n}\n\nconst PASSWORD_FUNCTIONS: Record<PasswordRule, (password: string, value: number) => boolean> = {\n min: checkPasswordMin,\n upper: checkPasswordUpper,\n lower: checkPasswordLower,\n number: checkPasswordNumber,\n symbol: checkPasswordSymbol,\n};\n\nexport async function hashPassword(password: string): Promise<string> {\n const hash = await bcrypt.hash(password, PW_SALT_ROUNDS);\n return hash;\n}\n\nexport async function verifyPassword(data?: string, encrypted?: string): Promise<boolean> {\n if (!data || !encrypted) {\n return false;\n }\n\n const verified = await bcrypt.compare(data, encrypted);\n return verified;\n}\n\nexport async function getPasswordComplexity(\n password: string,\n rules: Partial<PasswordRuleObject> = PASSWORD_RULES\n): Promise<Partial<PasswordValidityObject>> {\n const entries = Object.entries(rules) as [PasswordRule, number][];\n\n const validity = entries.reduce<Partial<PasswordValidityObject>>((acc, [rule, value]) => {\n acc[rule] = PASSWORD_FUNCTIONS[rule](password, value);\n return acc;\n }, {});\n\n return Promise.resolve(validity);\n}\n\nexport async function checkPasswordComplexity(\n password: string,\n rules: Partial<PasswordRuleObject> = PASSWORD_RULES\n): Promise<Partial<boolean>> {\n const validity = await getPasswordComplexity(password, rules);\n return Promise.resolve(Object.values(validity).every(Boolean));\n}\n","/* eslint-disable @typescript-eslint/no-magic-numbers */\n\nimport Joi from 'joi';\n\nimport { createSchema } from '../forms/ValidationService';\nimport type { LoginFormFields } from './interfaces';\n\nconst LoginRequest = createSchema<LoginFormFields>({\n email: Joi.string().email({ minDomainSegments: 2, tlds: false }).required(),\n password: Joi.string().min(8).required(),\n});\n\nexport default LoginRequest;\n","/* eslint-disable @typescript-eslint/no-magic-numbers */\n\nimport Joi from 'joi';\n\nimport { createSchema } from '../forms/ValidationService';\nimport type { PasswordFormFields } from './interfaces';\n\nconst PasswordRequest = createSchema<PasswordFormFields>({\n email: Joi.string().max(60).email({ minDomainSegments: 2, tlds: false }).required().messages({\n 'any.required': 'Please provide your email address, so we can send you a reset link',\n 'string.empty': 'Please provide your email address, so we can send you a reset link',\n 'string.email': 'Please make sure your email address is valid',\n 'string.max': 'Please make sure your email address is valid',\n }),\n});\n\nexport default PasswordRequest;\n","import Joi from 'joi';\n\nimport { checkPasswordComplexity } from './PasswordService';\nimport type { PasswordRuleObject } from './PasswordService';\nimport type { ValidationCustomHelpers } from '../forms/ValidationService';\n\nimport { createSchema } from '../forms/ValidationService';\nimport type { PasswordResetWithTokenFormFields } from './interfaces';\n\nconst passwordComplexity: PasswordRuleObject = {\n lower: 1,\n min: 8,\n number: 1,\n upper: 1,\n};\n\nasync function passwordIsComplex(\n value: string,\n helpers: ValidationCustomHelpers\n): Promise<Error | string> {\n if (!(await checkPasswordComplexity(value, passwordComplexity))) {\n return helpers.message({\n external:\n 'Please make sure your password is complex enough, to keep your account secure',\n });\n }\n return value;\n}\n\nconst PasswordResetWithTokenRequest = createSchema<PasswordResetWithTokenFormFields>({\n password: Joi.string().external(passwordIsComplex).required().messages({\n 'any.required': 'Please provide your new password',\n 'string.empty': 'Please provide your new password',\n }),\n token: Joi.string().pattern(/[a-z0-9]{40}/u),\n});\n\nexport default PasswordResetWithTokenRequest;\n","import type { Errorable } from '@sqrzro/interfaces';\nimport { and, eq, inArray, isNull, lte } from 'drizzle-orm';\n\nimport { db } from '../database/DatabaseService';\nimport { authResetTable, authUserTable } from '../database/schema';\n\nimport { submitForm } from '../forms/FormService';\nimport ValidationError from '../forms/ValidationError';\n\nimport { checkMFAEnabled } from './MFAService';\nimport { hashPassword, verifyPassword } from './PasswordService';\nimport {\n createUserSession,\n generateID,\n getScopeByID,\n getSessionID,\n invalidateSession,\n invalidateUserSessions,\n} from './SessionService';\n\nimport LoginRequest from './LoginRequest';\nimport PasswordRequest from './PasswordRequest';\nimport PasswordResetWithTokenRequest from './PasswordResetWithTokenRequest';\n\nimport type {\n LoginFormFields,\n PasswordFormFields,\n PasswordResetWithTokenFormFields,\n UserObject,\n} from './interfaces';\n\nconst RESET_TOKEN_LENGTH = 40;\n\n// Set expiry to 1 hour (in ms)\nconst RESET_TOKEN_EXPIRY = 3600000;\n\nexport async function handleLogout(): Promise<void> {\n const id = await getSessionID();\n\n if (id) {\n await invalidateSession(id);\n }\n}\n\ninterface LoginUserArgs {\n email: string;\n password: string;\n role?: number;\n token?: string;\n}\n\nexport function getAllowedRoles(): number[] {\n const role = process.env.AUTH_ROLE;\n\n if (!role) {\n throw new Error('AUTH_ROLE is not defined. Authentication will not be possible.');\n }\n\n return [Number(role)];\n}\n\nexport function getMaximumRole(): number {\n const roles = getAllowedRoles();\n return Math.max(...roles);\n}\n\nasync function handleUserSession(userID: string): Promise<string | null> {\n await createUserSession(userID, checkMFAEnabled() ? 'MFA' : 'AUTHED');\n\n const scope = await getScopeByID('AUTHED');\n return scope?.redirectOnAuth || null;\n}\n\nexport async function getUserByEmail(email: string, role?: number): Promise<UserObject | null> {\n const conditions = [eq(authUserTable.email, email), isNull(authUserTable.deletedAt)];\n\n if (role) {\n conditions.push(eq(authUserTable.role, role));\n } else {\n conditions.push(lte(authUserTable.role, getMaximumRole()));\n }\n\n const [user] = await db\n .select()\n .from(authUserTable)\n .where(and(...conditions))\n .limit(1);\n\n return user;\n}\n\nasync function loginUser({ email, password }: LoginUserArgs): Promise<string> {\n if (!process.env.AUTH_ROLE) {\n throw new Error('AUTH_ROLE is not defined. Authentication will not be possible.');\n }\n\n const user = await getUserByEmail(email, Number(process.env.AUTH_ROLE));\n\n if (!user?.password || !(await verifyPassword(password, user.password))) {\n throw new ValidationError({ email: '', password: '' });\n }\n\n const session = await handleUserSession(user.id);\n\n if (!session) {\n throw new ValidationError({ email: '', password: '' });\n }\n\n return session;\n}\n\nexport async function handleLoginForm(\n formData: LoginFormFields,\n onSuccess?: () => Promise<void>\n): Promise<Errorable<string>> {\n const response = await submitForm<LoginFormFields, string>({\n fn: loginUser,\n formData,\n onSuccess: async () => {\n await onSuccess?.();\n },\n request: LoginRequest,\n });\n\n return response;\n}\n\ninterface RegisterUserArgs {\n email: string;\n password?: string;\n role?: number;\n}\n\nexport async function registerUser({\n email,\n password,\n role,\n}: RegisterUserArgs): Promise<UserObject | null> {\n const hash = password ? await hashPassword(password) : null;\n\n const [user] = await db\n .insert(authUserTable)\n .values({ id: generateID(), email, password: hash, role })\n .returning();\n\n return user;\n}\n\nasync function updateDeletedAt(\n email: string,\n role: number,\n deletedAt: Date | null\n): Promise<boolean> {\n const [user] = await db\n .select()\n .from(authUserTable)\n .where(and(eq(authUserTable.email, email), eq(authUserTable.role, role)))\n .limit(1);\n\n if (!user) {\n return false;\n }\n\n await db.update(authUserTable).set({ deletedAt }).where(eq(authUserTable.id, user.id));\n\n return true;\n}\n\nexport async function deleteUser(email: string, role: number): Promise<boolean> {\n return updateDeletedAt(email, role, new Date());\n}\n\nexport async function undeleteUser(email: string, role: number): Promise<boolean> {\n return updateDeletedAt(email, role, null);\n}\n\nasync function createPasswordResetToken(email: string): Promise<string | null> {\n const user = await getUserByEmail(email);\n\n if (!user) {\n return null;\n }\n\n await db.delete(authResetTable).where(eq(authResetTable.userId, user.id));\n\n const id = generateID('', RESET_TOKEN_LENGTH);\n\n await db.insert(authResetTable).values({\n id,\n userId: user.id,\n expiresAt: new Date(new Date().getTime() + RESET_TOKEN_EXPIRY),\n });\n\n return id;\n}\n\nexport async function handlePasswordForm(\n formData: PasswordFormFields,\n mailFn: (email: string, token: string) => Promise<boolean>\n): Promise<Errorable<boolean>> {\n async function mutateFn(data: PasswordFormFields): Promise<boolean> {\n const token = await createPasswordResetToken(data.email);\n\n if (!token) {\n // Return true, even though the email doesn't exist (to prevent user enumeration)\n return true;\n }\n\n return mailFn(data.email, token);\n }\n\n const response = await submitForm<PasswordFormFields, boolean>({\n fn: mutateFn,\n formData,\n request: PasswordRequest,\n });\n\n return response;\n}\n\nasync function validatePasswordResetToken(token: string, password: string): Promise<string> {\n const [result] = await db\n .select()\n .from(authResetTable)\n .where(eq(authResetTable.id, token))\n .limit(1);\n\n if (!result) {\n throw new Error('PASSWORD_RESET_TOKEN_NOT_FOUND');\n }\n\n await db.delete(authResetTable).where(eq(authResetTable.id, token));\n\n if (result.expiresAt < new Date()) {\n throw new Error('PASSWORD_RESET_TOKEN_EXPIRED');\n }\n\n await invalidateUserSessions(result.userId);\n\n await db\n .update(authUserTable)\n .set({ password: await hashPassword(password) })\n .where(\n and(eq(authUserTable.id, result.userId), inArray(authUserTable.role, getAllowedRoles()))\n );\n\n return result.userId;\n}\n\nexport async function handlePasswordResetWithTokenForm(\n formData: PasswordResetWithTokenFormFields,\n onSuccess?: (model: string) => Promise<void>\n): Promise<Errorable<string>> {\n async function mutateFn(data: PasswordResetWithTokenFormFields): Promise<string> {\n const userID = await validatePasswordResetToken(data.token, data.password);\n const session = await handleUserSession(userID);\n\n if (!session) {\n throw new Error('COULD_NOT_CREATE_SESSION');\n }\n\n return session;\n }\n\n const response = await submitForm({\n fn: mutateFn,\n formData,\n onSuccess,\n request: PasswordResetWithTokenRequest,\n });\n\n return response;\n}\n","import type { NextRequest } from 'next/server';\nimport { eq } from 'drizzle-orm';\n\nimport { db } from '../database/DatabaseService';\nimport { authClientTable } from '../database/schema';\nimport type { AuthClient } from '../database/schema';\n\nimport { hashPassword, verifyPassword } from './PasswordService';\nimport { generateID } from './SessionService';\n\nconst ID_LENGTH = 16;\nconst SECRET_LENGTH = 64;\n\nexport async function getClientByID(id: string): Promise<AuthClient | null> {\n const [client] = await db\n .select()\n .from(authClientTable)\n .where(eq(authClientTable.id, id))\n .limit(1);\n\n return client;\n}\n\ninterface RegisterClientArgs {\n alias: string;\n id?: string;\n secret?: string;\n}\n\nexport async function registerClient({\n alias,\n id,\n secret,\n}: RegisterClientArgs): Promise<AuthClient | null> {\n const [client] = await db\n .insert(authClientTable)\n .values({\n alias,\n id: id || generateID('', ID_LENGTH),\n secret: await hashPassword(secret || generateID('', SECRET_LENGTH)),\n })\n .returning();\n\n return client;\n}\n\nexport async function handleClientAuth(request: NextRequest): Promise<AuthClient | null> {\n const { headers } = request;\n const header = headers.get('authorization');\n\n if (!header) {\n return null;\n }\n\n const auth = Buffer.from(header.replace('Basic ', ''), 'base64')\n .toString('utf-8')\n .replace(/:$/u, '');\n\n const [id, ...secret] = auth.split('-');\n\n const [client] = await db\n .select()\n .from(authClientTable)\n .where(eq(authClientTable.id, id))\n .limit(1);\n\n if (!client) {\n return null;\n }\n\n const isVerified = await verifyPassword(secret.join(''), client.secret);\n return isVerified ? client : null;\n}\n"]}
1
+ {"version":3,"sources":["../../src/database/DatabaseService.ts","../../src/database/schema.ts","../../src/forms/ValidationError.ts","../../src/forms/lang.ts","../../src/forms/ValidationService.ts","../../src/forms/FormService.ts","../../src/auth/MFARequest.ts","../../src/cache/CacheService.ts","../../src/url/URLService.ts","../../src/auth/SessionService.ts","../../src/auth/MFAService.ts","../../src/auth/PasswordService.ts","../../src/auth/LoginRequest.ts","../../src/auth/PasswordRequest.ts","../../src/auth/PasswordResetWithTokenRequest.ts","../../src/auth/AuthService.ts","../../src/auth/ClientService.ts"],"names":["createSingleton","drizzle","postgres","db","DEFAULT_ROLE","mfaType","pgEnum","scope","authSchema","pgSchema","authUserTable","text","integer","timestamp","table","uniqueIndex","authSessionTable","authResetTable","authMFATable","authClientTable","ValidationError","messages","ValidationError_default","lang_default","getErrorMessages","acc","key","value","transformErrors","error","cur","validateSchema","formData","validation","err","Joi","createSchema","schema","serializeError","hasFn","args","submitForm","data","validated","validationError","model","MFARequest","MFARequest_default","client","isLocalhost","url","getClient","createClient","getFromCache","setToCache","getOrigin","envOrigin","origin","headers","proto","host","DEFAULT_REDIRECT","ID_LENGTH","DEFAULT_SCOPES","timespanMap","getSessionExpiry","TimeSpan","unit","adapter","DrizzlePostgreSQLAdapter","lucia","Lucia","attributes","generateID","prefix","length","generateId","invalidateSession","id","cookie","cookies","invalidateUserSessions","createUserSession","session","sessionCookie","getSessionID","checkSessionExists","checkUserRole","userRole","targetRoles","targetRolesArray","getAllowedRoles","getSessionUser","roles","sessionID","user","pick","checkRouteAllowed","pathname","route","match","getScopes","scopes","getScopeByID","setScopes","customScopes","validateSessionFromID","handleSession","request","NextResponse","checkMFAEnabled","generateMFA","name","email","eq","secret","authenticator","otpauth","and","isNull","resolve","reject","qrcode","checkUserHasMFA","mfa","isNotNull","markAsVerified","userID","validateUserToken","token","deleteMFA","promises","handleMFA","handleMFAForm","PW_SALT_ROUNDS","PASSWORD_RULES","checkPasswordMin","password","checkPasswordUpper","checkPasswordLower","checkPasswordNumber","checkPasswordSymbol","PASSWORD_FUNCTIONS","hashPassword","bcrypt","verifyPassword","encrypted","getPasswordComplexity","rules","validity","rule","checkPasswordComplexity","LoginRequest","LoginRequest_default","PasswordRequest","PasswordRequest_default","passwordComplexity","passwordIsComplex","helpers","PasswordResetWithTokenRequest","PasswordResetWithTokenRequest_default","RESET_TOKEN_LENGTH","RESET_TOKEN_EXPIRY","handleLogout","role","getMaximumRole","handleUserSession","getUserByEmail","conditions","lte","loginUser","handleLoginForm","onSuccess","registerUser","hash","updateDeletedAt","deletedAt","deleteUser","undeleteUser","createPasswordResetToken","handlePasswordForm","mailFn","mutateFn","validatePasswordResetToken","result","inArray","handlePasswordResetWithTokenForm","SECRET_LENGTH","getClientByID","registerClient","alias","handleClientAuth","header","auth"],"mappings":"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","file":"index.js","sourcesContent":["import { drizzle } from 'drizzle-orm/postgres-js';\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js';\nimport postgres from 'postgres';\n\ndeclare global {\n var szdb: ReturnType<typeof createSingleton> | undefined; // eslint-disable-line no-var, vars-on-top\n}\n\nfunction createSingleton(): PostgresJsDatabase {\n if (!process.env.DATABASE_URL) {\n throw new Error('DATABASE_URL is not defined');\n }\n return drizzle(postgres(process.env.DATABASE_URL, { prepare: false }));\n}\n\nexport const db = globalThis.szdb ?? createSingleton();\n\nif (!process.env.VERCEL_ENV) {\n globalThis.szdb = db;\n}\n","/* istanbul ignore file */\n\nimport { integer, pgEnum, pgSchema, text, timestamp, uniqueIndex } from 'drizzle-orm/pg-core';\n\nconst DEFAULT_ROLE = 10;\n\nexport const mfaType = pgEnum('mfaType', ['TOTP', 'HARDWARE']);\nexport const scope = pgEnum('scope', ['ANON', 'MFA', 'AUTHED']);\n\nexport type Scope = (typeof scope.enumValues)[number];\n\nexport const authSchema = pgSchema('auth');\n\nexport const authUserTable = authSchema.table(\n 'user_credentials',\n {\n id: text('id').primaryKey(),\n email: text('email').notNull(),\n password: text('password'),\n role: integer('role').notNull().default(DEFAULT_ROLE),\n deletedAt: timestamp('deletedAt'),\n },\n (table) => ({\n unique: uniqueIndex().on(table.email, table.role),\n })\n);\n\nexport type AuthUser = typeof authUserTable.$inferSelect;\n\nexport const authSessionTable = authSchema.table('sessions', {\n id: text('id').primaryKey(),\n userId: text('userId')\n .notNull()\n .references(() => authUserTable.id, { onDelete: 'cascade' }),\n scope: scope('scope').notNull().default('ANON'),\n expiresAt: timestamp('expiresAt').notNull(),\n});\n\nexport type AuthSession = typeof authSessionTable.$inferSelect;\n\nexport const authResetTable = authSchema.table('resets', {\n id: text('id').primaryKey(),\n userId: text('userId')\n .notNull()\n .references(() => authUserTable.id, { onDelete: 'cascade' }),\n expiresAt: timestamp('expiresAt').notNull(),\n});\n\nexport type AuthReset = typeof authResetTable.$inferSelect;\n\nexport const authMFATable = authSchema.table('mfas', {\n id: text('id').primaryKey(),\n name: text('name').notNull(),\n userId: text('userId')\n .notNull()\n .references(() => authUserTable.id, { onDelete: 'cascade' }),\n type: mfaType('type').notNull().default('TOTP'),\n secret: text('secret').notNull(),\n verifiedAt: timestamp('verifiedAt'),\n});\n\nexport type AuthMFA = typeof authMFATable.$inferSelect;\n\nexport const authClientTable = authSchema.table('client_credentials', {\n id: text('id').primaryKey(),\n alias: text('alias').notNull().unique(),\n secret: text('secret').notNull().unique(),\n});\n\nexport type AuthClient = typeof authClientTable.$inferSelect;\n","class ValidationError extends Error {\n public messages: Record<string, string>;\n\n public constructor(messages: Record<string, string>) {\n super(JSON.stringify(messages));\n\n this.messages = messages;\n this.name = 'ValidationError';\n }\n}\n\nexport default ValidationError;\n","const messages: Record<string, string> = {\n 'alternatives.all': '',\n 'alternatives.any': '',\n 'alternatives.match': '',\n 'alternatives.one': '',\n 'alternatives.types': '',\n 'any.custom': '',\n 'any.default': '',\n 'any.failover': '',\n 'any.invalid': '',\n 'any.only': '',\n 'any.ref': '',\n 'any.required': '{{#label}} is required',\n 'any.unknown': '',\n 'array.base': '',\n 'array.excludes': '',\n 'array.includesRequiredBoth': '',\n 'array.includesRequiredKnowns': '',\n 'array.includesRequiredUnknowns': '',\n 'array.includes': '',\n 'array.length': '',\n 'array.max': '',\n 'array.min': '',\n 'array.orderedLength': '',\n 'array.sort': '',\n 'array.sort.mismatching': '',\n 'array.sort.unsupported': '',\n 'array.sparse': '',\n 'array.unique': '',\n 'array.hasKnown': '',\n 'array.hasUnknown': '',\n 'binary.base': '',\n 'binary.length': '',\n 'binary.max': '',\n 'binary.min': '',\n 'boolean.base': '',\n 'date.base': '',\n 'date.format': '',\n 'date.greater': '',\n 'date.less': '',\n 'date.max': '',\n 'date.min': '',\n 'date.strict': '',\n 'function.arity': '',\n 'function.class': '',\n 'function.maxArity': '',\n 'function.minArity': '',\n 'number.base': '{{#label}} should be a number',\n 'number.greater': '',\n 'number.infinity': '',\n 'number.integer': '',\n 'number.less': '',\n 'number.max': '',\n 'number.min': '{{#label}} should be greater than or equal to {{#limit}}',\n 'number.multiple': '',\n 'number.negative': '',\n 'number.port': '',\n 'number.positive': '',\n 'number.precision': '',\n 'number.unsafe': '',\n 'object.unknown': '',\n 'object.and': '',\n 'object.assert': '',\n 'object.base': '',\n 'object.length': '',\n 'object.max': '',\n 'object.min': '',\n 'object.missing': '',\n 'object.nand': '',\n 'object.pattern.match': '',\n 'object.refType': '',\n 'object.regex': '',\n 'object.rename.multiple': '',\n 'object.rename.override': '',\n 'object.schema': '',\n 'object.instance': '',\n 'object.with': '',\n 'object.without': '',\n 'object.xor': '',\n 'object.oxor': '',\n 'string.alphanum': '',\n 'string.base64': '',\n 'string.base': '',\n 'string.creditCard': '',\n 'string.dataUri': '',\n 'string.domain': '',\n 'string.email': '',\n 'string.empty': '{{#label}} is required',\n 'string.guid': '',\n 'string.hexAlign': '',\n 'string.hex': '',\n 'string.hostname': '',\n 'string.ipVersion': '',\n 'string.ip': '',\n 'string.isoDate': '',\n 'string.isoDuration': '',\n 'string.length': '',\n 'string.lowercase': '',\n 'string.max': '',\n 'string.min': '',\n 'string.normalize': '',\n 'string.pattern.base': '{{#label}} is not in the correct format',\n 'string.pattern.name': '',\n 'string.pattern.invert.base': '',\n 'string.pattern.invert.name': '',\n 'string.token': '',\n 'string.trim': '',\n 'string.uppercase': '',\n 'string.uri': '',\n 'string.uriCustomScheme': '',\n 'string.uriRelativeOnly': '',\n 'symbol.base': '',\n 'symbol.map': '',\n};\n\nexport default messages;\n","import type { Errorable } from '@sqrzro/interfaces';\nimport Joi from 'joi';\n\nimport lang from './lang';\nimport ValidationError from './ValidationError';\n\nexport function validate(): typeof Joi {\n return Joi;\n}\n\nexport type ValidationCustomHelpers<V = any> = Joi.CustomHelpers<V>; // eslint-disable-line @typescript-eslint/no-explicit-any\nexport type ValidationExternalHelpers<V = any> = Joi.ExternalHelpers<V>; // eslint-disable-line @typescript-eslint/no-explicit-any\nexport type ValidationErrorReport = Joi.ErrorReport;\n\nexport function getDefaultErrorMessages(): Record<string, string> {\n return lang;\n}\n\nfunction getErrorMessages(): Record<string, string> {\n return Object.entries(lang).reduce((acc, [key, value]) => {\n if (!value) {\n return acc;\n }\n return {\n ...acc,\n [key]: value,\n };\n }, {});\n}\n\nfunction transformErrors(error: Joi.ValidationError): ValidationError {\n const messages = error.details.reduce(\n (acc, cur) => ({\n ...acc,\n [cur.path.join('.')]: cur.message.replace(/\"/gu, ''),\n }),\n {}\n );\n return new ValidationError(messages);\n}\n\n/**\n * This function takes FormData and a schema. It then attempts to transform the FormData into an\n * object that matches `T`. This is because the FormData object is not typed and we want to be able\n * to validate it properly typed.\n *\n * Once transformed, the object is validated against the schema. This will result in either a\n * properly typed `T` object or an array of validation errors.\n * @param formData\n * @param validation\n * @returns\n */\nexport async function validateSchema<T>(\n formData: Partial<T>,\n validation: Joi.ObjectSchema<T>,\n messages?: Record<string, string>\n): Promise<Errorable<T>> {\n try {\n const validated = await validation.validateAsync(formData, {\n abortEarly: false,\n messages: messages || getErrorMessages(),\n stripUnknown: true,\n });\n\n return [validated, null];\n } catch (err) {\n if (err instanceof Joi.ValidationError) {\n return [null, transformErrors(err)];\n }\n\n if (err instanceof Error) {\n return [null, err];\n }\n\n return [null, new Error('Unknown validation error occured')];\n }\n}\n\nexport function createSchema<T>(schema: Joi.SchemaMap<T, true>): Joi.ObjectSchema<T> {\n return Joi.object<T>(schema);\n}\n\nexport function extendSchema<T, U extends T>(\n schema: Joi.ObjectSchema<T>,\n appends: Joi.PartialSchemaMap<U>\n): Joi.ObjectSchema<U> {\n return schema.append<U>(appends);\n}\n","/* eslint-disable max-statements */\n\nimport type { SerializedError, SerializedErrorable } from '@sqrzro/interfaces';\nimport type Joi from 'joi';\nimport { NextResponse } from 'next/server';\n\nimport ValidationError from './ValidationError';\nimport { validateSchema } from './ValidationService';\n\nfunction serializeError(err: Error): SerializedError {\n return {\n cause: err.cause,\n message: err.message,\n name: err.name,\n stack: err.stack,\n };\n}\n\ninterface SubmitFormArgs<F extends object> {\n formData: F;\n onSuccess?: (model: F) => Promise<void> | void;\n onValidationError?: (error: ValidationError) => void;\n request?: Joi.ObjectSchema<F>;\n}\n\ninterface SubmitFormArgsWithFn<F extends object, M> extends Omit<SubmitFormArgs<F>, 'onSuccess'> {\n fn: (data: F) => Promise<M | null>;\n onSuccess?: (model: M) => Promise<void> | void;\n}\n\nfunction hasFn<F extends object, M>(\n args: SubmitFormArgs<F> | SubmitFormArgsWithFn<F, M>\n): args is SubmitFormArgsWithFn<F, M> {\n return Boolean(Object.prototype.hasOwnProperty.call(args, 'fn'));\n}\n\nexport async function submitForm<F extends object>(\n args: SubmitFormArgs<F>\n): Promise<SerializedErrorable<F>>;\nexport async function submitForm<F extends object, M>(\n args: SubmitFormArgsWithFn<F, M>\n): Promise<SerializedErrorable<M>>;\n\nexport async function submitForm<F extends object, M>(\n args: SubmitFormArgs<F> | SubmitFormArgsWithFn<F, M>\n): Promise<[F, null] | [M, null] | [null, SerializedError]> {\n let data = { ...args.formData };\n\n if (args.request) {\n const [validated, validationError] = await validateSchema<F>(args.formData, args.request);\n\n if (validationError !== null) {\n if (validationError instanceof ValidationError) {\n args.onValidationError?.(validationError);\n }\n\n return [null, serializeError(validationError)];\n }\n\n data = validated;\n }\n\n if (!hasFn(args)) {\n await args.onSuccess?.(data);\n return [data, null];\n }\n\n let model: Awaited<M> | null = null;\n\n try {\n model = await args.fn(data);\n } catch (err: unknown) {\n if (err instanceof ValidationError) {\n args.onValidationError?.(err);\n return [null, serializeError(err)];\n }\n if (err instanceof Error) {\n throw err;\n }\n throw new Error('The function supplied to submitForm encountered an unknown error');\n }\n\n if (!model) {\n throw new Error('NO_MODEL');\n }\n\n await args.onSuccess?.(model);\n return [model, null];\n}\n\nexport async function submitAPIRequest<F extends object, M>(\n args: SubmitFormArgsWithFn<F, M>\n): Promise<[M, null] | [null, NextResponse]> {\n const [response, error] = await submitForm<F, M>(args);\n\n if (error !== null) {\n if (error.name === 'ValidationError') {\n try {\n const errors = JSON.parse(error.message) as Record<string, string>;\n return [null, NextResponse.json(errors, { status: 422 })];\n } catch (err) {\n return [\n null,\n NextResponse.json({ message: 'An unknown error occured' }, { status: 500 }),\n ];\n }\n }\n return [null, NextResponse.json({ message: error.message }, { status: 500 })];\n }\n\n return [response, null];\n}\n","/* eslint-disable @typescript-eslint/no-magic-numbers */\n\nimport Joi from 'joi';\n\nimport { createSchema } from '../forms/ValidationService';\nimport type { MFAFormFields } from './interfaces';\n\nconst MFARequest = createSchema<MFAFormFields>({\n token: Joi.string()\n .pattern(/^[0-9]{6}$/u)\n .required(),\n});\n\nexport default MFARequest;\n","import { createClient } from 'redis';\n\nlet client: ReturnType<typeof createClient> | null = null;\n\nfunction isLocalhost(url: string): boolean {\n return url.includes('localhost') || url.includes('127.0.0.1');\n}\n\nasync function getClient(): Promise<ReturnType<typeof createClient>> {\n if (!process.env.REDIS_URL) {\n throw new Error('REDIS_URL is not defined. Access to the cache is not possible.');\n }\n\n if (client) {\n return client;\n }\n\n client = createClient({\n socket: {\n tls: !isLocalhost(process.env.REDIS_URL),\n },\n url: process.env.REDIS_URL,\n });\n\n await client.connect();\n return client;\n}\n\nexport async function getFromCache(key: string): Promise<string | null> {\n return (await getClient()).get(key);\n}\n\nexport async function setToCache(key: string, value: string): Promise<void> {\n await (await getClient()).set(key, value);\n}\n","import { headers } from 'next/headers';\n\n/**\n * Uses a number of methods to determine the current origin.\n *\n * First, it checks if an `x-origin` header. This will have been set by the `handleMiddleware`\n * function, further up the chain. For more information on how it is being set, see the\n * `middleware` documentation.\n *\n * There are some situations where middleware is not being applied, such as API routes (because the\n * redirection is not necessary, and API routes handle their own authentication). In these cases,\n * this function tries to piece together the origin from the `x-forwarded-proto` and\n * `x-forwarded-host` headers.\n *\n * Finally, if the origin cannot be determined, an error is thrown.\n *\n * @returns The origin of the current request.\n */\nexport async function getOrigin(): Promise<string> {\n const envOrigin = process.env.SZ_ORIGIN;\n\n if (envOrigin) {\n return envOrigin;\n }\n\n const origin = (await headers()).get('x-origin');\n\n if (origin) {\n return origin;\n }\n\n const proto = (await headers()).get('x-forwarded-proto');\n const host = (await headers()).get('x-forwarded-host');\n\n if (proto && host) {\n return `${proto}://${host}`;\n }\n\n throw new Error('No origin could be determined');\n}\n\nexport async function getPathname(): Promise<string> {\n const pathname = (await headers()).get('x-pathname');\n\n if (pathname) {\n return pathname;\n }\n\n throw new Error(\n 'No pathname could be determined. Please make sure middleware is being applied to the current request.'\n );\n}\n\n/**\n * Builds a URL from the current origin and a given pathname. For more information on how the origin\n * is determined, see the `getOrigin` function. This function then just concatenates the origin and\n * the pathname, and performs some cleanup to ensure the URL is valid.\n *\n * @param pathname\n * @returns The URL, with the origin and pathname combined.\n */\nexport async function makeURL(pathname?: string): Promise<string> {\n const origin = await getOrigin();\n\n if (!pathname) {\n return origin;\n }\n\n const isSecure = origin.startsWith('https://');\n\n const protocol = isSecure ? 'https://' : 'http://';\n const originWithoutProtocol = origin.replace(/^https?:\\/\\//u, '');\n\n const cleanURL = `${originWithoutProtocol}/${pathname}`.replace(/\\/+/gu, '/');\n return `${protocol}${cleanURL}`;\n}\n\n/**\n * @deprecated Use `makeURL` instead.\n */\nexport async function getURL(pathname?: string): Promise<string> {\n return makeURL(pathname);\n}\n","import { DrizzlePostgreSQLAdapter } from '@lucia-auth/adapter-drizzle';\nimport { pick } from '@sqrzro/utility';\nimport { Lucia, TimeSpan, generateId } from 'lucia';\nimport { cookies } from 'next/headers';\nimport { NextResponse } from 'next/server';\nimport type { NextRequest } from 'next/server';\nimport { match } from 'path-to-regexp';\n\nimport { getAllowedRoles } from './AuthService';\n\nimport { db } from '../database/DatabaseService';\nimport { authSessionTable, authUserTable } from '../database/schema';\nimport type { Scope } from '../database/schema';\n\nimport { getFromCache, setToCache } from '../cache/CacheService';\nimport { getOrigin } from '../url/URLService';\n\nconst DEFAULT_REDIRECT = '/auth/login';\nconst ID_LENGTH = 16;\n\ntype TimeSpanUnit = 'd' | 'h' | 'm' | 'ms' | 's' | 'w';\n\ninterface ScopeData {\n allowedRoute?: string;\n redirectOnAuth?: string;\n redirectOnUnauth?: string;\n}\n\nexport type ScopeObject = Record<Scope, ScopeData>;\n\ninterface DatabaseSessionAttributes {\n scope: Scope;\n}\n\ninterface DatabaseUserAttributes {\n email: string;\n role: number;\n deletedAt?: Date | null;\n}\n\ndeclare module 'lucia' {\n interface Register {\n Lucia: typeof lucia;\n DatabaseSessionAttributes: DatabaseSessionAttributes;\n DatabaseUserAttributes: DatabaseUserAttributes;\n }\n}\n\nconst DEFAULT_SCOPES: ScopeObject = {\n ANON: {\n allowedRoute: '/auth/(login|password)',\n redirectOnUnauth: DEFAULT_REDIRECT,\n },\n MFA: {\n allowedRoute: '/auth/mfa',\n redirectOnUnauth: '/auth/mfa',\n },\n AUTHED: {\n allowedRoute: '*',\n redirectOnAuth: '/',\n },\n};\n\n/* eslint-disable id-length */\nconst timespanMap: Record<string, TimeSpanUnit> = {\n D: 'd',\n H: 'h',\n M: 'm',\n MS: 'ms',\n S: 's',\n W: 'w',\n};\n/* eslint-enable id-length */\n\nfunction getSessionExpiry(): TimeSpan {\n if (!process.env.AUTH_SESSION_EXPIRY) {\n return new TimeSpan(2, 'w');\n }\n\n const [value, unit] = process.env.AUTH_SESSION_EXPIRY.split(/_/u);\n return new TimeSpan(Number(value), timespanMap[unit]);\n}\n\nconst adapter = new DrizzlePostgreSQLAdapter(db, authSessionTable, authUserTable);\n\nexport const lucia = new Lucia(adapter, {\n getSessionAttributes: (attributes: DatabaseSessionAttributes): DatabaseSessionAttributes => ({\n scope: attributes.scope,\n }),\n getUserAttributes: (attributes: DatabaseUserAttributes): DatabaseUserAttributes => ({\n email: attributes.email,\n role: attributes.role,\n deletedAt: attributes.deletedAt,\n }),\n sessionCookie: {\n attributes: {\n secure: process.env.APP_ENV === 'production',\n },\n name: process.env.AUTH_COOKIE_NAME || 'auth_session',\n },\n sessionExpiresIn: getSessionExpiry(),\n});\n\nexport function generateID<T extends string = string>(prefix = '', length = ID_LENGTH): T {\n return `${prefix ? `${prefix}_` : ''}${generateId(length)}` as T;\n}\n\nexport async function invalidateSession(id: string): Promise<void> {\n const cookie = lucia.createBlankSessionCookie();\n (await cookies()).set(cookie.name, cookie.value, cookie.attributes);\n\n return lucia.invalidateSession(id);\n}\n\nexport async function invalidateUserSessions(id: string): Promise<void> {\n return lucia.invalidateUserSessions(id);\n}\n\nexport async function createUserSession(id: string, scope: Scope = 'ANON'): Promise<boolean> {\n const session = await lucia.createSession(id, { scope });\n const sessionCookie = lucia.createSessionCookie(session.id);\n (await cookies()).set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);\n\n return true;\n}\n\nexport async function getSessionID(): Promise<string | null> {\n return (await cookies()).get(lucia.sessionCookieName)?.value ?? null;\n}\n\nexport async function checkSessionExists(): Promise<boolean> {\n return Boolean(await getSessionID());\n}\n\nfunction checkUserRole(userRole: number, targetRoles?: number[] | number): boolean {\n const targetRolesArray = Array.isArray(targetRoles) ? targetRoles : [targetRoles];\n\n if (targetRolesArray[0]) {\n return targetRolesArray.includes(userRole);\n }\n\n return getAllowedRoles().includes(userRole);\n}\n\nexport async function getSessionUser(roles?: number[] | number): Promise<{\n id: string;\n email: string;\n role: number;\n} | null> {\n const sessionID = await getSessionID();\n\n if (!sessionID) {\n return null;\n }\n\n const { user } = await lucia.validateSession(sessionID);\n\n if (!user || user.deletedAt || !checkUserRole(user.role, roles)) {\n return null;\n }\n\n return pick(user, ['id', 'email', 'role']);\n}\n\nexport function checkRouteAllowed(pathname: string, route?: string): boolean {\n if (!route) {\n return false;\n }\n\n if (route === '*') {\n return true;\n }\n\n return match(route)(pathname) !== false;\n}\n\nexport async function getScopes(): Promise<ScopeObject> {\n const scopes = await getFromCache(`${await getOrigin()}:scopes`);\n return scopes ? (JSON.parse(scopes) as ScopeObject) : DEFAULT_SCOPES;\n}\n\nexport async function getScopeByID(id: Scope): Promise<ScopeData> {\n const scopes = await getScopes();\n return scopes[id];\n}\n\nexport async function setScopes(customScopes?: Partial<ScopeObject>): Promise<void> {\n const scopes = {\n ANON: {\n ...DEFAULT_SCOPES.ANON,\n ...customScopes?.ANON,\n },\n MFA: {\n ...DEFAULT_SCOPES.MFA,\n ...customScopes?.MFA,\n },\n AUTHED: {\n ...DEFAULT_SCOPES.AUTHED,\n ...customScopes?.AUTHED,\n },\n };\n\n return setToCache(`${await getOrigin()}:scopes`, JSON.stringify(scopes));\n}\n\nasync function validateSessionFromID(\n sessionID: string,\n pathname: string\n): Promise<{ redirect: string | null; email: string | null }> {\n const scopes = await getScopes();\n const { session, user } = await lucia.validateSession(sessionID);\n\n const scope =\n scopes[session && getAllowedRoles().includes(user?.role) ? session.scope : 'ANON'];\n\n return {\n email: user?.email || null,\n redirect: checkRouteAllowed(pathname, scope.allowedRoute)\n ? null\n : scope.redirectOnUnauth || DEFAULT_REDIRECT,\n };\n}\n\nexport async function handleSession(\n request: NextRequest,\n customScopes?: Partial<ScopeObject>\n): Promise<NextResponse> {\n const sessionID = request.nextUrl.searchParams.get('id') || '';\n const pathname = request.nextUrl.searchParams.get('pathname') || '/';\n\n await setScopes(customScopes);\n\n return NextResponse.json(await validateSessionFromID(sessionID, pathname));\n}\n","import type { Errorable } from '@sqrzro/interfaces';\nimport { and, eq, isNotNull, isNull } from 'drizzle-orm';\nimport { authenticator } from 'otplib';\nimport qrcode from 'qrcode';\n\nimport { db } from '../database/DatabaseService';\nimport { authMFATable, authUserTable } from '../database/schema';\n\nimport { submitForm } from '../forms/FormService';\nimport ValidationError from '../forms/ValidationError';\n\nimport MFARequest from './MFARequest';\nimport {\n createUserSession,\n generateID,\n getSessionUser,\n invalidateUserSessions,\n} from './SessionService';\nimport type { MFAFormFields, UserObject } from './interfaces';\n\nexport function checkMFAEnabled(): boolean {\n return process.env.AUTH_MFA_ENABLED !== 'false';\n}\n\nexport async function generateMFA(name: string, email?: string): Promise<string | null> {\n if (!checkMFAEnabled()) {\n throw new Error('MFA is not enabled. Cannot generate MFA secret.');\n }\n\n if (!email) {\n return null;\n }\n\n const [user] = await db\n .select()\n .from(authUserTable)\n .where(eq(authUserTable.email, email))\n .limit(1);\n\n if (!user) {\n return null;\n }\n\n const secret = authenticator.generateSecret();\n const otpauth = authenticator.keyuri(email, name, secret);\n\n // Delete all the unverified MFA entries for this user\n\n await db\n .delete(authMFATable)\n .where(and(eq(authMFATable.userId, user.id), isNull(authMFATable.verifiedAt)));\n\n // Add the new MFA entry\n\n await db.insert(authMFATable).values({\n id: generateID(),\n name: 'Default',\n secret,\n userId: user.id,\n });\n\n return new Promise((resolve, reject) => {\n qrcode.toDataURL(\n otpauth,\n { rendererOpts: { quality: 1 }, margin: 0, scale: 2 },\n (err, data) => {\n if (err) {\n reject(err);\n }\n resolve(data);\n }\n );\n });\n}\n\nexport async function checkUserHasMFA(user: UserObject): Promise<boolean> {\n if (!checkMFAEnabled()) {\n return false;\n }\n\n const [mfa] = await db\n .select()\n .from(authMFATable)\n .where(and(eq(authMFATable.userId, user.id), isNotNull(authMFATable.verifiedAt)))\n .limit(1);\n\n return Boolean(mfa);\n}\n\nasync function markAsVerified(userID: string): Promise<void> {\n if (!checkMFAEnabled()) {\n return;\n }\n\n await db\n .update(authMFATable)\n .set({ verifiedAt: new Date() })\n .where(eq(authMFATable.userId, userID));\n}\n\nasync function validateUserToken(userID: string, token: string): Promise<boolean> {\n if (!checkMFAEnabled()) {\n return false;\n }\n\n const [mfa] = await db\n .select()\n .from(authMFATable)\n .where(eq(authMFATable.userId, userID))\n .limit(1);\n\n if (!mfa) {\n return false;\n }\n\n return authenticator.check(token, mfa.secret);\n}\n\nexport async function deleteMFA(userID: string): Promise<boolean> {\n const promises = [\n db.delete(authMFATable).where(eq(authMFATable.userId, userID)),\n invalidateUserSessions(userID),\n ];\n\n await Promise.all(promises);\n return true;\n}\n\nexport async function handleMFA(data: MFAFormFields): Promise<boolean> {\n if (!checkMFAEnabled()) {\n throw new ValidationError({ token: 'MFA is not enabled' });\n }\n\n const user = await getSessionUser();\n\n if (!user) {\n throw new ValidationError({ token: 'User not found' });\n }\n\n const isValid = await validateUserToken(user.id, data.token);\n\n if (!isValid) {\n throw new ValidationError({ token: 'Invalid token' });\n }\n\n await markAsVerified(user.id);\n return createUserSession(user.id, 'AUTHED');\n}\n\nexport async function handleMFAForm(formData: MFAFormFields): Promise<Errorable<boolean>> {\n if (!checkMFAEnabled()) {\n return [null, new Error('MFA is not enabled')];\n }\n\n const response = await submitForm<MFAFormFields, boolean>({\n fn: handleMFA,\n formData,\n request: MFARequest,\n });\n\n return response;\n}\n","import bcrypt from 'bcryptjs';\n\nconst PW_SALT_ROUNDS = 12;\n\ntype PasswordRule = 'lower' | 'min' | 'number' | 'symbol' | 'upper';\n\nexport type PasswordRuleObject = Partial<Record<PasswordRule, number>>;\ntype PasswordValidityObject = Record<PasswordRule, boolean>;\n\nconst PASSWORD_RULES: PasswordRuleObject = {\n min: 8,\n upper: 1,\n lower: 1,\n number: 1,\n symbol: 1,\n};\n\nfunction checkPasswordMin(password: string, value: number): boolean {\n return password.length >= value;\n}\n\nfunction checkPasswordUpper(password: string, value: number): boolean {\n return password.replace(/[^A-Z]/gu, '').length >= value;\n}\n\nfunction checkPasswordLower(password: string, value: number): boolean {\n return password.replace(/[^a-z]/gu, '').length >= value;\n}\n\nfunction checkPasswordNumber(password: string, value: number): boolean {\n return password.replace(/[^0-9]/gu, '').length >= value;\n}\n\nfunction checkPasswordSymbol(password: string, value: number): boolean {\n return password.replace(/[^$]/gu, '').length >= value;\n}\n\nconst PASSWORD_FUNCTIONS: Record<PasswordRule, (password: string, value: number) => boolean> = {\n min: checkPasswordMin,\n upper: checkPasswordUpper,\n lower: checkPasswordLower,\n number: checkPasswordNumber,\n symbol: checkPasswordSymbol,\n};\n\nexport async function hashPassword(password: string): Promise<string> {\n const hash = await bcrypt.hash(password, PW_SALT_ROUNDS);\n return hash;\n}\n\nexport async function verifyPassword(data?: string, encrypted?: string): Promise<boolean> {\n if (!data || !encrypted) {\n return false;\n }\n\n const verified = await bcrypt.compare(data, encrypted);\n return verified;\n}\n\nexport async function getPasswordComplexity(\n password: string,\n rules: Partial<PasswordRuleObject> = PASSWORD_RULES\n): Promise<Partial<PasswordValidityObject>> {\n const entries = Object.entries(rules) as [PasswordRule, number][];\n\n const validity = entries.reduce<Partial<PasswordValidityObject>>((acc, [rule, value]) => {\n acc[rule] = PASSWORD_FUNCTIONS[rule](password, value);\n return acc;\n }, {});\n\n return Promise.resolve(validity);\n}\n\nexport async function checkPasswordComplexity(\n password: string,\n rules: Partial<PasswordRuleObject> = PASSWORD_RULES\n): Promise<Partial<boolean>> {\n const validity = await getPasswordComplexity(password, rules);\n return Promise.resolve(Object.values(validity).every(Boolean));\n}\n","/* eslint-disable @typescript-eslint/no-magic-numbers */\n\nimport Joi from 'joi';\n\nimport { createSchema } from '../forms/ValidationService';\nimport type { LoginFormFields } from './interfaces';\n\nconst LoginRequest = createSchema<LoginFormFields>({\n email: Joi.string().email({ minDomainSegments: 2, tlds: false }).required(),\n password: Joi.string().min(8).required(),\n});\n\nexport default LoginRequest;\n","/* eslint-disable @typescript-eslint/no-magic-numbers */\n\nimport Joi from 'joi';\n\nimport { createSchema } from '../forms/ValidationService';\nimport type { PasswordFormFields } from './interfaces';\n\nconst PasswordRequest = createSchema<PasswordFormFields>({\n email: Joi.string().max(60).email({ minDomainSegments: 2, tlds: false }).required().messages({\n 'any.required': 'Please provide your email address, so we can send you a reset link',\n 'string.empty': 'Please provide your email address, so we can send you a reset link',\n 'string.email': 'Please make sure your email address is valid',\n 'string.max': 'Please make sure your email address is valid',\n }),\n});\n\nexport default PasswordRequest;\n","import Joi from 'joi';\n\nimport { checkPasswordComplexity } from './PasswordService';\nimport type { PasswordRuleObject } from './PasswordService';\nimport type { ValidationCustomHelpers } from '../forms/ValidationService';\n\nimport { createSchema } from '../forms/ValidationService';\nimport type { PasswordResetWithTokenFormFields } from './interfaces';\n\nconst passwordComplexity: PasswordRuleObject = {\n lower: 1,\n min: 8,\n number: 1,\n upper: 1,\n};\n\nasync function passwordIsComplex(\n value: string,\n helpers: ValidationCustomHelpers\n): Promise<Error | string> {\n if (!(await checkPasswordComplexity(value, passwordComplexity))) {\n return helpers.message({\n external:\n 'Please make sure your password is complex enough, to keep your account secure',\n });\n }\n return value;\n}\n\nconst PasswordResetWithTokenRequest = createSchema<PasswordResetWithTokenFormFields>({\n password: Joi.string().external(passwordIsComplex).required().messages({\n 'any.required': 'Please provide your new password',\n 'string.empty': 'Please provide your new password',\n }),\n token: Joi.string().pattern(/[a-z0-9]{40}/u),\n});\n\nexport default PasswordResetWithTokenRequest;\n","import type { Errorable } from '@sqrzro/interfaces';\nimport { and, eq, inArray, isNull, lte } from 'drizzle-orm';\n\nimport { db } from '../database/DatabaseService';\nimport { authResetTable, authUserTable } from '../database/schema';\n\nimport { submitForm } from '../forms/FormService';\nimport ValidationError from '../forms/ValidationError';\n\nimport { checkMFAEnabled } from './MFAService';\nimport { hashPassword, verifyPassword } from './PasswordService';\nimport {\n createUserSession,\n generateID,\n getScopeByID,\n getSessionID,\n invalidateSession,\n invalidateUserSessions,\n} from './SessionService';\n\nimport LoginRequest from './LoginRequest';\nimport PasswordRequest from './PasswordRequest';\nimport PasswordResetWithTokenRequest from './PasswordResetWithTokenRequest';\n\nimport type {\n LoginFormFields,\n PasswordFormFields,\n PasswordResetWithTokenFormFields,\n UserObject,\n} from './interfaces';\n\nconst RESET_TOKEN_LENGTH = 40;\n\n// Set expiry to 1 hour (in ms)\nconst RESET_TOKEN_EXPIRY = 3600000;\n\nexport async function handleLogout(): Promise<void> {\n const id = await getSessionID();\n\n if (id) {\n await invalidateSession(id);\n }\n}\n\ninterface LoginUserArgs {\n email: string;\n password: string;\n role?: number;\n token?: string;\n}\n\nexport function getAllowedRoles(): number[] {\n const role = process.env.AUTH_ROLE;\n\n if (!role) {\n throw new Error('AUTH_ROLE is not defined. Authentication will not be possible.');\n }\n\n return [Number(role)];\n}\n\nexport function getMaximumRole(): number {\n const roles = getAllowedRoles();\n return Math.max(...roles);\n}\n\nasync function handleUserSession(userID: string): Promise<string | null> {\n await createUserSession(userID, checkMFAEnabled() ? 'MFA' : 'AUTHED');\n\n const scope = await getScopeByID('AUTHED');\n return scope?.redirectOnAuth || null;\n}\n\nexport async function getUserByEmail(email: string, role?: number): Promise<UserObject | null> {\n console.log('[--] getUserByEmail', email, role, getMaximumRole());\n\n const conditions = [eq(authUserTable.email, email), isNull(authUserTable.deletedAt)];\n\n if (role) {\n conditions.push(eq(authUserTable.role, role));\n } else {\n conditions.push(lte(authUserTable.role, getMaximumRole()));\n }\n\n const [user] = await db\n .select()\n .from(authUserTable)\n .where(and(...conditions))\n .limit(1);\n\n console.log('[--] user', user);\n\n return user;\n}\n\nasync function loginUser({ email, password }: LoginUserArgs): Promise<string> {\n if (!process.env.AUTH_ROLE) {\n throw new Error('AUTH_ROLE is not defined. Authentication will not be possible.');\n }\n\n const user = await getUserByEmail(email, Number(process.env.AUTH_ROLE));\n\n if (!user?.password || !(await verifyPassword(password, user.password))) {\n throw new ValidationError({ email: '', password: '' });\n }\n\n const session = await handleUserSession(user.id);\n\n if (!session) {\n throw new ValidationError({ email: '', password: '' });\n }\n\n return session;\n}\n\nexport async function handleLoginForm(\n formData: LoginFormFields,\n onSuccess?: () => Promise<void>\n): Promise<Errorable<string>> {\n const response = await submitForm<LoginFormFields, string>({\n fn: loginUser,\n formData,\n onSuccess: async () => {\n await onSuccess?.();\n },\n request: LoginRequest,\n });\n\n return response;\n}\n\ninterface RegisterUserArgs {\n email: string;\n password?: string;\n role?: number;\n}\n\nexport async function registerUser({\n email,\n password,\n role,\n}: RegisterUserArgs): Promise<UserObject | null> {\n const hash = password ? await hashPassword(password) : null;\n\n const [user] = await db\n .insert(authUserTable)\n .values({ id: generateID(), email, password: hash, role })\n .returning();\n\n return user;\n}\n\nasync function updateDeletedAt(\n email: string,\n role: number,\n deletedAt: Date | null\n): Promise<boolean> {\n const [user] = await db\n .select()\n .from(authUserTable)\n .where(and(eq(authUserTable.email, email), eq(authUserTable.role, role)))\n .limit(1);\n\n if (!user) {\n return false;\n }\n\n await db.update(authUserTable).set({ deletedAt }).where(eq(authUserTable.id, user.id));\n\n return true;\n}\n\nexport async function deleteUser(email: string, role: number): Promise<boolean> {\n return updateDeletedAt(email, role, new Date());\n}\n\nexport async function undeleteUser(email: string, role: number): Promise<boolean> {\n return updateDeletedAt(email, role, null);\n}\n\nasync function createPasswordResetToken(email: string): Promise<string | null> {\n console.log('[--] createPasswordResetToken', email);\n\n const user = await getUserByEmail(email);\n\n console.log('[--] user', user);\n\n if (!user) {\n return null;\n }\n\n await db.delete(authResetTable).where(eq(authResetTable.userId, user.id));\n\n const id = generateID('', RESET_TOKEN_LENGTH);\n\n await db.insert(authResetTable).values({\n id,\n userId: user.id,\n expiresAt: new Date(new Date().getTime() + RESET_TOKEN_EXPIRY),\n });\n\n return id;\n}\n\nexport async function handlePasswordForm(\n formData: PasswordFormFields,\n mailFn: (email: string, token: string) => Promise<boolean>\n): Promise<Errorable<boolean>> {\n console.log('[--] handlePasswordForm', formData);\n\n async function mutateFn(data: PasswordFormFields): Promise<boolean> {\n console.log('[--] mutateFn', data);\n\n const token = await createPasswordResetToken(data.email);\n\n console.log('[--] token', token);\n\n if (!token) {\n // Return true, even though the email doesn't exist (to prevent user enumeration)\n return true;\n }\n\n return mailFn(data.email, token);\n }\n\n const response = await submitForm<PasswordFormFields, boolean>({\n fn: mutateFn,\n formData,\n request: PasswordRequest,\n });\n\n return response;\n}\n\nasync function validatePasswordResetToken(token: string, password: string): Promise<string> {\n const [result] = await db\n .select()\n .from(authResetTable)\n .where(eq(authResetTable.id, token))\n .limit(1);\n\n if (!result) {\n throw new Error('PASSWORD_RESET_TOKEN_NOT_FOUND');\n }\n\n await db.delete(authResetTable).where(eq(authResetTable.id, token));\n\n if (result.expiresAt < new Date()) {\n throw new Error('PASSWORD_RESET_TOKEN_EXPIRED');\n }\n\n await invalidateUserSessions(result.userId);\n\n await db\n .update(authUserTable)\n .set({ password: await hashPassword(password) })\n .where(\n and(eq(authUserTable.id, result.userId), inArray(authUserTable.role, getAllowedRoles()))\n );\n\n return result.userId;\n}\n\nexport async function handlePasswordResetWithTokenForm(\n formData: PasswordResetWithTokenFormFields,\n onSuccess?: (model: string) => Promise<void>\n): Promise<Errorable<string>> {\n async function mutateFn(data: PasswordResetWithTokenFormFields): Promise<string> {\n const userID = await validatePasswordResetToken(data.token, data.password);\n const session = await handleUserSession(userID);\n\n if (!session) {\n throw new Error('COULD_NOT_CREATE_SESSION');\n }\n\n return session;\n }\n\n const response = await submitForm({\n fn: mutateFn,\n formData,\n onSuccess,\n request: PasswordResetWithTokenRequest,\n });\n\n return response;\n}\n","import type { NextRequest } from 'next/server';\nimport { eq } from 'drizzle-orm';\n\nimport { db } from '../database/DatabaseService';\nimport { authClientTable } from '../database/schema';\nimport type { AuthClient } from '../database/schema';\n\nimport { hashPassword, verifyPassword } from './PasswordService';\nimport { generateID } from './SessionService';\n\nconst ID_LENGTH = 16;\nconst SECRET_LENGTH = 64;\n\nexport async function getClientByID(id: string): Promise<AuthClient | null> {\n const [client] = await db\n .select()\n .from(authClientTable)\n .where(eq(authClientTable.id, id))\n .limit(1);\n\n return client;\n}\n\ninterface RegisterClientArgs {\n alias: string;\n id?: string;\n secret?: string;\n}\n\nexport async function registerClient({\n alias,\n id,\n secret,\n}: RegisterClientArgs): Promise<AuthClient | null> {\n const [client] = await db\n .insert(authClientTable)\n .values({\n alias,\n id: id || generateID('', ID_LENGTH),\n secret: await hashPassword(secret || generateID('', SECRET_LENGTH)),\n })\n .returning();\n\n return client;\n}\n\nexport async function handleClientAuth(request: NextRequest): Promise<AuthClient | null> {\n const { headers } = request;\n const header = headers.get('authorization');\n\n if (!header) {\n return null;\n }\n\n const auth = Buffer.from(header.replace('Basic ', ''), 'base64')\n .toString('utf-8')\n .replace(/:$/u, '');\n\n const [id, ...secret] = auth.split('-');\n\n const [client] = await db\n .select()\n .from(authClientTable)\n .where(eq(authClientTable.id, id))\n .limit(1);\n\n if (!client) {\n return null;\n }\n\n const isVerified = await verifyPassword(secret.join(''), client.secret);\n return isVerified ? client : null;\n}\n"]}
@@ -1,3 +1,3 @@
1
- 'use strict';var l=require('@sendgrid/mail'),u=require('stream');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var l__default=/*#__PURE__*/_interopDefault(l);var u__default=/*#__PURE__*/_interopDefault(u);function A(t,e){return {subject:t,template:e}}async function g(t){let e=(await import('react-dom/server')).default;return new Promise(o=>{let n=new u__default.default.Writable,r="";function i(c,m,p){r+=c.toString(),p();}n._write=i;let{pipe:a}=e.renderToPipeableStream(t,{onShellReady:()=>{a(n),o(r);}});})}async function f(t,e){let{subject:o,template:n}=t,r=await n(e),i=await g(r);return {subject:o,html:i}}function h(){if(!process.env.MAIL_FROM)throw new Error("Mail from address has not been set");let t=/^(?<name>[^<]+)<(?<email>[^>]+)>$/u.exec(process.env.MAIL_FROM);if(!t?.groups?.name||!t?.groups?.email)throw new Error('Mail from address is not the correct format. It should be "Name <email>".');return {email:t.groups.email.trim(),name:t.groups.name.trim()}}function s(t){return t?Array.isArray(t)?t.map(e=>({email:e})):[{email:t}]:[]}async function M(t){if(!process.env.MAIL_API_KEY)throw new Error("Mail API key has not been set");let[e,o]=process.env.MAIL_API_KEY.split("."),n=Array.isArray(t.to)?t.to.map(r=>({email:r})):[{email:t.to}];try{return (await(await fetch(`https://sandbox.api.mailtrap.io/api/send/${e}`,{method:"POST",headers:{"Api-Token":o,"Content-Type":"application/json"},body:JSON.stringify({attachments:t.attachments,bcc:s(t.bcc),cc:s(t.cc),from:t.from,html:t.html,subject:t.subject,to:n})})).json()).success}catch{return !1}}async function b(t){if(process.env.APP_ENV!=="production")throw new Error("Trying to run production mail in a development environment");if(!process.env.MAIL_ENABLE_PRODUCTION)throw new Error("Mail has not been enabled in production. Please add MAIL_ENABLE_PRODUCTION to your environment variables.");if(!process.env.MAIL_API_KEY)throw new Error("Mail API key has not been set");l__default.default.setApiKey(process.env.MAIL_API_KEY);let e=await l__default.default.send({attachments:t.attachments,bcc:s(t.bcc),cc:s(t.cc),from:t.from,html:t.html,to:s(t.to),subject:t.subject});if(!e[0].statusCode.toString().startsWith("2"))throw new Error(`Mail not sent. ${JSON.stringify(e)}`);return !0}async function E(t,e,o,n,r){if(!process.env.MAIL_API_KEY)throw new Error("Mail API key has not been set");let i=h(),{subject:a,html:c}=await f(t,e),m={attachments:r,bcc:n?.bcc,cc:n?.cc,from:i,html:c,subject:a,to:o};return process.env.APP_ENV==="production"?b(m):M(m)}
2
- exports.createMail=A;exports.getMail=f;exports.sendMail=E;//# sourceMappingURL=index.cjs.map
1
+ 'use strict';var l=require('@sendgrid/mail'),u=require('stream');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var l__default=/*#__PURE__*/_interopDefault(l);var u__default=/*#__PURE__*/_interopDefault(u);function A(t,e){return {subject:t,template:e}}async function p(t){let e=(await import('react-dom/server')).default;return new Promise(s=>{let n=new u__default.default.Writable,r="";function o(c,m,g){r+=c.toString(),g();}n._write=o;let{pipe:a}=e.renderToPipeableStream(t,{onShellReady:()=>{a(n),s(r);}});})}async function f(t,e){let{subject:s,template:n}=t,r=await n(e),o=await p(r);return {subject:s,html:o}}function h(){if(!process.env.MAIL_FROM)throw new Error("Mail from address has not been set");let t=/^(?<name>[^<]+)<(?<email>[^>]+)>$/u.exec(process.env.MAIL_FROM);if(!t?.groups?.name||!t?.groups?.email)throw new Error('Mail from address is not the correct format. It should be "Name <email>".');return {email:t.groups.email.trim(),name:t.groups.name.trim()}}function i(t){return t?Array.isArray(t)?t.map(e=>({email:e})):[{email:t}]:[]}async function M(t){if(!process.env.MAIL_API_KEY)throw new Error("Mail API key has not been set");let[e,s]=process.env.MAIL_API_KEY.split("."),n=Array.isArray(t.to)?t.to.map(r=>({email:r})):[{email:t.to}];try{return (await(await fetch(`https://sandbox.api.mailtrap.io/api/send/${e}`,{method:"POST",headers:{"Api-Token":s,"Content-Type":"application/json"},body:JSON.stringify({attachments:t.attachments,bcc:i(t.bcc),cc:i(t.cc),from:t.from,html:t.html,subject:t.subject,to:n})})).json()).success}catch{return !1}}async function b(t){if(!process.env.MAIL_API_KEY)throw new Error("Mail API key has not been set");l__default.default.setApiKey(process.env.MAIL_API_KEY);let e=await l__default.default.send({attachments:t.attachments,bcc:i(t.bcc),cc:i(t.cc),from:t.from,html:t.html,to:i(t.to),subject:t.subject});if(!e[0].statusCode.toString().startsWith("2"))throw new Error(`Mail not sent. ${JSON.stringify(e)}`);return !0}async function y(t,e,s,n,r){let o=h(),{subject:a,html:c}=await f(t,e),m={attachments:r,bcc:n?.bcc,cc:n?.cc,from:o,html:c,subject:a,to:s};return process.env.MAIL_ENABLE_PRODUCTION==="true"||process.env.MAIL_ENABLE_PRODUCTION==="1"?b(m):M(m)}
2
+ exports.createMail=A;exports.getMail=f;exports.sendMail=y;//# sourceMappingURL=index.cjs.map
3
3
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/mail/MailService.ts"],"names":["createMail","subject","template","renderMail","element","ReactDOMServer","resolve","ws","stream","content","write","chunk","enc","next","pipe","getMail","mail","data","html","getSenderDetails","matches","transformEmailData","emails","email","sendDevelopmentMail","sendObject","id","key","to","sendProductionMail","sgMail","response","sendMail","options","attachments","from"],"mappings":"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","file":"index.cjs","sourcesContent":["import sgMail from '@sendgrid/mail';\n\nimport stream from 'node:stream';\n\nexport interface MailObject<T extends object> {\n subject: string;\n template: (data: T) => Promise<React.ReactElement> | React.ReactElement;\n}\n\nexport function createMail<T extends object>(\n subject: string,\n template: (data: T) => Promise<React.ReactElement> | React.ReactElement\n): MailObject<T> {\n return { subject, template };\n}\n\nasync function renderMail(element: React.ReactElement): Promise<string> {\n const ReactDOMServer = (await import('react-dom/server')).default;\n\n return new Promise((resolve) => {\n const ws = new stream.Writable();\n let content = '';\n\n function write<T extends { toString: () => string }>(\n chunk: T,\n enc: BufferEncoding,\n next: (error?: Error | null) => void\n ): void {\n content += chunk.toString();\n next();\n }\n\n ws._write = write; // eslint-disable-line no-underscore-dangle\n\n const { pipe } = ReactDOMServer.renderToPipeableStream(element, {\n onShellReady: () => {\n pipe(ws);\n resolve(content);\n },\n });\n });\n}\n\nexport async function getMail<T extends object>(\n mail: MailObject<T>,\n data: T\n): Promise<{ subject: string; html: string }> {\n const { subject, template } = mail;\n\n const element = await template(data);\n const html = await renderMail(element);\n\n return {\n subject,\n html,\n };\n}\n\nfunction getSenderDetails(): { email: string; name: string } {\n if (!process.env.MAIL_FROM) {\n throw new Error('Mail from address has not been set');\n }\n\n const matches = /^(?<name>[^<]+)<(?<email>[^>]+)>$/u.exec(process.env.MAIL_FROM);\n\n if (!matches?.groups?.name || !matches?.groups?.email) {\n throw new Error(\n 'Mail from address is not the correct format. It should be \"Name <email>\".'\n );\n }\n\n return {\n email: matches.groups.email.trim(),\n name: matches.groups.name.trim(),\n };\n}\n\nfunction transformEmailData(emails?: string[] | string): { email: string }[] {\n if (!emails) {\n return [];\n }\n return Array.isArray(emails) ? emails.map((email) => ({ email })) : [{ email: emails }];\n}\n\ninterface SendMailObject {\n attachments?: { content: string; filename: string; type: string }[];\n bcc?: string[] | string;\n cc?: string[] | string;\n from: { email: string; name: string };\n html: string;\n subject: string;\n to: string[] | string;\n}\n\nasync function sendDevelopmentMail(sendObject: SendMailObject): Promise<boolean> {\n if (!process.env.MAIL_API_KEY) {\n throw new Error('Mail API key has not been set');\n }\n\n /*\n * The account id and api key are both in the MAIL_API_KEY variable, separated by a `.`. We need\n * to split them.\n */\n\n const [id, key] = process.env.MAIL_API_KEY.split('.');\n\n const to = Array.isArray(sendObject.to)\n ? sendObject.to.map((email) => ({ email }))\n : [{ email: sendObject.to }];\n\n try {\n const response = await fetch(`https://sandbox.api.mailtrap.io/api/send/${id}`, {\n method: 'POST',\n headers: { 'Api-Token': key, 'Content-Type': 'application/json' },\n body: JSON.stringify({\n attachments: sendObject.attachments,\n bcc: transformEmailData(sendObject.bcc),\n cc: transformEmailData(sendObject.cc),\n from: sendObject.from,\n html: sendObject.html,\n subject: sendObject.subject,\n to,\n }),\n });\n const json = (await response.json()) as { success: boolean };\n return json.success;\n } catch (err) {\n return false;\n }\n}\n\nasync function sendProductionMail(sendObject: SendMailObject): Promise<boolean> {\n if (process.env.APP_ENV !== 'production') {\n throw new Error('Trying to run production mail in a development environment');\n }\n\n if (!process.env.MAIL_ENABLE_PRODUCTION) {\n throw new Error(\n 'Mail has not been enabled in production. Please add MAIL_ENABLE_PRODUCTION to your environment variables.'\n );\n }\n\n if (!process.env.MAIL_API_KEY) {\n throw new Error('Mail API key has not been set');\n }\n\n sgMail.setApiKey(process.env.MAIL_API_KEY);\n\n const response = await sgMail.send({\n attachments: sendObject.attachments,\n bcc: transformEmailData(sendObject.bcc),\n cc: transformEmailData(sendObject.cc),\n from: sendObject.from,\n html: sendObject.html,\n to: transformEmailData(sendObject.to),\n subject: sendObject.subject,\n });\n\n if (!response[0].statusCode.toString().startsWith('2')) {\n throw new Error(`Mail not sent. ${JSON.stringify(response)}`);\n }\n\n return true;\n}\n\nexport async function sendMail<T extends object>(\n mail: MailObject<T>,\n data: T,\n to: string[] | string,\n options?: { cc?: string[]; bcc?: string[] },\n attachments?: { content: string; filename: string; type: string }[]\n): Promise<boolean> {\n if (!process.env.MAIL_API_KEY) {\n throw new Error('Mail API key has not been set');\n }\n\n const from = getSenderDetails();\n const { subject, html } = await getMail(mail, data);\n\n const sendObject: SendMailObject = {\n attachments,\n bcc: options?.bcc,\n cc: options?.cc,\n from,\n html,\n subject,\n to,\n };\n\n if (process.env.APP_ENV === 'production') {\n return sendProductionMail(sendObject);\n }\n\n return sendDevelopmentMail(sendObject);\n}\n"]}
1
+ {"version":3,"sources":["../../src/mail/MailService.ts"],"names":["createMail","subject","template","renderMail","element","ReactDOMServer","resolve","ws","stream","content","write","chunk","enc","next","pipe","getMail","mail","data","html","getSenderDetails","matches","transformEmailData","emails","email","sendDevelopmentMail","sendObject","id","key","to","sendProductionMail","sgMail","response","sendMail","options","attachments","from"],"mappings":"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","file":"index.cjs","sourcesContent":["import sgMail from '@sendgrid/mail';\n\nimport stream from 'node:stream';\n\nexport interface MailObject<T extends object> {\n subject: string;\n template: (data: T) => Promise<React.ReactElement> | React.ReactElement;\n}\n\nexport function createMail<T extends object>(\n subject: string,\n template: (data: T) => Promise<React.ReactElement> | React.ReactElement\n): MailObject<T> {\n return { subject, template };\n}\n\nasync function renderMail(element: React.ReactElement): Promise<string> {\n const ReactDOMServer = (await import('react-dom/server')).default;\n\n return new Promise((resolve) => {\n const ws = new stream.Writable();\n let content = '';\n\n function write<T extends { toString: () => string }>(\n chunk: T,\n enc: BufferEncoding,\n next: (error?: Error | null) => void\n ): void {\n content += chunk.toString();\n next();\n }\n\n ws._write = write; // eslint-disable-line no-underscore-dangle\n\n const { pipe } = ReactDOMServer.renderToPipeableStream(element, {\n onShellReady: () => {\n pipe(ws);\n resolve(content);\n },\n });\n });\n}\n\nexport async function getMail<T extends object>(\n mail: MailObject<T>,\n data: T\n): Promise<{ subject: string; html: string }> {\n const { subject, template } = mail;\n\n const element = await template(data);\n const html = await renderMail(element);\n\n return {\n subject,\n html,\n };\n}\n\nfunction getSenderDetails(): { email: string; name: string } {\n if (!process.env.MAIL_FROM) {\n throw new Error('Mail from address has not been set');\n }\n\n const matches = /^(?<name>[^<]+)<(?<email>[^>]+)>$/u.exec(process.env.MAIL_FROM);\n\n if (!matches?.groups?.name || !matches?.groups?.email) {\n throw new Error(\n 'Mail from address is not the correct format. It should be \"Name <email>\".'\n );\n }\n\n return {\n email: matches.groups.email.trim(),\n name: matches.groups.name.trim(),\n };\n}\n\nfunction transformEmailData(emails?: string[] | string): { email: string }[] {\n if (!emails) {\n return [];\n }\n return Array.isArray(emails) ? emails.map((email) => ({ email })) : [{ email: emails }];\n}\n\ninterface SendMailObject {\n attachments?: { content: string; filename: string; type: string }[];\n bcc?: string[] | string;\n cc?: string[] | string;\n from: { email: string; name: string };\n html: string;\n subject: string;\n to: string[] | string;\n}\n\nasync function sendDevelopmentMail(sendObject: SendMailObject): Promise<boolean> {\n if (!process.env.MAIL_API_KEY) {\n throw new Error('Mail API key has not been set');\n }\n\n /*\n * The account id and api key are both in the MAIL_API_KEY variable, separated by a `.`. We need\n * to split them.\n */\n\n const [id, key] = process.env.MAIL_API_KEY.split('.');\n\n const to = Array.isArray(sendObject.to)\n ? sendObject.to.map((email) => ({ email }))\n : [{ email: sendObject.to }];\n\n try {\n const response = await fetch(`https://sandbox.api.mailtrap.io/api/send/${id}`, {\n method: 'POST',\n headers: { 'Api-Token': key, 'Content-Type': 'application/json' },\n body: JSON.stringify({\n attachments: sendObject.attachments,\n bcc: transformEmailData(sendObject.bcc),\n cc: transformEmailData(sendObject.cc),\n from: sendObject.from,\n html: sendObject.html,\n subject: sendObject.subject,\n to,\n }),\n });\n const json = (await response.json()) as { success: boolean };\n return json.success;\n } catch (err) {\n return false;\n }\n}\n\nasync function sendProductionMail(sendObject: SendMailObject): Promise<boolean> {\n if (!process.env.MAIL_API_KEY) {\n throw new Error('Mail API key has not been set');\n }\n\n sgMail.setApiKey(process.env.MAIL_API_KEY);\n\n const response = await sgMail.send({\n attachments: sendObject.attachments,\n bcc: transformEmailData(sendObject.bcc),\n cc: transformEmailData(sendObject.cc),\n from: sendObject.from,\n html: sendObject.html,\n to: transformEmailData(sendObject.to),\n subject: sendObject.subject,\n });\n\n if (!response[0].statusCode.toString().startsWith('2')) {\n throw new Error(`Mail not sent. ${JSON.stringify(response)}`);\n }\n\n return true;\n}\n\nexport async function sendMail<T extends object>(\n mail: MailObject<T>,\n data: T,\n to: string[] | string,\n options?: { cc?: string[]; bcc?: string[] },\n attachments?: { content: string; filename: string; type: string }[]\n): Promise<boolean> {\n const from = getSenderDetails();\n const { subject, html } = await getMail(mail, data);\n\n const sendObject: SendMailObject = {\n attachments,\n bcc: options?.bcc,\n cc: options?.cc,\n from,\n html,\n subject,\n to,\n };\n\n if (\n process.env.MAIL_ENABLE_PRODUCTION === 'true' ||\n process.env.MAIL_ENABLE_PRODUCTION === '1'\n ) {\n return sendProductionMail(sendObject);\n }\n\n return sendDevelopmentMail(sendObject);\n}\n"]}
@@ -1,3 +1,3 @@
1
- import l from'@sendgrid/mail';import u from'stream';function A(t,e){return {subject:t,template:e}}async function g(t){let e=(await import('react-dom/server')).default;return new Promise(o=>{let n=new u.Writable,r="";function i(c,m,p){r+=c.toString(),p();}n._write=i;let{pipe:a}=e.renderToPipeableStream(t,{onShellReady:()=>{a(n),o(r);}});})}async function f(t,e){let{subject:o,template:n}=t,r=await n(e),i=await g(r);return {subject:o,html:i}}function h(){if(!process.env.MAIL_FROM)throw new Error("Mail from address has not been set");let t=/^(?<name>[^<]+)<(?<email>[^>]+)>$/u.exec(process.env.MAIL_FROM);if(!t?.groups?.name||!t?.groups?.email)throw new Error('Mail from address is not the correct format. It should be "Name <email>".');return {email:t.groups.email.trim(),name:t.groups.name.trim()}}function s(t){return t?Array.isArray(t)?t.map(e=>({email:e})):[{email:t}]:[]}async function M(t){if(!process.env.MAIL_API_KEY)throw new Error("Mail API key has not been set");let[e,o]=process.env.MAIL_API_KEY.split("."),n=Array.isArray(t.to)?t.to.map(r=>({email:r})):[{email:t.to}];try{return (await(await fetch(`https://sandbox.api.mailtrap.io/api/send/${e}`,{method:"POST",headers:{"Api-Token":o,"Content-Type":"application/json"},body:JSON.stringify({attachments:t.attachments,bcc:s(t.bcc),cc:s(t.cc),from:t.from,html:t.html,subject:t.subject,to:n})})).json()).success}catch{return !1}}async function b(t){if(process.env.APP_ENV!=="production")throw new Error("Trying to run production mail in a development environment");if(!process.env.MAIL_ENABLE_PRODUCTION)throw new Error("Mail has not been enabled in production. Please add MAIL_ENABLE_PRODUCTION to your environment variables.");if(!process.env.MAIL_API_KEY)throw new Error("Mail API key has not been set");l.setApiKey(process.env.MAIL_API_KEY);let e=await l.send({attachments:t.attachments,bcc:s(t.bcc),cc:s(t.cc),from:t.from,html:t.html,to:s(t.to),subject:t.subject});if(!e[0].statusCode.toString().startsWith("2"))throw new Error(`Mail not sent. ${JSON.stringify(e)}`);return !0}async function E(t,e,o,n,r){if(!process.env.MAIL_API_KEY)throw new Error("Mail API key has not been set");let i=h(),{subject:a,html:c}=await f(t,e),m={attachments:r,bcc:n?.bcc,cc:n?.cc,from:i,html:c,subject:a,to:o};return process.env.APP_ENV==="production"?b(m):M(m)}
2
- export{A as createMail,f as getMail,E as sendMail};//# sourceMappingURL=index.js.map
1
+ import l from'@sendgrid/mail';import u from'stream';function A(t,e){return {subject:t,template:e}}async function p(t){let e=(await import('react-dom/server')).default;return new Promise(s=>{let n=new u.Writable,r="";function o(c,m,g){r+=c.toString(),g();}n._write=o;let{pipe:a}=e.renderToPipeableStream(t,{onShellReady:()=>{a(n),s(r);}});})}async function f(t,e){let{subject:s,template:n}=t,r=await n(e),o=await p(r);return {subject:s,html:o}}function h(){if(!process.env.MAIL_FROM)throw new Error("Mail from address has not been set");let t=/^(?<name>[^<]+)<(?<email>[^>]+)>$/u.exec(process.env.MAIL_FROM);if(!t?.groups?.name||!t?.groups?.email)throw new Error('Mail from address is not the correct format. It should be "Name <email>".');return {email:t.groups.email.trim(),name:t.groups.name.trim()}}function i(t){return t?Array.isArray(t)?t.map(e=>({email:e})):[{email:t}]:[]}async function M(t){if(!process.env.MAIL_API_KEY)throw new Error("Mail API key has not been set");let[e,s]=process.env.MAIL_API_KEY.split("."),n=Array.isArray(t.to)?t.to.map(r=>({email:r})):[{email:t.to}];try{return (await(await fetch(`https://sandbox.api.mailtrap.io/api/send/${e}`,{method:"POST",headers:{"Api-Token":s,"Content-Type":"application/json"},body:JSON.stringify({attachments:t.attachments,bcc:i(t.bcc),cc:i(t.cc),from:t.from,html:t.html,subject:t.subject,to:n})})).json()).success}catch{return !1}}async function b(t){if(!process.env.MAIL_API_KEY)throw new Error("Mail API key has not been set");l.setApiKey(process.env.MAIL_API_KEY);let e=await l.send({attachments:t.attachments,bcc:i(t.bcc),cc:i(t.cc),from:t.from,html:t.html,to:i(t.to),subject:t.subject});if(!e[0].statusCode.toString().startsWith("2"))throw new Error(`Mail not sent. ${JSON.stringify(e)}`);return !0}async function y(t,e,s,n,r){let o=h(),{subject:a,html:c}=await f(t,e),m={attachments:r,bcc:n?.bcc,cc:n?.cc,from:o,html:c,subject:a,to:s};return process.env.MAIL_ENABLE_PRODUCTION==="true"||process.env.MAIL_ENABLE_PRODUCTION==="1"?b(m):M(m)}
2
+ export{A as createMail,f as getMail,y as sendMail};//# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/mail/MailService.ts"],"names":["createMail","subject","template","renderMail","element","ReactDOMServer","resolve","ws","stream","content","write","chunk","enc","next","pipe","getMail","mail","data","html","getSenderDetails","matches","transformEmailData","emails","email","sendDevelopmentMail","sendObject","id","key","to","sendProductionMail","sgMail","response","sendMail","options","attachments","from"],"mappings":"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","file":"index.js","sourcesContent":["import sgMail from '@sendgrid/mail';\n\nimport stream from 'node:stream';\n\nexport interface MailObject<T extends object> {\n subject: string;\n template: (data: T) => Promise<React.ReactElement> | React.ReactElement;\n}\n\nexport function createMail<T extends object>(\n subject: string,\n template: (data: T) => Promise<React.ReactElement> | React.ReactElement\n): MailObject<T> {\n return { subject, template };\n}\n\nasync function renderMail(element: React.ReactElement): Promise<string> {\n const ReactDOMServer = (await import('react-dom/server')).default;\n\n return new Promise((resolve) => {\n const ws = new stream.Writable();\n let content = '';\n\n function write<T extends { toString: () => string }>(\n chunk: T,\n enc: BufferEncoding,\n next: (error?: Error | null) => void\n ): void {\n content += chunk.toString();\n next();\n }\n\n ws._write = write; // eslint-disable-line no-underscore-dangle\n\n const { pipe } = ReactDOMServer.renderToPipeableStream(element, {\n onShellReady: () => {\n pipe(ws);\n resolve(content);\n },\n });\n });\n}\n\nexport async function getMail<T extends object>(\n mail: MailObject<T>,\n data: T\n): Promise<{ subject: string; html: string }> {\n const { subject, template } = mail;\n\n const element = await template(data);\n const html = await renderMail(element);\n\n return {\n subject,\n html,\n };\n}\n\nfunction getSenderDetails(): { email: string; name: string } {\n if (!process.env.MAIL_FROM) {\n throw new Error('Mail from address has not been set');\n }\n\n const matches = /^(?<name>[^<]+)<(?<email>[^>]+)>$/u.exec(process.env.MAIL_FROM);\n\n if (!matches?.groups?.name || !matches?.groups?.email) {\n throw new Error(\n 'Mail from address is not the correct format. It should be \"Name <email>\".'\n );\n }\n\n return {\n email: matches.groups.email.trim(),\n name: matches.groups.name.trim(),\n };\n}\n\nfunction transformEmailData(emails?: string[] | string): { email: string }[] {\n if (!emails) {\n return [];\n }\n return Array.isArray(emails) ? emails.map((email) => ({ email })) : [{ email: emails }];\n}\n\ninterface SendMailObject {\n attachments?: { content: string; filename: string; type: string }[];\n bcc?: string[] | string;\n cc?: string[] | string;\n from: { email: string; name: string };\n html: string;\n subject: string;\n to: string[] | string;\n}\n\nasync function sendDevelopmentMail(sendObject: SendMailObject): Promise<boolean> {\n if (!process.env.MAIL_API_KEY) {\n throw new Error('Mail API key has not been set');\n }\n\n /*\n * The account id and api key are both in the MAIL_API_KEY variable, separated by a `.`. We need\n * to split them.\n */\n\n const [id, key] = process.env.MAIL_API_KEY.split('.');\n\n const to = Array.isArray(sendObject.to)\n ? sendObject.to.map((email) => ({ email }))\n : [{ email: sendObject.to }];\n\n try {\n const response = await fetch(`https://sandbox.api.mailtrap.io/api/send/${id}`, {\n method: 'POST',\n headers: { 'Api-Token': key, 'Content-Type': 'application/json' },\n body: JSON.stringify({\n attachments: sendObject.attachments,\n bcc: transformEmailData(sendObject.bcc),\n cc: transformEmailData(sendObject.cc),\n from: sendObject.from,\n html: sendObject.html,\n subject: sendObject.subject,\n to,\n }),\n });\n const json = (await response.json()) as { success: boolean };\n return json.success;\n } catch (err) {\n return false;\n }\n}\n\nasync function sendProductionMail(sendObject: SendMailObject): Promise<boolean> {\n if (process.env.APP_ENV !== 'production') {\n throw new Error('Trying to run production mail in a development environment');\n }\n\n if (!process.env.MAIL_ENABLE_PRODUCTION) {\n throw new Error(\n 'Mail has not been enabled in production. Please add MAIL_ENABLE_PRODUCTION to your environment variables.'\n );\n }\n\n if (!process.env.MAIL_API_KEY) {\n throw new Error('Mail API key has not been set');\n }\n\n sgMail.setApiKey(process.env.MAIL_API_KEY);\n\n const response = await sgMail.send({\n attachments: sendObject.attachments,\n bcc: transformEmailData(sendObject.bcc),\n cc: transformEmailData(sendObject.cc),\n from: sendObject.from,\n html: sendObject.html,\n to: transformEmailData(sendObject.to),\n subject: sendObject.subject,\n });\n\n if (!response[0].statusCode.toString().startsWith('2')) {\n throw new Error(`Mail not sent. ${JSON.stringify(response)}`);\n }\n\n return true;\n}\n\nexport async function sendMail<T extends object>(\n mail: MailObject<T>,\n data: T,\n to: string[] | string,\n options?: { cc?: string[]; bcc?: string[] },\n attachments?: { content: string; filename: string; type: string }[]\n): Promise<boolean> {\n if (!process.env.MAIL_API_KEY) {\n throw new Error('Mail API key has not been set');\n }\n\n const from = getSenderDetails();\n const { subject, html } = await getMail(mail, data);\n\n const sendObject: SendMailObject = {\n attachments,\n bcc: options?.bcc,\n cc: options?.cc,\n from,\n html,\n subject,\n to,\n };\n\n if (process.env.APP_ENV === 'production') {\n return sendProductionMail(sendObject);\n }\n\n return sendDevelopmentMail(sendObject);\n}\n"]}
1
+ {"version":3,"sources":["../../src/mail/MailService.ts"],"names":["createMail","subject","template","renderMail","element","ReactDOMServer","resolve","ws","stream","content","write","chunk","enc","next","pipe","getMail","mail","data","html","getSenderDetails","matches","transformEmailData","emails","email","sendDevelopmentMail","sendObject","id","key","to","sendProductionMail","sgMail","response","sendMail","options","attachments","from"],"mappings":"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","file":"index.js","sourcesContent":["import sgMail from '@sendgrid/mail';\n\nimport stream from 'node:stream';\n\nexport interface MailObject<T extends object> {\n subject: string;\n template: (data: T) => Promise<React.ReactElement> | React.ReactElement;\n}\n\nexport function createMail<T extends object>(\n subject: string,\n template: (data: T) => Promise<React.ReactElement> | React.ReactElement\n): MailObject<T> {\n return { subject, template };\n}\n\nasync function renderMail(element: React.ReactElement): Promise<string> {\n const ReactDOMServer = (await import('react-dom/server')).default;\n\n return new Promise((resolve) => {\n const ws = new stream.Writable();\n let content = '';\n\n function write<T extends { toString: () => string }>(\n chunk: T,\n enc: BufferEncoding,\n next: (error?: Error | null) => void\n ): void {\n content += chunk.toString();\n next();\n }\n\n ws._write = write; // eslint-disable-line no-underscore-dangle\n\n const { pipe } = ReactDOMServer.renderToPipeableStream(element, {\n onShellReady: () => {\n pipe(ws);\n resolve(content);\n },\n });\n });\n}\n\nexport async function getMail<T extends object>(\n mail: MailObject<T>,\n data: T\n): Promise<{ subject: string; html: string }> {\n const { subject, template } = mail;\n\n const element = await template(data);\n const html = await renderMail(element);\n\n return {\n subject,\n html,\n };\n}\n\nfunction getSenderDetails(): { email: string; name: string } {\n if (!process.env.MAIL_FROM) {\n throw new Error('Mail from address has not been set');\n }\n\n const matches = /^(?<name>[^<]+)<(?<email>[^>]+)>$/u.exec(process.env.MAIL_FROM);\n\n if (!matches?.groups?.name || !matches?.groups?.email) {\n throw new Error(\n 'Mail from address is not the correct format. It should be \"Name <email>\".'\n );\n }\n\n return {\n email: matches.groups.email.trim(),\n name: matches.groups.name.trim(),\n };\n}\n\nfunction transformEmailData(emails?: string[] | string): { email: string }[] {\n if (!emails) {\n return [];\n }\n return Array.isArray(emails) ? emails.map((email) => ({ email })) : [{ email: emails }];\n}\n\ninterface SendMailObject {\n attachments?: { content: string; filename: string; type: string }[];\n bcc?: string[] | string;\n cc?: string[] | string;\n from: { email: string; name: string };\n html: string;\n subject: string;\n to: string[] | string;\n}\n\nasync function sendDevelopmentMail(sendObject: SendMailObject): Promise<boolean> {\n if (!process.env.MAIL_API_KEY) {\n throw new Error('Mail API key has not been set');\n }\n\n /*\n * The account id and api key are both in the MAIL_API_KEY variable, separated by a `.`. We need\n * to split them.\n */\n\n const [id, key] = process.env.MAIL_API_KEY.split('.');\n\n const to = Array.isArray(sendObject.to)\n ? sendObject.to.map((email) => ({ email }))\n : [{ email: sendObject.to }];\n\n try {\n const response = await fetch(`https://sandbox.api.mailtrap.io/api/send/${id}`, {\n method: 'POST',\n headers: { 'Api-Token': key, 'Content-Type': 'application/json' },\n body: JSON.stringify({\n attachments: sendObject.attachments,\n bcc: transformEmailData(sendObject.bcc),\n cc: transformEmailData(sendObject.cc),\n from: sendObject.from,\n html: sendObject.html,\n subject: sendObject.subject,\n to,\n }),\n });\n const json = (await response.json()) as { success: boolean };\n return json.success;\n } catch (err) {\n return false;\n }\n}\n\nasync function sendProductionMail(sendObject: SendMailObject): Promise<boolean> {\n if (!process.env.MAIL_API_KEY) {\n throw new Error('Mail API key has not been set');\n }\n\n sgMail.setApiKey(process.env.MAIL_API_KEY);\n\n const response = await sgMail.send({\n attachments: sendObject.attachments,\n bcc: transformEmailData(sendObject.bcc),\n cc: transformEmailData(sendObject.cc),\n from: sendObject.from,\n html: sendObject.html,\n to: transformEmailData(sendObject.to),\n subject: sendObject.subject,\n });\n\n if (!response[0].statusCode.toString().startsWith('2')) {\n throw new Error(`Mail not sent. ${JSON.stringify(response)}`);\n }\n\n return true;\n}\n\nexport async function sendMail<T extends object>(\n mail: MailObject<T>,\n data: T,\n to: string[] | string,\n options?: { cc?: string[]; bcc?: string[] },\n attachments?: { content: string; filename: string; type: string }[]\n): Promise<boolean> {\n const from = getSenderDetails();\n const { subject, html } = await getMail(mail, data);\n\n const sendObject: SendMailObject = {\n attachments,\n bcc: options?.bcc,\n cc: options?.cc,\n from,\n html,\n subject,\n to,\n };\n\n if (\n process.env.MAIL_ENABLE_PRODUCTION === 'true' ||\n process.env.MAIL_ENABLE_PRODUCTION === '1'\n ) {\n return sendProductionMail(sendObject);\n }\n\n return sendDevelopmentMail(sendObject);\n}\n"]}
@@ -1,2 +1,2 @@
1
- 'use strict';var server=require('next/server');var c="/auth/login";function p(e){return e.headers.get("accept")==="application/json"}function r(e,t){return t.headers.set("x-origin",e.nextUrl.origin),t.headers.set("x-pathname",e.nextUrl.pathname),t.headers.set("x-search-params",e.nextUrl.searchParams.toString()),t}function x(e){return e.toString().replace(e.origin,"")}function o(e,t=c){return e.nextUrl.pathname===t?r(e,server.NextResponse.next()):r(e,p(e)?server.NextResponse.json({error:"Unauthorized"},{status:401}):server.NextResponse.redirect(`${e.nextUrl.origin}${t}?r=${encodeURIComponent(x(e.nextUrl))}`))}function l(){let e=new Headers;return process.env.VERCEL_AUTOMATION_BYPASS_SECRET&&e.append("x-vercel-protection-bypass",process.env.VERCEL_AUTOMATION_BYPASS_SECRET),{headers:e}}async function d(e,t){if(e.nextUrl.pathname==="/api/session")return r(e,t?t():server.NextResponse.next());let i=e.cookies.get(process.env.AUTH_COOKIE_NAME||"auth_session")?.value||"";try{let s=await(await fetch(`${e.nextUrl.origin}/api/session?id=${i}&pathname=${e.nextUrl.pathname}`,l())).json();return s.redirect===null?r(e,t?t():server.NextResponse.next()):o(e,s.redirect)}catch{return o(e)}}exports.handleMiddleware=d;//# sourceMappingURL=middleware.cjs.map
1
+ 'use strict';var server=require('next/server');var c="/auth/login";function p(e){return e.headers.get("accept")==="application/json"}function r(e,t){return t.headers.set("x-origin",e.nextUrl.origin),t.headers.set("x-pathname",e.nextUrl.pathname),t.headers.set("x-search-params",e.nextUrl.searchParams.toString()),t}function x(e){return e.toString().replace(e.origin,"")}function l(e){let t=x(e.nextUrl);return t&&t!=="/"?`?r=${encodeURIComponent(t)}`:""}function o(e,t=c){return e.nextUrl.pathname===t?r(e,server.NextResponse.next()):r(e,p(e)?server.NextResponse.json({error:"Unauthorized"},{status:401}):server.NextResponse.redirect(`${e.nextUrl.origin}${t}${l(e)}`))}function R(){let e=new Headers;return process.env.VERCEL_AUTOMATION_BYPASS_SECRET&&e.append("x-vercel-protection-bypass",process.env.VERCEL_AUTOMATION_BYPASS_SECRET),{headers:e}}async function d(e,t){if(e.nextUrl.pathname==="/api/session")return r(e,t?t():server.NextResponse.next());let i=e.cookies.get(process.env.AUTH_COOKIE_NAME||"auth_session")?.value||"";try{let s=await(await fetch(`${e.nextUrl.origin}/api/session?id=${i}&pathname=${e.nextUrl.pathname}`,R())).json();return s.redirect===null?r(e,t?t():server.NextResponse.next()):o(e,s.redirect)}catch{return o(e)}}exports.handleMiddleware=d;//# sourceMappingURL=middleware.cjs.map
2
2
  //# sourceMappingURL=middleware.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/middleware.ts"],"names":["DEFAULT_REDIRECT","isJsonRequest","request","applyHeaders","response","getRelativeUrl","url","redirect","pathname","NextResponse","bypassProtection","headers","handleMiddleware","nextFn","sessionID","json"],"mappings":"+CAGA,IAAMA,CAAAA,CAAmB,cAEzB,SAASC,CAAAA,CAAcC,CAA+B,CAAA,CAClD,OAAOA,CAAAA,CAAQ,QAAQ,GAAI,CAAA,QAAQ,CAAM,GAAA,kBAC7C,CAEA,SAASC,EAAaD,CAAsBE,CAAAA,CAAAA,CAAsC,CAC9E,OAAAA,CAAS,CAAA,OAAA,CAAQ,IAAI,UAAYF,CAAAA,CAAAA,CAAQ,OAAQ,CAAA,MAAM,CACvDE,CAAAA,CAAAA,CAAS,QAAQ,GAAI,CAAA,YAAA,CAAcF,CAAQ,CAAA,OAAA,CAAQ,QAAQ,CAAA,CAC3DE,EAAS,OAAQ,CAAA,GAAA,CAAI,iBAAmBF,CAAAA,CAAAA,CAAQ,OAAQ,CAAA,YAAA,CAAa,UAAU,CAAA,CACxEE,CACX,CAEA,SAASC,CAAAA,CAAeC,EAAqC,CACzD,OAAOA,CAAI,CAAA,QAAA,EAAW,CAAA,OAAA,CAAQA,EAAI,MAAQ,CAAA,EAAE,CAChD,CAEA,SAASC,CAAAA,CAASL,EAAsBM,CAAWR,CAAAA,CAAAA,CAAgC,CAC/E,OAAIE,CAAQ,CAAA,OAAA,CAAQ,WAAaM,CACtBL,CAAAA,CAAAA,CAAaD,CAASO,CAAAA,mBAAAA,CAAa,IAAK,EAAC,EAG7CN,CACHD,CAAAA,CAAAA,CACAD,CAAcC,CAAAA,CAAO,CACfO,CAAAA,mBAAAA,CAAa,KAAK,CAAE,KAAA,CAAO,cAAe,CAAA,CAAG,CAAE,MAAA,CAAQ,GAAI,CAAC,CAAA,CAC5DA,mBAAa,CAAA,QAAA,CACT,CAAGP,EAAAA,CAAAA,CAAQ,QAAQ,MAAM,CAAA,EAAGM,CAAQ,CAAA,GAAA,EAAM,kBACtCH,CAAAA,CAAAA,CAAeH,EAAQ,OAAO,CAClC,CAAC,CAAA,CACL,CACV,CACJ,CAMA,SAASQ,CAAAA,EAAgC,CACrC,IAAMC,CAAU,CAAA,IAAI,QAEpB,OAAI,OAAA,CAAQ,GAAI,CAAA,+BAAA,EACZA,CAAQ,CAAA,MAAA,CAAO,6BAA8B,OAAQ,CAAA,GAAA,CAAI,+BAA+B,CAAA,CAGrF,CAAE,OAAA,CAAAA,CAAQ,CACrB,CAEA,eAAsBC,CAAAA,CAClBV,CACAW,CAAAA,CAAAA,CACqB,CAErB,GAAIX,CAAAA,CAAQ,OAAQ,CAAA,QAAA,GAAa,cAC7B,CAAA,OAAOC,EAAaD,CAASW,CAAAA,CAAAA,CAASA,CAAO,EAAA,CAAIJ,mBAAa,CAAA,IAAA,EAAM,CAGxE,CAAA,IAAMK,CACFZ,CAAAA,CAAAA,CAAQ,OAAQ,CAAA,GAAA,CAAI,QAAQ,GAAI,CAAA,gBAAA,EAAoB,cAAc,CAAA,EAAG,KAAS,EAAA,EAAA,CAElF,GAAI,CAKA,IAAMa,CAAQ,CAAA,KAAA,CAJE,MAAM,KAAA,CAClB,GAAGb,CAAQ,CAAA,OAAA,CAAQ,MAAM,CAAA,gBAAA,EAAmBY,CAAS,CAAA,UAAA,EAAaZ,EAAQ,OAAQ,CAAA,QAAQ,CAC1FQ,CAAAA,CAAAA,CAAAA,EACJ,CAAA,EAC4B,MAE5B,CAAA,OAAIK,CAAK,CAAA,QAAA,GAAa,IACXZ,CAAAA,CAAAA,CAAaD,EAASW,CAASA,CAAAA,CAAAA,EAAWJ,CAAAA,mBAAAA,CAAa,IAAK,EAAC,EAGjEF,CAASL,CAAAA,CAAAA,CAASa,CAAK,CAAA,QAAQ,CAC1C,CAAA,KAAc,CACV,OAAOR,CAAAA,CAASL,CAAO,CAC3B,CACJ","file":"middleware.cjs","sourcesContent":["import { NextResponse } from 'next/server';\nimport type { NextRequest } from 'next/server';\n\nconst DEFAULT_REDIRECT = '/auth/login';\n\nfunction isJsonRequest(request: NextRequest): boolean {\n return request.headers.get('accept') === 'application/json';\n}\n\nfunction applyHeaders(request: NextRequest, response: NextResponse): NextResponse {\n response.headers.set('x-origin', request.nextUrl.origin);\n response.headers.set('x-pathname', request.nextUrl.pathname);\n response.headers.set('x-search-params', request.nextUrl.searchParams.toString());\n return response;\n}\n\nfunction getRelativeUrl(url: NextRequest['nextUrl']): string {\n return url.toString().replace(url.origin, '');\n}\n\nfunction redirect(request: NextRequest, pathname = DEFAULT_REDIRECT): NextResponse {\n if (request.nextUrl.pathname === pathname) {\n return applyHeaders(request, NextResponse.next());\n }\n\n return applyHeaders(\n request,\n isJsonRequest(request)\n ? NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n : NextResponse.redirect(\n `${request.nextUrl.origin}${pathname}?r=${encodeURIComponent(\n getRelativeUrl(request.nextUrl)\n )}`\n )\n );\n}\n\n/*\n * When deployed to Vercel in a preview environment, we need to bypass the protection when fetching\n * the session from the API.\n */\nfunction bypassProtection(): RequestInit {\n const headers = new Headers();\n\n if (process.env.VERCEL_AUTOMATION_BYPASS_SECRET) {\n headers.append('x-vercel-protection-bypass', process.env.VERCEL_AUTOMATION_BYPASS_SECRET);\n }\n\n return { headers };\n}\n\nexport async function handleMiddleware(\n request: NextRequest,\n nextFn?: () => NextResponse\n): Promise<NextResponse> {\n // If the URL is /api/session, we should just return the response, otherwise we end up in a loop\n if (request.nextUrl.pathname === '/api/session') {\n return applyHeaders(request, nextFn ? nextFn() : NextResponse.next());\n }\n\n const sessionID =\n request.cookies.get(process.env.AUTH_COOKIE_NAME || 'auth_session')?.value || '';\n\n try {\n const session = await fetch(\n `${request.nextUrl.origin}/api/session?id=${sessionID}&pathname=${request.nextUrl.pathname}`,\n bypassProtection()\n );\n const json = (await session.json()) as { redirect: string | null };\n\n if (json.redirect === null) {\n return applyHeaders(request, nextFn ? nextFn() : NextResponse.next());\n }\n\n return redirect(request, json.redirect);\n } catch (err) {\n return redirect(request);\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/middleware.ts"],"names":["DEFAULT_REDIRECT","isJsonRequest","request","applyHeaders","response","getRelativeUrl","url","getRedirectQuery","redirect","pathname","NextResponse","bypassProtection","headers","handleMiddleware","nextFn","sessionID","json"],"mappings":"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","file":"middleware.cjs","sourcesContent":["import { NextResponse } from 'next/server';\nimport type { NextRequest } from 'next/server';\n\nconst DEFAULT_REDIRECT = '/auth/login';\n\nfunction isJsonRequest(request: NextRequest): boolean {\n return request.headers.get('accept') === 'application/json';\n}\n\nfunction applyHeaders(request: NextRequest, response: NextResponse): NextResponse {\n response.headers.set('x-origin', request.nextUrl.origin);\n response.headers.set('x-pathname', request.nextUrl.pathname);\n response.headers.set('x-search-params', request.nextUrl.searchParams.toString());\n return response;\n}\n\nfunction getRelativeUrl(url: NextRequest['nextUrl']): string {\n return url.toString().replace(url.origin, '');\n}\n\nfunction getRedirectQuery(request: NextRequest): string {\n const url = getRelativeUrl(request.nextUrl);\n return url && url !== '/' ? `?r=${encodeURIComponent(url)}` : '';\n}\n\nfunction redirect(request: NextRequest, pathname = DEFAULT_REDIRECT): NextResponse {\n if (request.nextUrl.pathname === pathname) {\n return applyHeaders(request, NextResponse.next());\n }\n\n return applyHeaders(\n request,\n isJsonRequest(request)\n ? NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n : NextResponse.redirect(\n `${request.nextUrl.origin}${pathname}${getRedirectQuery(request)}`\n )\n );\n}\n\n/*\n * When deployed to Vercel in a preview environment, we need to bypass the protection when fetching\n * the session from the API.\n */\nfunction bypassProtection(): RequestInit {\n const headers = new Headers();\n\n if (process.env.VERCEL_AUTOMATION_BYPASS_SECRET) {\n headers.append('x-vercel-protection-bypass', process.env.VERCEL_AUTOMATION_BYPASS_SECRET);\n }\n\n return { headers };\n}\n\nexport async function handleMiddleware(\n request: NextRequest,\n nextFn?: () => NextResponse\n): Promise<NextResponse> {\n // If the URL is /api/session, we should just return the response, otherwise we end up in a loop\n if (request.nextUrl.pathname === '/api/session') {\n return applyHeaders(request, nextFn ? nextFn() : NextResponse.next());\n }\n\n const sessionID =\n request.cookies.get(process.env.AUTH_COOKIE_NAME || 'auth_session')?.value || '';\n\n try {\n const session = await fetch(\n `${request.nextUrl.origin}/api/session?id=${sessionID}&pathname=${request.nextUrl.pathname}`,\n bypassProtection()\n );\n const json = (await session.json()) as { redirect: string | null };\n\n if (json.redirect === null) {\n return applyHeaders(request, nextFn ? nextFn() : NextResponse.next());\n }\n\n return redirect(request, json.redirect);\n } catch (err) {\n return redirect(request);\n }\n}\n"]}
@@ -1,2 +1,2 @@
1
- import {NextResponse}from'next/server';var c="/auth/login";function p(e){return e.headers.get("accept")==="application/json"}function r(e,t){return t.headers.set("x-origin",e.nextUrl.origin),t.headers.set("x-pathname",e.nextUrl.pathname),t.headers.set("x-search-params",e.nextUrl.searchParams.toString()),t}function x(e){return e.toString().replace(e.origin,"")}function o(e,t=c){return e.nextUrl.pathname===t?r(e,NextResponse.next()):r(e,p(e)?NextResponse.json({error:"Unauthorized"},{status:401}):NextResponse.redirect(`${e.nextUrl.origin}${t}?r=${encodeURIComponent(x(e.nextUrl))}`))}function l(){let e=new Headers;return process.env.VERCEL_AUTOMATION_BYPASS_SECRET&&e.append("x-vercel-protection-bypass",process.env.VERCEL_AUTOMATION_BYPASS_SECRET),{headers:e}}async function d(e,t){if(e.nextUrl.pathname==="/api/session")return r(e,t?t():NextResponse.next());let i=e.cookies.get(process.env.AUTH_COOKIE_NAME||"auth_session")?.value||"";try{let s=await(await fetch(`${e.nextUrl.origin}/api/session?id=${i}&pathname=${e.nextUrl.pathname}`,l())).json();return s.redirect===null?r(e,t?t():NextResponse.next()):o(e,s.redirect)}catch{return o(e)}}export{d as handleMiddleware};//# sourceMappingURL=middleware.js.map
1
+ import {NextResponse}from'next/server';var c="/auth/login";function p(e){return e.headers.get("accept")==="application/json"}function r(e,t){return t.headers.set("x-origin",e.nextUrl.origin),t.headers.set("x-pathname",e.nextUrl.pathname),t.headers.set("x-search-params",e.nextUrl.searchParams.toString()),t}function x(e){return e.toString().replace(e.origin,"")}function l(e){let t=x(e.nextUrl);return t&&t!=="/"?`?r=${encodeURIComponent(t)}`:""}function o(e,t=c){return e.nextUrl.pathname===t?r(e,NextResponse.next()):r(e,p(e)?NextResponse.json({error:"Unauthorized"},{status:401}):NextResponse.redirect(`${e.nextUrl.origin}${t}${l(e)}`))}function R(){let e=new Headers;return process.env.VERCEL_AUTOMATION_BYPASS_SECRET&&e.append("x-vercel-protection-bypass",process.env.VERCEL_AUTOMATION_BYPASS_SECRET),{headers:e}}async function d(e,t){if(e.nextUrl.pathname==="/api/session")return r(e,t?t():NextResponse.next());let i=e.cookies.get(process.env.AUTH_COOKIE_NAME||"auth_session")?.value||"";try{let s=await(await fetch(`${e.nextUrl.origin}/api/session?id=${i}&pathname=${e.nextUrl.pathname}`,R())).json();return s.redirect===null?r(e,t?t():NextResponse.next()):o(e,s.redirect)}catch{return o(e)}}export{d as handleMiddleware};//# sourceMappingURL=middleware.js.map
2
2
  //# sourceMappingURL=middleware.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/middleware.ts"],"names":["DEFAULT_REDIRECT","isJsonRequest","request","applyHeaders","response","getRelativeUrl","url","redirect","pathname","NextResponse","bypassProtection","headers","handleMiddleware","nextFn","sessionID","json"],"mappings":"uCAGA,IAAMA,CAAAA,CAAmB,cAEzB,SAASC,CAAAA,CAAcC,CAA+B,CAAA,CAClD,OAAOA,CAAAA,CAAQ,QAAQ,GAAI,CAAA,QAAQ,CAAM,GAAA,kBAC7C,CAEA,SAASC,EAAaD,CAAsBE,CAAAA,CAAAA,CAAsC,CAC9E,OAAAA,CAAS,CAAA,OAAA,CAAQ,IAAI,UAAYF,CAAAA,CAAAA,CAAQ,OAAQ,CAAA,MAAM,CACvDE,CAAAA,CAAAA,CAAS,QAAQ,GAAI,CAAA,YAAA,CAAcF,CAAQ,CAAA,OAAA,CAAQ,QAAQ,CAAA,CAC3DE,EAAS,OAAQ,CAAA,GAAA,CAAI,iBAAmBF,CAAAA,CAAAA,CAAQ,OAAQ,CAAA,YAAA,CAAa,UAAU,CAAA,CACxEE,CACX,CAEA,SAASC,CAAAA,CAAeC,EAAqC,CACzD,OAAOA,CAAI,CAAA,QAAA,EAAW,CAAA,OAAA,CAAQA,EAAI,MAAQ,CAAA,EAAE,CAChD,CAEA,SAASC,CAAAA,CAASL,EAAsBM,CAAWR,CAAAA,CAAAA,CAAgC,CAC/E,OAAIE,CAAQ,CAAA,OAAA,CAAQ,WAAaM,CACtBL,CAAAA,CAAAA,CAAaD,CAASO,CAAAA,YAAAA,CAAa,IAAK,EAAC,EAG7CN,CACHD,CAAAA,CAAAA,CACAD,CAAcC,CAAAA,CAAO,CACfO,CAAAA,YAAAA,CAAa,KAAK,CAAE,KAAA,CAAO,cAAe,CAAA,CAAG,CAAE,MAAA,CAAQ,GAAI,CAAC,CAAA,CAC5DA,YAAa,CAAA,QAAA,CACT,CAAGP,EAAAA,CAAAA,CAAQ,QAAQ,MAAM,CAAA,EAAGM,CAAQ,CAAA,GAAA,EAAM,kBACtCH,CAAAA,CAAAA,CAAeH,EAAQ,OAAO,CAClC,CAAC,CAAA,CACL,CACV,CACJ,CAMA,SAASQ,CAAAA,EAAgC,CACrC,IAAMC,CAAU,CAAA,IAAI,QAEpB,OAAI,OAAA,CAAQ,GAAI,CAAA,+BAAA,EACZA,CAAQ,CAAA,MAAA,CAAO,6BAA8B,OAAQ,CAAA,GAAA,CAAI,+BAA+B,CAAA,CAGrF,CAAE,OAAA,CAAAA,CAAQ,CACrB,CAEA,eAAsBC,CAAAA,CAClBV,CACAW,CAAAA,CAAAA,CACqB,CAErB,GAAIX,CAAAA,CAAQ,OAAQ,CAAA,QAAA,GAAa,cAC7B,CAAA,OAAOC,EAAaD,CAASW,CAAAA,CAAAA,CAASA,CAAO,EAAA,CAAIJ,YAAa,CAAA,IAAA,EAAM,CAGxE,CAAA,IAAMK,CACFZ,CAAAA,CAAAA,CAAQ,OAAQ,CAAA,GAAA,CAAI,QAAQ,GAAI,CAAA,gBAAA,EAAoB,cAAc,CAAA,EAAG,KAAS,EAAA,EAAA,CAElF,GAAI,CAKA,IAAMa,CAAQ,CAAA,KAAA,CAJE,MAAM,KAAA,CAClB,GAAGb,CAAQ,CAAA,OAAA,CAAQ,MAAM,CAAA,gBAAA,EAAmBY,CAAS,CAAA,UAAA,EAAaZ,EAAQ,OAAQ,CAAA,QAAQ,CAC1FQ,CAAAA,CAAAA,CAAAA,EACJ,CAAA,EAC4B,MAE5B,CAAA,OAAIK,CAAK,CAAA,QAAA,GAAa,IACXZ,CAAAA,CAAAA,CAAaD,EAASW,CAASA,CAAAA,CAAAA,EAAWJ,CAAAA,YAAAA,CAAa,IAAK,EAAC,EAGjEF,CAASL,CAAAA,CAAAA,CAASa,CAAK,CAAA,QAAQ,CAC1C,CAAA,KAAc,CACV,OAAOR,CAAAA,CAASL,CAAO,CAC3B,CACJ","file":"middleware.js","sourcesContent":["import { NextResponse } from 'next/server';\nimport type { NextRequest } from 'next/server';\n\nconst DEFAULT_REDIRECT = '/auth/login';\n\nfunction isJsonRequest(request: NextRequest): boolean {\n return request.headers.get('accept') === 'application/json';\n}\n\nfunction applyHeaders(request: NextRequest, response: NextResponse): NextResponse {\n response.headers.set('x-origin', request.nextUrl.origin);\n response.headers.set('x-pathname', request.nextUrl.pathname);\n response.headers.set('x-search-params', request.nextUrl.searchParams.toString());\n return response;\n}\n\nfunction getRelativeUrl(url: NextRequest['nextUrl']): string {\n return url.toString().replace(url.origin, '');\n}\n\nfunction redirect(request: NextRequest, pathname = DEFAULT_REDIRECT): NextResponse {\n if (request.nextUrl.pathname === pathname) {\n return applyHeaders(request, NextResponse.next());\n }\n\n return applyHeaders(\n request,\n isJsonRequest(request)\n ? NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n : NextResponse.redirect(\n `${request.nextUrl.origin}${pathname}?r=${encodeURIComponent(\n getRelativeUrl(request.nextUrl)\n )}`\n )\n );\n}\n\n/*\n * When deployed to Vercel in a preview environment, we need to bypass the protection when fetching\n * the session from the API.\n */\nfunction bypassProtection(): RequestInit {\n const headers = new Headers();\n\n if (process.env.VERCEL_AUTOMATION_BYPASS_SECRET) {\n headers.append('x-vercel-protection-bypass', process.env.VERCEL_AUTOMATION_BYPASS_SECRET);\n }\n\n return { headers };\n}\n\nexport async function handleMiddleware(\n request: NextRequest,\n nextFn?: () => NextResponse\n): Promise<NextResponse> {\n // If the URL is /api/session, we should just return the response, otherwise we end up in a loop\n if (request.nextUrl.pathname === '/api/session') {\n return applyHeaders(request, nextFn ? nextFn() : NextResponse.next());\n }\n\n const sessionID =\n request.cookies.get(process.env.AUTH_COOKIE_NAME || 'auth_session')?.value || '';\n\n try {\n const session = await fetch(\n `${request.nextUrl.origin}/api/session?id=${sessionID}&pathname=${request.nextUrl.pathname}`,\n bypassProtection()\n );\n const json = (await session.json()) as { redirect: string | null };\n\n if (json.redirect === null) {\n return applyHeaders(request, nextFn ? nextFn() : NextResponse.next());\n }\n\n return redirect(request, json.redirect);\n } catch (err) {\n return redirect(request);\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/middleware.ts"],"names":["DEFAULT_REDIRECT","isJsonRequest","request","applyHeaders","response","getRelativeUrl","url","getRedirectQuery","redirect","pathname","NextResponse","bypassProtection","headers","handleMiddleware","nextFn","sessionID","json"],"mappings":"uCAGA,IAAMA,CAAAA,CAAmB,aAEzB,CAAA,SAASC,CAAcC,CAAAA,CAAAA,CAA+B,CAClD,OAAOA,CAAQ,CAAA,OAAA,CAAQ,IAAI,QAAQ,CAAA,GAAM,kBAC7C,CAEA,SAASC,CAAAA,CAAaD,CAAsBE,CAAAA,CAAAA,CAAsC,CAC9E,OAAAA,CAAS,CAAA,OAAA,CAAQ,GAAI,CAAA,UAAA,CAAYF,EAAQ,OAAQ,CAAA,MAAM,CACvDE,CAAAA,CAAAA,CAAS,OAAQ,CAAA,GAAA,CAAI,YAAcF,CAAAA,CAAAA,CAAQ,OAAQ,CAAA,QAAQ,CAC3DE,CAAAA,CAAAA,CAAS,OAAQ,CAAA,GAAA,CAAI,kBAAmBF,CAAQ,CAAA,OAAA,CAAQ,YAAa,CAAA,QAAA,EAAU,CAAA,CACxEE,CACX,CAEA,SAASC,CAAAA,CAAeC,CAAqC,CAAA,CACzD,OAAOA,CAAAA,CAAI,UAAW,CAAA,OAAA,CAAQA,CAAI,CAAA,MAAA,CAAQ,EAAE,CAChD,CAEA,SAASC,CAAiBL,CAAAA,CAAAA,CAA8B,CACpD,IAAMI,CAAMD,CAAAA,CAAAA,CAAeH,EAAQ,OAAO,CAAA,CAC1C,OAAOI,CAAAA,EAAOA,CAAQ,GAAA,GAAA,CAAM,CAAM,GAAA,EAAA,kBAAA,CAAmBA,CAAG,CAAC,CAAK,CAAA,CAAA,EAClE,CAEA,SAASE,EAASN,CAAsBO,CAAAA,CAAAA,CAAWT,CAAgC,CAAA,CAC/E,OAAIE,CAAAA,CAAQ,OAAQ,CAAA,QAAA,GAAaO,CACtBN,CAAAA,CAAAA,CAAaD,CAASQ,CAAAA,YAAAA,CAAa,IAAK,EAAC,CAG7CP,CAAAA,CAAAA,CACHD,CACAD,CAAAA,CAAAA,CAAcC,CAAO,CAAA,CACfQ,YAAa,CAAA,IAAA,CAAK,CAAE,KAAA,CAAO,cAAe,CAAA,CAAG,CAAE,MAAA,CAAQ,GAAI,CAAC,EAC5DA,YAAa,CAAA,QAAA,CACT,CAAGR,EAAAA,CAAAA,CAAQ,OAAQ,CAAA,MAAM,CAAGO,EAAAA,CAAQ,CAAGF,EAAAA,CAAAA,CAAiBL,CAAO,CAAC,CACpE,CAAA,CACV,CACJ,CAMA,SAASS,CAAgC,EAAA,CACrC,IAAMC,CAAAA,CAAU,IAAI,OAAA,CAEpB,OAAI,OAAA,CAAQ,GAAI,CAAA,+BAAA,EACZA,CAAQ,CAAA,MAAA,CAAO,6BAA8B,OAAQ,CAAA,GAAA,CAAI,+BAA+B,CAAA,CAGrF,CAAE,OAAA,CAAAA,CAAQ,CACrB,CAEA,eAAsBC,CAClBX,CAAAA,CAAAA,CACAY,CACqB,CAAA,CAErB,GAAIZ,CAAQ,CAAA,OAAA,CAAQ,QAAa,GAAA,cAAA,CAC7B,OAAOC,CAAAA,CAAaD,CAASY,CAAAA,CAAAA,CAASA,CAAO,EAAA,CAAIJ,YAAa,CAAA,IAAA,EAAM,CAAA,CAGxE,IAAMK,CACFb,CAAAA,CAAAA,CAAQ,OAAQ,CAAA,GAAA,CAAI,OAAQ,CAAA,GAAA,CAAI,gBAAoB,EAAA,cAAc,CAAG,EAAA,KAAA,EAAS,EAElF,CAAA,GAAI,CAKA,IAAMc,EAAQ,KAJE,CAAA,MAAM,KAClB,CAAA,CAAA,EAAGd,CAAQ,CAAA,OAAA,CAAQ,MAAM,CAAA,gBAAA,EAAmBa,CAAS,CAAA,UAAA,EAAab,CAAQ,CAAA,OAAA,CAAQ,QAAQ,CAAA,CAAA,CAC1FS,GACJ,CAAA,EAC4B,IAAK,EAAA,CAEjC,OAAIK,CAAAA,CAAK,QAAa,GAAA,IAAA,CACXb,CAAaD,CAAAA,CAAAA,CAASY,CAASA,CAAAA,CAAAA,EAAWJ,CAAAA,YAAAA,CAAa,IAAK,EAAC,CAGjEF,CAAAA,CAAAA,CAASN,CAASc,CAAAA,CAAAA,CAAK,QAAQ,CAC1C,CAAc,KAAA,CACV,OAAOR,CAAAA,CAASN,CAAO,CAC3B,CACJ","file":"middleware.js","sourcesContent":["import { NextResponse } from 'next/server';\nimport type { NextRequest } from 'next/server';\n\nconst DEFAULT_REDIRECT = '/auth/login';\n\nfunction isJsonRequest(request: NextRequest): boolean {\n return request.headers.get('accept') === 'application/json';\n}\n\nfunction applyHeaders(request: NextRequest, response: NextResponse): NextResponse {\n response.headers.set('x-origin', request.nextUrl.origin);\n response.headers.set('x-pathname', request.nextUrl.pathname);\n response.headers.set('x-search-params', request.nextUrl.searchParams.toString());\n return response;\n}\n\nfunction getRelativeUrl(url: NextRequest['nextUrl']): string {\n return url.toString().replace(url.origin, '');\n}\n\nfunction getRedirectQuery(request: NextRequest): string {\n const url = getRelativeUrl(request.nextUrl);\n return url && url !== '/' ? `?r=${encodeURIComponent(url)}` : '';\n}\n\nfunction redirect(request: NextRequest, pathname = DEFAULT_REDIRECT): NextResponse {\n if (request.nextUrl.pathname === pathname) {\n return applyHeaders(request, NextResponse.next());\n }\n\n return applyHeaders(\n request,\n isJsonRequest(request)\n ? NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n : NextResponse.redirect(\n `${request.nextUrl.origin}${pathname}${getRedirectQuery(request)}`\n )\n );\n}\n\n/*\n * When deployed to Vercel in a preview environment, we need to bypass the protection when fetching\n * the session from the API.\n */\nfunction bypassProtection(): RequestInit {\n const headers = new Headers();\n\n if (process.env.VERCEL_AUTOMATION_BYPASS_SECRET) {\n headers.append('x-vercel-protection-bypass', process.env.VERCEL_AUTOMATION_BYPASS_SECRET);\n }\n\n return { headers };\n}\n\nexport async function handleMiddleware(\n request: NextRequest,\n nextFn?: () => NextResponse\n): Promise<NextResponse> {\n // If the URL is /api/session, we should just return the response, otherwise we end up in a loop\n if (request.nextUrl.pathname === '/api/session') {\n return applyHeaders(request, nextFn ? nextFn() : NextResponse.next());\n }\n\n const sessionID =\n request.cookies.get(process.env.AUTH_COOKIE_NAME || 'auth_session')?.value || '';\n\n try {\n const session = await fetch(\n `${request.nextUrl.origin}/api/session?id=${sessionID}&pathname=${request.nextUrl.pathname}`,\n bypassProtection()\n );\n const json = (await session.json()) as { redirect: string | null };\n\n if (json.redirect === null) {\n return applyHeaders(request, nextFn ? nextFn() : NextResponse.next());\n }\n\n return redirect(request, json.redirect);\n } catch (err) {\n return redirect(request);\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sqrzro/server",
3
- "version": "2.0.0-bz.65",
3
+ "version": "2.0.0-bz.67",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",