authhero 0.143.0 → 0.144.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/authhero.cjs CHANGED
@@ -26,7 +26,7 @@
26
26
  }};
27
27
  <\/script>
28
28
  </body>
29
- </html>`;return new Response(i,{headers:{"Content-Type":"text/html"}})}async function d2(t,e,n,r,i){var m,w,h;if(!n.redirect_uri)throw new A(400,{message:"Missing redirect_uri in authParams"});if(!r.email)throw new A(400,{message:"Missing email in user"});const[o]=await t.env.data.keys.list();if(!o)throw new A(500,{message:"No signing key found"});if(!((m=e.addons)!=null&&m.samlp))throw new A(400,{message:`SAML Addon is not enabled for client ${e.id}`});const{recipient:a,audience:c}=e.addons.samlp,d=n.state||"";if(!a||!d||!r||!n.state)throw new A(400,{message:"Missing recipient or inResponseTo"});const l=JSON.parse(n.state),u=new URL(n.redirect_uri),f=await l2(t,{issuer:t.env.ISSUER,audience:c||n.client_id,destination:u.toString(),inResponseTo:l.requestId,userId:((h=(w=r.app_metadata)==null?void 0:w.vimeo)==null?void 0:h.user_id)||r.user_id,email:r.email,sessionIndex:i,signature:{privateKeyPem:o.pkcs7,cert:o.cert,kid:o.kid}});return c2(u.toString(),f,l.relayState)}async function l2(t,e){const n=e.notBefore||new Date().toISOString(),r=e.notAfter||new Date(new Date(n).getTime()+10*60*1e3).toISOString(),i=e.issueInstant||n,o=e.sessionNotOnOrAfter||r,a=e.responseId||`_${Ee()}`,c=e.assertionId||`_${Ee()}`,d=[{"samlp:Response":[{"saml:Issuer":[{"#text":e.issuer}]},{"samlp:Status":[{"samlp:StatusCode":[],":@":{"@_Value":"urn:oasis:names:tc:SAML:2.0:status:Success"}}]},{"saml:Assertion":[{"saml:Issuer":[{"#text":e.issuer}]},{"saml:Subject":[{"saml:NameID":[{"#text":e.email}],":@":{"@_Format":"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"}},{"saml:SubjectConfirmation":[{"saml:SubjectConfirmationData":[],":@":{"@_InResponseTo":e.inResponseTo,"@_NotOnOrAfter":r,"@_Recipient":e.destination}}],":@":{"@_Method":"urn:oasis:names:tc:SAML:2.0:cm:bearer"}}]},{"saml:Conditions":[{"saml:AudienceRestriction":[{"saml:Audience":[{"#text":e.audience}]}]}],":@":{"@_NotBefore":n,"@_NotOnOrAfter":r}},{"saml:AuthnStatement":[{"saml:AuthnContext":[{"saml:AuthnContextClassRef":[{"#text":"urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified"}]}]}],":@":{"@_AuthnInstant":i,"@_SessionIndex":e.sessionIndex,"@_SessionNotOnOrAfter":o}},{"saml:AttributeStatement":[{"saml:Attribute":[{"saml:AttributeValue":[{"#text":e.userId}],":@":{"@_xmlns:xs":"http://www.w3.org/2001/XMLSchema","@_xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance","@_xsi:type":"xs:string"}}],":@":{"@_FriendlyName":"persistent","@_Name":"id","@_NameFormat":"urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"}},{"saml:Attribute":[{"saml:AttributeValue":[{"#text":e.email}],":@":{"@_xmlns:xs":"http://www.w3.org/2001/XMLSchema","@_xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance","@_xsi:type":"xs:string"}}],":@":{"@_Name":"email","@_NameFormat":"urn:oasis:names:tc:SAML:2.0:attrname-format:basic"}},{"saml:Attribute":[{"saml:AttributeValue":[{"#text":"manage-account"}],":@":{"@_xmlns:xs":"http://www.w3.org/2001/XMLSchema","@_xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance","@_xsi:type":"xs:string"}}],":@":{"@_Name":"Role","@_NameFormat":"urn:oasis:names:tc:SAML:2.0:attrname-format:basic"}},{"saml:Attribute":[{"saml:AttributeValue":[{"#text":"default-roles-master"}],":@":{"@_xmlns:xs":"http://www.w3.org/2001/XMLSchema","@_xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance","@_xsi:type":"xs:string"}}],":@":{"@_Name":"Role","@_NameFormat":"urn:oasis:names:tc:SAML:2.0:attrname-format:basic"}},{"saml:Attribute":[{"saml:AttributeValue":[{"#text":"offline_access"}],":@":{"@_xmlns:xs":"http://www.w3.org/2001/XMLSchema","@_xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance","@_xsi:type":"xs:string"}}],":@":{"@_Name":"Role","@_NameFormat":"urn:oasis:names:tc:SAML:2.0:attrname-format:basic"}},{"saml:Attribute":[{"saml:AttributeValue":[{"#text":"view-profile"}],":@":{"@_xmlns:xs":"http://www.w3.org/2001/XMLSchema","@_xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance","@_xsi:type":"xs:string"}}],":@":{"@_Name":"Role","@_NameFormat":"urn:oasis:names:tc:SAML:2.0:attrname-format:basic"}},{"saml:Attribute":[{"saml:AttributeValue":[{"#text":"uma_authorization"}],":@":{"@_xmlns:xs":"http://www.w3.org/2001/XMLSchema","@_xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance","@_xsi:type":"xs:string"}}],":@":{"@_Name":"Role","@_NameFormat":"urn:oasis:names:tc:SAML:2.0:attrname-format:basic"}},{"saml:Attribute":[{"saml:AttributeValue":[{"#text":"manage-account-links"}],":@":{"@_xmlns:xs":"http://www.w3.org/2001/XMLSchema","@_xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance","@_xsi:type":"xs:string"}}],":@":{"@_Name":"Role","@_NameFormat":"urn:oasis:names:tc:SAML:2.0:attrname-format:basic"}}]}],":@":{"@_xmlns":"urn:oasis:names:tc:SAML:2.0:assertion","@_ID":c,"@_IssueInstant":i,"@_Version":"2.0"}}],":@":{"@_xmlns:samlp":"urn:oasis:names:tc:SAML:2.0:protocol","@_xmlns:saml":"urn:oasis:names:tc:SAML:2.0:assertion","@_Destination":e.destination,"@_ID":a,"@_InResponseTo":e.inResponseTo,"@_IssueInstant":i,"@_Version":"2.0"}}];let u=new a2.XMLBuilder({ignoreAttributes:!1,suppressEmptyNode:!0,preserveOrder:!0}).build(d);if(e.signature){const m=await fetch(t.env.SAML_SIGN_URL,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({xmlContent:u,privateKey:e.signature.privateKeyPem,publicCert:e.signature.cert})});if(!m.ok)throw new Error(`Failed to sign SAML response: ${m.status}`);u=await m.text()}return e.encode===!1?u:btoa(u)}var u2={deno:"Deno",bun:"Bun",workerd:"Cloudflare-Workers",node:"Node.js"},p2=()=>{var n,r;const t=globalThis;if(typeof navigator<"u"&&typeof navigator.userAgent=="string"){for(const[i,o]of Object.entries(u2))if(f2(o))return i}return typeof(t==null?void 0:t.EdgeRuntime)=="string"?"edge-light":(t==null?void 0:t.fastly)!==void 0?"fastly":((r=(n=t==null?void 0:t.process)==null?void 0:n.release)==null?void 0:r.name)==="node"?"node":"other"},f2=t=>navigator.userAgent.startsWith(t);function It(t,e){p2()==="workerd"&&t.executionCtx.waitUntil(e)}function Xt(t){var e,n,r,i;return{auth0Client:(e=t.query("auth0Client"))==null?void 0:e.slice(0,255),ip:(n=t.header("x-real-ip"))==null?void 0:n.slice(0,45),useragent:(r=t.header("user-agent"))==null?void 0:r.slice(0,512),countryCode:(i=t.header("cf-ipcountry"))==null?void 0:i.slice(0,2)}}const Bu=["sub","iss","aud","exp","nbf","iat","jti"];async function Ss(t,e){var v,x;const{authParams:n,user:r,client:i,session_id:o}=e,c=(await t.env.data.keys.list()).filter(z=>!z.revoked_at||new Date(z.revoked_at)>new Date),d=c[c.length-1];if(!(d!=null&&d.pkcs7))throw new A(500,{message:"No signing key available"});const l=O_(d.pkcs7),u=t.var.custom_domain?`https://${t.var.custom_domain}/`:t.env.ISSUER,f={aud:n.audience||"default",scope:n.scope||"",sub:(r==null?void 0:r.user_id)||n.client_id,iss:u,tenant_id:t.var.tenant_id,sid:o},m=r&&((v=n.scope)!=null&&v.split(" ").includes("openid"))?{aud:n.client_id,sub:r.user_id,iss:u,sid:o,nonce:n.nonce,given_name:r.given_name,family_name:r.family_name,nickname:r.nickname,picture:r.picture,locale:r.locale,name:r.name,email:r.email,email_verified:r.email_verified}:void 0;(x=t.env.hooks)!=null&&x.onExecuteCredentialsExchange&&await t.env.hooks.onExecuteCredentialsExchange({client:i,user:r,request:{ip:t.req.header("x-real-ip")||"",user_agent:t.req.header("user-agent")||"",method:t.req.method,url:t.req.url},scope:n.scope||"",grant_type:""},{accessToken:{setCustomClaim:(z,O)=>{if(Bu.includes(z))throw new Error(`Cannot overwrite reserved claim '${z}'`);f[z]=O}},idToken:{setCustomClaim:(z,O)=>{if(Bu.includes(z))throw new Error(`Cannot overwrite reserved claim '${z}'`);m&&(m[z]=O)}},access:{deny:z=>{throw new A(400,{message:`Access denied: ${z}`})}}});const w={includeIssuedTimestamp:!0,expiresIn:new qd(1,"d"),headers:{kid:d.kid}},h=await Cu("RS256",l,f,w),y=m?await Cu("RS256",l,m,w):void 0;return{access_token:h,refresh_token:e.refresh_token,id_token:y,token_type:"Bearer",expires_in:86400}}async function y0(t,e){return{code:(await t.env.data.codes.create(e.client.tenant.id,{code_id:Ee(),user_id:e.user.user_id,code_type:"authorization_code",login_id:e.login_id,expires_at:new Date(Date.now()+B_*1e3).toISOString()})).code_id,state:e.authParams.state}}async function h2(t,e){const{client:n,scope:r,audience:i=n.tenant.audience,session_id:o}=e,a=Xt(t.req);return await t.env.data.refreshTokens.create(n.tenant.id,{id:Ee(),session_id:o,client_id:n.id,idle_expires_at:new Date(Date.now()+xs*1e3).toISOString(),user_id:e.user.user_id,device:{last_ip:a.ip||"",initial_ip:a.ip||"",last_user_agent:a.useragent||"",initial_user_agent:a.useragent||"",initial_asn:"",last_asn:""},resource_servers:[{audience:i,scopes:r}],rotating:!1})}async function w0(t,{user:e,client:n,loginSession:r}){const i=await t.env.data.sessions.create(n.tenant.id,{id:Ee(),user_id:e.user_id,idle_expires_at:new Date(Date.now()+xs*1e3).toISOString(),device:{last_ip:t.req.header("x-real-ip")||"",initial_ip:t.req.header("x-real-ip")||"",last_user_agent:t.req.header("user-agent")||"",initial_user_agent:t.req.header("user-agent")||"",initial_asn:"",last_asn:""},clients:[n.id]});return await t.env.data.loginSessions.update(n.tenant.id,r.id,{session_id:i.id}),i}async function hn(t,e){var h,y;const{authParams:n,user:r,client:i,ticketAuth:o}=e,a=we(t,{type:he.SUCCESS_LOGIN,description:`Successful login for ${r.user_id}`,userId:r.user_id});if(It(t,t.env.data.logs.create(i.tenant.id,a)),It(t,t.env.data.users.update(i.tenant.id,r.user_id,{last_login:new Date().toISOString(),last_ip:t.req.header("x-real-ip")||"",login_count:r.login_count+1})),o){if(!e.loginSession)throw new A(500,{message:"Login session not found for ticket auth."});const v=j_(),x=Ee(12),z=await t.env.data.codes.create(i.tenant.id,{code_id:Ee(),code_type:"ticket",login_id:e.loginSession.id,expires_at:new Date(Date.now()+U_).toISOString(),code_verifier:[x,v].join("|")});return t.json({login_ticket:z.code_id,co_verifier:v,co_id:x})}let c=e.refreshToken,d=e.sessionId,l=r;if(!d&&((h=e.loginSession)!=null&&h.session_id)){d=e.loginSession.session_id;const v=await t.env.data.sessions.get(i.tenant.id,d);v&&!v.clients.includes(i.id)&&await t.env.data.sessions.update(i.tenant.id,d,{clients:[...v.clients,i.id]}),!c&&((y=n.scope)!=null&&y.split(" ").includes("offline_access"))&&(c=(await h2(t,{user:l,client:i,session_id:d,scope:n.scope,audience:n.audience})).id)}else if(!d){if(!e.loginSession)throw new A(500,{message:"Login session not found for creating a new session."});const v=await b2(t,t.env.data,i.tenant.id,r,e.loginSession,{client:i,authParams:n});if(v instanceof Response)return v;l=v,d=(await w0(t,{user:l,client:i,loginSession:e.loginSession})).id}if(e.authParams.response_mode===Ft.SAML_POST){if(!d)throw new A(500,{message:"Session ID not available for SAML response"});return d2(t,e.client,e.authParams,l,d)}const u=await Ss(t,{authParams:n,user:l,client:i,session_id:d,refresh_token:c});if(n.response_mode===Ft.WEB_MESSAGE){if(d){const v=nc(i.tenant.id,d,t.var.custom_domain||t.req.header("host")||"");v&&t.header("set-cookie",v)}else console.warn("Session ID not available for WEB_MESSAGE, cookie will not be set.");return u}const f=new Headers;if(d){const v=nc(i.tenant.id,d,t.var.custom_domain||t.req.header("host")||"");v&&f.set("set-cookie",v)}const m=n.response_type||it.CODE;if(m===it.CODE){const v=await y0(t,{user:l,client:i,authParams:n,login_id:d});if(!n.redirect_uri)throw new A(400,{message:"Redirect uri not found for code response type."});const x=new URL(n.redirect_uri);return x.searchParams.set("code",v.code),v.state&&x.searchParams.set("state",v.state),f.set("location",x.toString()),new Response("Redirecting",{status:302,headers:f})}if(!n.redirect_uri)throw new A(400,{message:"Redirect uri not found for this response mode."});const w=new URL(n.redirect_uri);if(m===it.TOKEN||m===it.TOKEN_ID_TOKEN)w.hash=new URLSearchParams({access_token:u.access_token,...u.id_token&&{id_token:u.id_token},token_type:u.token_type,expires_in:u.expires_in.toString(),...n.state&&{state:n.state},...n.scope&&{scope:n.scope}}).toString();else throw new A(500,{message:`Unsupported response type ('${m}') for redirect with tokens.`});return f.set("location",w.toString()),new Response("Redirecting",{status:302,headers:f})}async function g2(t,e,n){const r=await t.env.data.tenants.get(e);if(!r)throw new Error(`Tenant not found: ${e}`);return Ss(t,{client:{id:t.env.ISSUER,tenant:r,created_at:new Date().toISOString(),updated_at:new Date().toISOString(),name:t.env.ISSUER,disable_sign_ups:!1,connections:[]},authParams:{client_id:t.env.ISSUER,response_type:it.TOKEN,scope:n}})}async function v0(t,e,n){const r=await g2(t,n.tenant_id,"webhook");for await(const i of e.filter(o=>"url"in o))if(!(await fetch(i.url,{method:"POST",headers:{Authorization:`Bearer ${r.access_token}`,"Content-Type":"application/json"},body:JSON.stringify(n)})).ok){const a=we(t,{type:he.FAILED_HOOK,description:`Failed to invoke hook ${i.hook_id}`});await t.env.data.logs.create(n.tenant_id,a)}}function m2(t){return async(e,n)=>{const{hooks:r}=await t.env.data.hooks.list(e);return await v0(t,r,{tenant_id:e,user:n,trigger_id:"post-user-registration"}),n}}function _2(t){return async(e,n)=>{const{hooks:r}=await t.env.data.hooks.list(e,{q:"trigger_id:pre-user-signup",page:0,per_page:100,include_totals:!1});await v0(t,r,{tenant_id:e,email:n,trigger_id:"pre-user-signup"})}}function Lu(t){return typeof t.form_id=="string"}async function y2(t,e,n){var d;const r=t.env.data,i=t.var.tenant_id||t.req.header("tenant-id");if(!i)throw new A(400,{message:"Missing tenant_id in context"});const o=await r.forms.get(i,e);if(!o)throw new A(404,{message:"Form not found for post-user-login hook"});let a=(d=o.start)==null?void 0:d.next_node;if(!a&&o.nodes&&o.nodes.length>0){const l=o.nodes.find(u=>u.type==="STEP");a=l==null?void 0:l.id}if(!a)throw new A(400,{message:"No start node found in form"});let c=`/u/forms/${o.id}/nodes/${a}?state=${encodeURIComponent(n.id)}`;return new Response(null,{status:302,headers:{location:c}})}function Uu(t){return typeof t.url=="string"}function w2(t,e){return async(n,r)=>{var a,c,d;const i={method:t.req.method,ip:t.req.query("x-real-ip")||"",user_agent:t.req.query("user-agent"),url:((a=t.var.loginSession)==null?void 0:a.authorization_url)||t.req.url};if((c=t.env.hooks)!=null&&c.onExecutePreUserRegistration)try{await t.env.hooks.onExecutePreUserRegistration({user:r,request:i},{user:{setUserMetadata:async(l,u)=>{r[l]=u}}})}catch{const u=we(t,{type:he.FAILED_SIGNUP,description:"Pre user registration hook failed"});await e.logs.create(n,u)}let o=await S_(e)(n,r);if((d=t.env.hooks)!=null&&d.onExecutePostUserRegistration)try{await t.env.hooks.onExecutePostUserRegistration({user:r,request:i},{user:{}})}catch{const u=we(t,{type:he.FAILED_SIGNUP,description:"Post user registration hook failed"});await t.env.data.logs.create(n,u)}return await m2(t)(n,o),o}}async function v2(t,e,n,r){var i;if(e.disable_sign_ups){const o=(i=t.var.loginSession)==null?void 0:i.authorization_url;if(!(o&&new URL(o).searchParams.get("screen_hint")==="signup")&&!await Es({userAdapter:n.users,tenant_id:e.tenant.id,email:r})){const d=we(t,{type:he.FAILED_SIGNUP,description:"Public signup is disabled"});throw await n.logs.create(e.tenant.id,d),new A(400,{message:"Signups are disabled for this client"})}}await _2(t)(t.var.tenant_id||"",r)}function As(t,e){return{...e,users:{...e.users,create:w2(t,e)}}}async function b2(t,e,n,r,i,o){var d;(d=t.env.hooks)!=null&&d.onExecutePostLogin&&(o!=null&&o.client)&&(o!=null&&o.authParams)&&await t.env.hooks.onExecutePostLogin({client:o.client,user:r,request:{ip:t.req.header("x-real-ip")||"",user_agent:t.req.header("user-agent")||"",method:t.req.method,url:t.req.url},scope:o.authParams.scope||"",grant_type:""},{prompt:{render:l=>{}}});const{hooks:a}=await e.hooks.list(n,{q:"trigger_id:post-user-login",page:0,per_page:100,include_totals:!1});if(i){const l=a.find(u=>u.enabled&&Lu(u));if(l&&Lu(l))return y2(t,l.form_id,i)}const c=a.filter(l=>l.enabled&&Uu(l));for(const l of c)if(Uu(l))try{await fetch(l.url,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({tenant_id:n,user:r,trigger_id:"post-user-login"})})}catch{const f=we(t,{type:he.FAILED_HOOK,description:`Failed to invoke post-user-login webhook: ${l.url}`});await e.logs.create(n,f)}return r}function b0(t){return As(t,t.env.data)}async function Xd(t,e,n){return(await t.list(e,{page:0,per_page:10,include_totals:!1,q:`email:${n}`})).users}async function kr({userAdapter:t,tenant_id:e,username:n,provider:r}){const i=r==="sms"?`phone_number:${n}`:`email:${n}`,{users:o}=await t.list(e,{page:0,per_page:10,include_totals:!1,q:`${i} provider:${r}`});return o.length>1&&console.error("More than one user found for same email and provider"),o[0]||null}async function Es({userAdapter:t,tenant_id:e,email:n}){var c;const{users:r}=await t.list(e,{page:0,per_page:10,include_totals:!1,q:`email:${n}`}),i=r.filter(d=>!(d.provider==="auth2"&&!d.email_verified));if(i.length===0)return;const o=i.filter(d=>!d.linked_to);if(o.length>0)return o.length>1&&console.error("More than one primary user found for same email"),o[0];const a=await t.get(e,(c=i[0])==null?void 0:c.linked_to);if(!a)throw new Error("Primary account not found");return a}async function zo({userAdapter:t,tenant_id:e,username:n,provider:r}){const i=await kr({userAdapter:t,tenant_id:e,username:n,provider:r});return i?i.linked_to?t.get(e,i.linked_to):i:null}async function zs(t,e){const{username:n,provider:r,connection:i,client:o,userId:a,isSocial:c,profileData:d={},ip:l=""}=e;let u=await zo({userAdapter:t.env.data.users,tenant_id:e.client.tenant.id,username:n,provider:r});if(!u){const f={user_id:`${r}|${a||$s()}`,email:i!=="sms"?n:void 0,phone_number:i==="sms"?n:void 0,name:n,provider:r,connection:i,email_verified:!0,last_ip:l,is_social:c,last_login:new Date().toISOString(),profileData:JSON.stringify(d)};u=await b0(t).users.create(o.tenant.id,f),t.set("user_id",u.user_id)}return u}const Dt=s.z.object({page:s.z.string().min(0).optional().default("0").transform(t=>parseInt(t,10)).openapi({description:"The page number where 0 is the first page"}),per_page:s.z.string().min(1).optional().default("10").transform(t=>parseInt(t,10)).openapi({description:"The number of items per page"}),include_totals:s.z.string().optional().default("false").transform(t=>t==="true").openapi({description:"If the total number of items should be included in the response"}),sort:s.z.string().regex(/^.+:(-1|1)$/).optional().openapi({description:"A property that should have the format 'string:-1' or 'string:1'"}),q:s.z.string().optional().openapi({description:"A lucene query string used to filter the results"})});function Vn(t){if(!t)return;const[e,n]=t.split(":"),r=n==="1"?"asc":"desc";if(!(!e||!r))return{sort_by:e,sort_order:r}}const Mu=Jt.extend({users:s.z.array(Et)}),$2=Jt.extend({sessions:s.z.array(bs)}),x2=new s.OpenAPIHono().openapi(s.createRoute({tags:["users"],method:"get",path:"/",request:{query:Dt,headers:s.z.object({"tenant-id":s.z.string()})},security:[{Bearer:["auth:read"]}],responses:{200:{content:{"application/json":{schema:s.z.union([s.z.array(Et),Mu])}},description:"List of users"}}}),async t=>{const{page:e,per_page:n,include_totals:r,sort:i,q:o}=t.req.valid("query"),{"tenant-id":a}=t.req.valid("header");if(o!=null&&o.includes("identities.profileData.email")){const u=o.split("=")[1],m=(await t.env.data.users.list(a,{page:e,per_page:n,include_totals:r,q:`email:${u}`})).users.filter(y=>y.linked_to),[w]=m;if(!w)return t.json([]);const h=await t.env.data.users.get(a,w.linked_to);if(!h)throw new A(500,{message:"Primary account not found"});return t.json([Et.parse(h)])}const c=["-_exists_:linked_to"];o&&c.push(o);const d=await t.env.data.users.list(a,{page:e,per_page:n,include_totals:r,sort:Vn(i),q:c.join(" ")}),l=d.users.filter(u=>!u.linked_to);return r?t.json(Mu.parse({users:l,length:d.length,start:d.start,limit:d.limit})):t.json(s.z.array(Et).parse(l))}).openapi(s.createRoute({tags:["users"],method:"get",path:"/{user_id}",request:{headers:s.z.object({"tenant-id":s.z.string()}),params:s.z.object({user_id:s.z.string()})},security:[{Bearer:["auth:read"]}],responses:{200:{content:{"application/json":{schema:Et}},description:"List of users"}}}),async t=>{const{user_id:e}=t.req.valid("param"),{"tenant-id":n}=t.req.valid("header"),r=await t.env.data.users.get(n,e);if(!r)throw new A(404);if(r.linked_to)throw new A(404,{message:"User is linked to another user"});return t.json(r)}).openapi(s.createRoute({tags:["users"],method:"delete",path:"/{user_id}",request:{headers:s.z.object({"tenant-id":s.z.string()}),params:s.z.object({user_id:s.z.string()})},security:[{Bearer:["auth:write"]}],responses:{200:{description:"Status"}}}),async t=>{const{user_id:e}=t.req.valid("param"),{"tenant-id":n}=t.req.valid("header");if(!await t.env.data.users.remove(n,e))throw new A(404);return t.text("OK")}).openapi(s.createRoute({tags:["users"],method:"post",path:"/",request:{headers:s.z.object({"tenant-id":s.z.string()}),body:{content:{"application/json":{schema:s.z.object({...vo.shape})}}}},security:[{Bearer:["auth:write"]}],responses:{201:{content:{"application/json":{schema:Et}},description:"Status"}}}),async t=>{const{"tenant-id":e}=t.req.valid("header"),n=t.req.valid("json");t.set("body",n);const{email:r,phone_number:i,name:o,linked_to:a,email_verified:c,provider:d,connection:l}=n,u=`${n.provider}|${n.user_id||$s()}`;try{const f=await t.env.data.users.create(e,{email:r,user_id:u,name:o||r||i,phone_number:i,provider:d,connection:l,linked_to:a??void 0,email_verified:c||!1,last_ip:"",is_social:!1,last_login:new Date().toISOString()});t.set("user_id",f.user_id);const m=we(t,{type:he.SUCCESS_API_OPERATION,description:"User created"});It(t,t.env.data.logs.create(e,m));const w={...f,identities:[{connection:f.connection,provider:f.provider,user_id:Iu(f.user_id),isSocial:f.is_social}]};return t.json(Et.parse(w),{status:201})}catch(f){throw f.message==="User already exists"?new A(409,{message:"User already exists"}):f}}).openapi(s.createRoute({tags:["users"],method:"patch",path:"/{user_id}",request:{headers:s.z.object({"tenant-id":s.z.string()}),body:{content:{"application/json":{schema:s.z.object({...vo.shape,verify_email:s.z.boolean(),password:s.z.string()}).partial()}}},params:s.z.object({user_id:s.z.string()})},security:[{Bearer:["auth:write"]}],responses:{200:{description:"Status"}}}),async t=>{var u;const{data:e}=t.env,{"tenant-id":n}=t.req.valid("header"),r=t.req.valid("json"),{user_id:i}=t.req.valid("param"),{verify_email:o,password:a,...c}=r,d=await e.users.get(n,i);if(!d)throw new A(404);if(c.email&&c.email!==d.email){const f=await Xd(t.env.data.users,n,c.email);if(f.length&&f.some(m=>m.user_id!==i))throw new A(409,{message:"Another user with the same email address already exists."})}if(d.linked_to)throw new A(404,{message:"User is linked to another user"});if(await t.env.data.users.update(n,i,c),a){const f=(u=d.identities)==null?void 0:u.find(h=>h.connection==="Username-Password-Authentication");if(!f)throw new A(400,{message:"User does not have a password identity"});const m={user_id:f.user_id,password:await vi.hash(a,10),algorithm:"bcrypt"};await e.passwords.get(n,f.user_id)?await e.passwords.update(n,m):await e.passwords.create(n,m)}const l=await t.env.data.users.get(n,i);if(!l)throw new A(500);return t.json(l)}).openapi(s.createRoute({tags:["users"],method:"post",path:"/{user_id}/identities",request:{headers:s.z.object({"tenant-id":s.z.string()}),body:{content:{"application/json":{schema:s.z.union([s.z.object({link_with:s.z.string()}),s.z.object({user_id:s.z.string(),provider:s.z.string(),connection:s.z.string().optional()})])}}},params:s.z.object({user_id:s.z.string()})},security:[{Bearer:["auth:write"]}],responses:{201:{content:{"application/json":{schema:s.z.array(s.z.object({connection:s.z.string(),provider:s.z.string(),user_id:s.z.string(),isSocial:s.z.boolean()}))}},description:"Status"}}}),async t=>{const{"tenant-id":e}=t.req.valid("header"),n=t.req.valid("json"),{user_id:r}=t.req.valid("param"),i="link_with"in n?n.link_with:n.user_id,o=await t.env.data.users.get(e,r);if(!o)throw new A(400,{message:"Linking an inexistent identity is not allowed."});await t.env.data.users.update(e,i,{linked_to:r});const a=await t.env.data.users.list(e,{page:0,per_page:10,include_totals:!1,q:`linked_to:${r}`}),c=[o,...a.users].map(d=>({connection:d.connection,provider:d.provider,user_id:Iu(d.user_id),isSocial:d.is_social}));return t.json(c,{status:201})}).openapi(s.createRoute({tags:["users"],method:"delete",path:"/{user_id}/identities/{provider}/{linked_user_id}",request:{headers:s.z.object({"tenant-id":s.z.string()}),params:s.z.object({user_id:s.z.string(),provider:s.z.string(),linked_user_id:s.z.string()})},security:[{Bearer:["auth:write"]}],responses:{200:{content:{"application/json":{schema:s.z.array(Et)}},description:"Status"}}}),async t=>{const{"tenant-id":e}=t.req.valid("header"),{user_id:n,provider:r,linked_user_id:i}=t.req.valid("param");await t.env.data.users.unlink(e,n,r,i);const o=await t.env.data.users.get(e,n);if(!o)throw new A(404);return t.json([Et.parse(o)])}).openapi(s.createRoute({tags:["users"],method:"get",path:"/{user_id}/sessions",request:{query:Dt,headers:s.z.object({"tenant-id":s.z.string()}),params:s.z.object({user_id:s.z.string()})},security:[{Bearer:["auth:read"]}],responses:{200:{content:{"application/json":{schema:s.z.union([s.z.array(bs),$2])}},description:"List of sessions"}}}),async t=>{const{user_id:e}=t.req.valid("param"),{include_totals:n,page:r,per_page:i}=t.req.valid("query"),{"tenant-id":o}=t.req.valid("header"),a=await t.env.data.sessions.list(o,{page:r,per_page:i,include_totals:n,q:`user_id:${e}`});return n?t.json(a):t.json(a.sessions)});/*! *****************************************************************************
29
+ </html>`;return new Response(i,{headers:{"Content-Type":"text/html"}})}async function d2(t,e,n,r,i){var m,w,h;if(!n.redirect_uri)throw new A(400,{message:"Missing redirect_uri in authParams"});if(!r.email)throw new A(400,{message:"Missing email in user"});const[o]=await t.env.data.keys.list();if(!o)throw new A(500,{message:"No signing key found"});if(!((m=e.addons)!=null&&m.samlp))throw new A(400,{message:`SAML Addon is not enabled for client ${e.id}`});const{recipient:a,audience:c}=e.addons.samlp,d=n.state||"";if(!a||!d||!r||!n.state)throw new A(400,{message:"Missing recipient or inResponseTo"});const l=JSON.parse(n.state),u=new URL(n.redirect_uri),f=await l2(t,{issuer:t.env.ISSUER,audience:c||n.client_id,destination:u.toString(),inResponseTo:l.requestId,userId:((h=(w=r.app_metadata)==null?void 0:w.vimeo)==null?void 0:h.user_id)||r.user_id,email:r.email,sessionIndex:i,signature:{privateKeyPem:o.pkcs7,cert:o.cert,kid:o.kid}});return c2(u.toString(),f,l.relayState)}async function l2(t,e){const n=e.notBefore||new Date().toISOString(),r=e.notAfter||new Date(new Date(n).getTime()+10*60*1e3).toISOString(),i=e.issueInstant||n,o=e.sessionNotOnOrAfter||r,a=e.responseId||`_${Ee()}`,c=e.assertionId||`_${Ee()}`,d=[{"samlp:Response":[{"saml:Issuer":[{"#text":e.issuer}]},{"samlp:Status":[{"samlp:StatusCode":[],":@":{"@_Value":"urn:oasis:names:tc:SAML:2.0:status:Success"}}]},{"saml:Assertion":[{"saml:Issuer":[{"#text":e.issuer}]},{"saml:Subject":[{"saml:NameID":[{"#text":e.email}],":@":{"@_Format":"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"}},{"saml:SubjectConfirmation":[{"saml:SubjectConfirmationData":[],":@":{"@_InResponseTo":e.inResponseTo,"@_NotOnOrAfter":r,"@_Recipient":e.destination}}],":@":{"@_Method":"urn:oasis:names:tc:SAML:2.0:cm:bearer"}}]},{"saml:Conditions":[{"saml:AudienceRestriction":[{"saml:Audience":[{"#text":e.audience}]}]}],":@":{"@_NotBefore":n,"@_NotOnOrAfter":r}},{"saml:AuthnStatement":[{"saml:AuthnContext":[{"saml:AuthnContextClassRef":[{"#text":"urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified"}]}]}],":@":{"@_AuthnInstant":i,"@_SessionIndex":e.sessionIndex,"@_SessionNotOnOrAfter":o}},{"saml:AttributeStatement":[{"saml:Attribute":[{"saml:AttributeValue":[{"#text":e.userId}],":@":{"@_xmlns:xs":"http://www.w3.org/2001/XMLSchema","@_xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance","@_xsi:type":"xs:string"}}],":@":{"@_FriendlyName":"persistent","@_Name":"id","@_NameFormat":"urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"}},{"saml:Attribute":[{"saml:AttributeValue":[{"#text":e.email}],":@":{"@_xmlns:xs":"http://www.w3.org/2001/XMLSchema","@_xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance","@_xsi:type":"xs:string"}}],":@":{"@_Name":"email","@_NameFormat":"urn:oasis:names:tc:SAML:2.0:attrname-format:basic"}},{"saml:Attribute":[{"saml:AttributeValue":[{"#text":"manage-account"}],":@":{"@_xmlns:xs":"http://www.w3.org/2001/XMLSchema","@_xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance","@_xsi:type":"xs:string"}}],":@":{"@_Name":"Role","@_NameFormat":"urn:oasis:names:tc:SAML:2.0:attrname-format:basic"}},{"saml:Attribute":[{"saml:AttributeValue":[{"#text":"default-roles-master"}],":@":{"@_xmlns:xs":"http://www.w3.org/2001/XMLSchema","@_xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance","@_xsi:type":"xs:string"}}],":@":{"@_Name":"Role","@_NameFormat":"urn:oasis:names:tc:SAML:2.0:attrname-format:basic"}},{"saml:Attribute":[{"saml:AttributeValue":[{"#text":"offline_access"}],":@":{"@_xmlns:xs":"http://www.w3.org/2001/XMLSchema","@_xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance","@_xsi:type":"xs:string"}}],":@":{"@_Name":"Role","@_NameFormat":"urn:oasis:names:tc:SAML:2.0:attrname-format:basic"}},{"saml:Attribute":[{"saml:AttributeValue":[{"#text":"view-profile"}],":@":{"@_xmlns:xs":"http://www.w3.org/2001/XMLSchema","@_xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance","@_xsi:type":"xs:string"}}],":@":{"@_Name":"Role","@_NameFormat":"urn:oasis:names:tc:SAML:2.0:attrname-format:basic"}},{"saml:Attribute":[{"saml:AttributeValue":[{"#text":"uma_authorization"}],":@":{"@_xmlns:xs":"http://www.w3.org/2001/XMLSchema","@_xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance","@_xsi:type":"xs:string"}}],":@":{"@_Name":"Role","@_NameFormat":"urn:oasis:names:tc:SAML:2.0:attrname-format:basic"}},{"saml:Attribute":[{"saml:AttributeValue":[{"#text":"manage-account-links"}],":@":{"@_xmlns:xs":"http://www.w3.org/2001/XMLSchema","@_xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance","@_xsi:type":"xs:string"}}],":@":{"@_Name":"Role","@_NameFormat":"urn:oasis:names:tc:SAML:2.0:attrname-format:basic"}}]}],":@":{"@_xmlns":"urn:oasis:names:tc:SAML:2.0:assertion","@_ID":c,"@_IssueInstant":i,"@_Version":"2.0"}}],":@":{"@_xmlns:samlp":"urn:oasis:names:tc:SAML:2.0:protocol","@_xmlns:saml":"urn:oasis:names:tc:SAML:2.0:assertion","@_Destination":e.destination,"@_ID":a,"@_InResponseTo":e.inResponseTo,"@_IssueInstant":i,"@_Version":"2.0"}}];let u=new a2.XMLBuilder({ignoreAttributes:!1,suppressEmptyNode:!0,preserveOrder:!0}).build(d);if(e.signature){const m=await fetch(t.env.SAML_SIGN_URL,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({xmlContent:u,privateKey:e.signature.privateKeyPem,publicCert:e.signature.cert})});if(!m.ok)throw new Error(`Failed to sign SAML response: ${m.status}`);u=await m.text()}return e.encode===!1?u:btoa(u)}var u2={deno:"Deno",bun:"Bun",workerd:"Cloudflare-Workers",node:"Node.js"},p2=()=>{var n,r;const t=globalThis;if(typeof navigator<"u"&&typeof navigator.userAgent=="string"){for(const[i,o]of Object.entries(u2))if(f2(o))return i}return typeof(t==null?void 0:t.EdgeRuntime)=="string"?"edge-light":(t==null?void 0:t.fastly)!==void 0?"fastly":((r=(n=t==null?void 0:t.process)==null?void 0:n.release)==null?void 0:r.name)==="node"?"node":"other"},f2=t=>navigator.userAgent.startsWith(t);function It(t,e){p2()==="workerd"&&t.executionCtx.waitUntil(e)}function Xt(t){var e,n,r,i;return{auth0Client:(e=t.query("auth0Client"))==null?void 0:e.slice(0,255),ip:(n=t.header("x-real-ip"))==null?void 0:n.slice(0,45),useragent:(r=t.header("user-agent"))==null?void 0:r.slice(0,512),countryCode:(i=t.header("cf-ipcountry"))==null?void 0:i.slice(0,2)}}const Bu=["sub","iss","aud","exp","nbf","iat","jti"];async function Ss(t,e){var v,x;const{authParams:n,user:r,client:i,session_id:o}=e,c=(await t.env.data.keys.list()).filter(z=>!z.revoked_at||new Date(z.revoked_at)>new Date),d=c[c.length-1];if(!(d!=null&&d.pkcs7))throw new A(500,{message:"No signing key available"});const l=O_(d.pkcs7),u=t.var.custom_domain?`https://${t.var.custom_domain}/`:t.env.ISSUER,f={aud:n.audience||"default",scope:n.scope||"",sub:(r==null?void 0:r.user_id)||n.client_id,iss:u,tenant_id:t.var.tenant_id,sid:o},m=r&&((v=n.scope)!=null&&v.split(" ").includes("openid"))?{aud:n.client_id,sub:r.user_id,iss:u,sid:o,nonce:n.nonce,given_name:r.given_name,family_name:r.family_name,nickname:r.nickname,picture:r.picture,locale:r.locale,name:r.name,email:r.email,email_verified:r.email_verified}:void 0;(x=t.env.hooks)!=null&&x.onExecuteCredentialsExchange&&await t.env.hooks.onExecuteCredentialsExchange({client:i,user:r,request:{ip:t.req.header("x-real-ip")||"",user_agent:t.req.header("user-agent")||"",method:t.req.method,url:t.req.url},scope:n.scope||"",grant_type:""},{accessToken:{setCustomClaim:(z,O)=>{if(Bu.includes(z))throw new Error(`Cannot overwrite reserved claim '${z}'`);f[z]=O}},idToken:{setCustomClaim:(z,O)=>{if(Bu.includes(z))throw new Error(`Cannot overwrite reserved claim '${z}'`);m&&(m[z]=O)}},access:{deny:z=>{throw new A(400,{message:`Access denied: ${z}`})}}});const w={includeIssuedTimestamp:!0,expiresIn:new qd(1,"d"),headers:{kid:d.kid}},h=await Cu("RS256",l,f,w),y=m?await Cu("RS256",l,m,w):void 0;return{access_token:h,refresh_token:e.refresh_token,id_token:y,token_type:"Bearer",expires_in:86400}}async function y0(t,e){return{code:(await t.env.data.codes.create(e.client.tenant.id,{code_id:Ee(),user_id:e.user.user_id,code_type:"authorization_code",login_id:e.login_id,expires_at:new Date(Date.now()+B_*1e3).toISOString()})).code_id,state:e.authParams.state}}async function h2(t,e){const{client:n,scope:r,audience:i=n.tenant.audience,session_id:o}=e,a=Xt(t.req);return await t.env.data.refreshTokens.create(n.tenant.id,{id:Ee(),session_id:o,client_id:n.id,idle_expires_at:new Date(Date.now()+xs*1e3).toISOString(),user_id:e.user.user_id,device:{last_ip:a.ip||"",initial_ip:a.ip||"",last_user_agent:a.useragent||"",initial_user_agent:a.useragent||"",initial_asn:"",last_asn:""},resource_servers:[{audience:i,scopes:r}],rotating:!1})}async function w0(t,{user:e,client:n,loginSession:r}){const i=await t.env.data.sessions.create(n.tenant.id,{id:Ee(),user_id:e.user_id,idle_expires_at:new Date(Date.now()+xs*1e3).toISOString(),device:{last_ip:t.req.header("x-real-ip")||"",initial_ip:t.req.header("x-real-ip")||"",last_user_agent:t.req.header("user-agent")||"",initial_user_agent:t.req.header("user-agent")||"",initial_asn:"",last_asn:""},clients:[n.id]});return await t.env.data.loginSessions.update(n.tenant.id,r.id,{session_id:i.id}),i}async function hn(t,e){var h,y;const{authParams:n,user:r,client:i,ticketAuth:o}=e,a=we(t,{type:he.SUCCESS_LOGIN,description:`Successful login for ${r.user_id}`,userId:r.user_id});if(It(t,t.env.data.logs.create(i.tenant.id,a)),It(t,t.env.data.users.update(i.tenant.id,r.user_id,{last_login:new Date().toISOString(),last_ip:t.req.header("x-real-ip")||"",login_count:r.login_count+1})),o){if(!e.loginSession)throw new A(500,{message:"Login session not found for ticket auth."});const v=j_(),x=Ee(12),z=await t.env.data.codes.create(i.tenant.id,{code_id:Ee(),code_type:"ticket",login_id:e.loginSession.id,expires_at:new Date(Date.now()+U_).toISOString(),code_verifier:[x,v].join("|")});return t.json({login_ticket:z.code_id,co_verifier:v,co_id:x})}let c=e.refreshToken,d=e.sessionId,l=r;if(!d&&((h=e.loginSession)!=null&&h.session_id)){d=e.loginSession.session_id;const v=await t.env.data.sessions.get(i.tenant.id,d);v&&!v.clients.includes(i.id)&&await t.env.data.sessions.update(i.tenant.id,d,{clients:[...v.clients,i.id]}),!c&&((y=n.scope)!=null&&y.split(" ").includes("offline_access"))&&(c=(await h2(t,{user:l,client:i,session_id:d,scope:n.scope,audience:n.audience})).id)}else if(!d){if(!e.loginSession)throw new A(500,{message:"Login session not found for creating a new session."});const v=await b2(t,t.env.data,i.tenant.id,r,e.loginSession,{client:i,authParams:n});if(v instanceof Response)return v;l=v,d=(await w0(t,{user:l,client:i,loginSession:e.loginSession})).id}if(e.authParams.response_mode===Ft.SAML_POST){if(!d)throw new A(500,{message:"Session ID not available for SAML response"});return d2(t,e.client,e.authParams,l,d)}const u=await Ss(t,{authParams:n,user:l,client:i,session_id:d,refresh_token:c});if(n.response_mode===Ft.WEB_MESSAGE){if(d){const v=nc(i.tenant.id,d,t.var.custom_domain||t.req.header("host")||"");v&&t.header("set-cookie",v)}else console.warn("Session ID not available for WEB_MESSAGE, cookie will not be set.");return u}const f=new Headers;if(d){const v=nc(i.tenant.id,d,t.var.custom_domain||t.req.header("host")||"");v&&f.set("set-cookie",v)}const m=n.response_type||it.CODE;if(m===it.CODE){if(!e.loginSession)throw new A(500,{message:"Login session not found for code response type."});const v=await y0(t,{user:l,client:i,authParams:n,login_id:e.loginSession.id});if(!n.redirect_uri)throw new A(400,{message:"Redirect uri not found for code response type."});const x=new URL(n.redirect_uri);return x.searchParams.set("code",v.code),v.state&&x.searchParams.set("state",v.state),f.set("location",x.toString()),new Response("Redirecting",{status:302,headers:f})}if(!n.redirect_uri)throw new A(400,{message:"Redirect uri not found for this response mode."});const w=new URL(n.redirect_uri);if(m===it.TOKEN||m===it.TOKEN_ID_TOKEN)w.hash=new URLSearchParams({access_token:u.access_token,...u.id_token&&{id_token:u.id_token},token_type:u.token_type,expires_in:u.expires_in.toString(),...n.state&&{state:n.state},...n.scope&&{scope:n.scope}}).toString();else throw new A(500,{message:`Unsupported response type ('${m}') for redirect with tokens.`});return f.set("location",w.toString()),new Response("Redirecting",{status:302,headers:f})}async function g2(t,e,n){const r=await t.env.data.tenants.get(e);if(!r)throw new Error(`Tenant not found: ${e}`);return Ss(t,{client:{id:t.env.ISSUER,tenant:r,created_at:new Date().toISOString(),updated_at:new Date().toISOString(),name:t.env.ISSUER,disable_sign_ups:!1,connections:[]},authParams:{client_id:t.env.ISSUER,response_type:it.TOKEN,scope:n}})}async function v0(t,e,n){const r=await g2(t,n.tenant_id,"webhook");for await(const i of e.filter(o=>"url"in o))if(!(await fetch(i.url,{method:"POST",headers:{Authorization:`Bearer ${r.access_token}`,"Content-Type":"application/json"},body:JSON.stringify(n)})).ok){const a=we(t,{type:he.FAILED_HOOK,description:`Failed to invoke hook ${i.hook_id}`});await t.env.data.logs.create(n.tenant_id,a)}}function m2(t){return async(e,n)=>{const{hooks:r}=await t.env.data.hooks.list(e);return await v0(t,r,{tenant_id:e,user:n,trigger_id:"post-user-registration"}),n}}function _2(t){return async(e,n)=>{const{hooks:r}=await t.env.data.hooks.list(e,{q:"trigger_id:pre-user-signup",page:0,per_page:100,include_totals:!1});await v0(t,r,{tenant_id:e,email:n,trigger_id:"pre-user-signup"})}}function Lu(t){return typeof t.form_id=="string"}async function y2(t,e,n){var d;const r=t.env.data,i=t.var.tenant_id||t.req.header("tenant-id");if(!i)throw new A(400,{message:"Missing tenant_id in context"});const o=await r.forms.get(i,e);if(!o)throw new A(404,{message:"Form not found for post-user-login hook"});let a=(d=o.start)==null?void 0:d.next_node;if(!a&&o.nodes&&o.nodes.length>0){const l=o.nodes.find(u=>u.type==="STEP");a=l==null?void 0:l.id}if(!a)throw new A(400,{message:"No start node found in form"});let c=`/u/forms/${o.id}/nodes/${a}?state=${encodeURIComponent(n.id)}`;return new Response(null,{status:302,headers:{location:c}})}function Uu(t){return typeof t.url=="string"}function w2(t,e){return async(n,r)=>{var a,c,d;const i={method:t.req.method,ip:t.req.query("x-real-ip")||"",user_agent:t.req.query("user-agent"),url:((a=t.var.loginSession)==null?void 0:a.authorization_url)||t.req.url};if((c=t.env.hooks)!=null&&c.onExecutePreUserRegistration)try{await t.env.hooks.onExecutePreUserRegistration({user:r,request:i},{user:{setUserMetadata:async(l,u)=>{r[l]=u}}})}catch{const u=we(t,{type:he.FAILED_SIGNUP,description:"Pre user registration hook failed"});await e.logs.create(n,u)}let o=await S_(e)(n,r);if((d=t.env.hooks)!=null&&d.onExecutePostUserRegistration)try{await t.env.hooks.onExecutePostUserRegistration({user:r,request:i},{user:{}})}catch{const u=we(t,{type:he.FAILED_SIGNUP,description:"Post user registration hook failed"});await t.env.data.logs.create(n,u)}return await m2(t)(n,o),o}}async function v2(t,e,n,r){var i;if(e.disable_sign_ups){const o=(i=t.var.loginSession)==null?void 0:i.authorization_url;if(!(o&&new URL(o).searchParams.get("screen_hint")==="signup")&&!await Es({userAdapter:n.users,tenant_id:e.tenant.id,email:r})){const d=we(t,{type:he.FAILED_SIGNUP,description:"Public signup is disabled"});throw await n.logs.create(e.tenant.id,d),new A(400,{message:"Signups are disabled for this client"})}}await _2(t)(t.var.tenant_id||"",r)}function As(t,e){return{...e,users:{...e.users,create:w2(t,e)}}}async function b2(t,e,n,r,i,o){var d;(d=t.env.hooks)!=null&&d.onExecutePostLogin&&(o!=null&&o.client)&&(o!=null&&o.authParams)&&await t.env.hooks.onExecutePostLogin({client:o.client,user:r,request:{ip:t.req.header("x-real-ip")||"",user_agent:t.req.header("user-agent")||"",method:t.req.method,url:t.req.url},scope:o.authParams.scope||"",grant_type:""},{prompt:{render:l=>{}}});const{hooks:a}=await e.hooks.list(n,{q:"trigger_id:post-user-login",page:0,per_page:100,include_totals:!1});if(i){const l=a.find(u=>u.enabled&&Lu(u));if(l&&Lu(l))return y2(t,l.form_id,i)}const c=a.filter(l=>l.enabled&&Uu(l));for(const l of c)if(Uu(l))try{await fetch(l.url,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({tenant_id:n,user:r,trigger_id:"post-user-login"})})}catch{const f=we(t,{type:he.FAILED_HOOK,description:`Failed to invoke post-user-login webhook: ${l.url}`});await e.logs.create(n,f)}return r}function b0(t){return As(t,t.env.data)}async function Xd(t,e,n){return(await t.list(e,{page:0,per_page:10,include_totals:!1,q:`email:${n}`})).users}async function kr({userAdapter:t,tenant_id:e,username:n,provider:r}){const i=r==="sms"?`phone_number:${n}`:`email:${n}`,{users:o}=await t.list(e,{page:0,per_page:10,include_totals:!1,q:`${i} provider:${r}`});return o.length>1&&console.error("More than one user found for same email and provider"),o[0]||null}async function Es({userAdapter:t,tenant_id:e,email:n}){var c;const{users:r}=await t.list(e,{page:0,per_page:10,include_totals:!1,q:`email:${n}`}),i=r.filter(d=>!(d.provider==="auth2"&&!d.email_verified));if(i.length===0)return;const o=i.filter(d=>!d.linked_to);if(o.length>0)return o.length>1&&console.error("More than one primary user found for same email"),o[0];const a=await t.get(e,(c=i[0])==null?void 0:c.linked_to);if(!a)throw new Error("Primary account not found");return a}async function zo({userAdapter:t,tenant_id:e,username:n,provider:r}){const i=await kr({userAdapter:t,tenant_id:e,username:n,provider:r});return i?i.linked_to?t.get(e,i.linked_to):i:null}async function zs(t,e){const{username:n,provider:r,connection:i,client:o,userId:a,isSocial:c,profileData:d={},ip:l=""}=e;let u=await zo({userAdapter:t.env.data.users,tenant_id:e.client.tenant.id,username:n,provider:r});if(!u){const f={user_id:`${r}|${a||$s()}`,email:i!=="sms"?n:void 0,phone_number:i==="sms"?n:void 0,name:n,provider:r,connection:i,email_verified:!0,last_ip:l,is_social:c,last_login:new Date().toISOString(),profileData:JSON.stringify(d)};u=await b0(t).users.create(o.tenant.id,f),t.set("user_id",u.user_id)}return u}const Dt=s.z.object({page:s.z.string().min(0).optional().default("0").transform(t=>parseInt(t,10)).openapi({description:"The page number where 0 is the first page"}),per_page:s.z.string().min(1).optional().default("10").transform(t=>parseInt(t,10)).openapi({description:"The number of items per page"}),include_totals:s.z.string().optional().default("false").transform(t=>t==="true").openapi({description:"If the total number of items should be included in the response"}),sort:s.z.string().regex(/^.+:(-1|1)$/).optional().openapi({description:"A property that should have the format 'string:-1' or 'string:1'"}),q:s.z.string().optional().openapi({description:"A lucene query string used to filter the results"})});function Vn(t){if(!t)return;const[e,n]=t.split(":"),r=n==="1"?"asc":"desc";if(!(!e||!r))return{sort_by:e,sort_order:r}}const Mu=Jt.extend({users:s.z.array(Et)}),$2=Jt.extend({sessions:s.z.array(bs)}),x2=new s.OpenAPIHono().openapi(s.createRoute({tags:["users"],method:"get",path:"/",request:{query:Dt,headers:s.z.object({"tenant-id":s.z.string()})},security:[{Bearer:["auth:read"]}],responses:{200:{content:{"application/json":{schema:s.z.union([s.z.array(Et),Mu])}},description:"List of users"}}}),async t=>{const{page:e,per_page:n,include_totals:r,sort:i,q:o}=t.req.valid("query"),{"tenant-id":a}=t.req.valid("header");if(o!=null&&o.includes("identities.profileData.email")){const u=o.split("=")[1],m=(await t.env.data.users.list(a,{page:e,per_page:n,include_totals:r,q:`email:${u}`})).users.filter(y=>y.linked_to),[w]=m;if(!w)return t.json([]);const h=await t.env.data.users.get(a,w.linked_to);if(!h)throw new A(500,{message:"Primary account not found"});return t.json([Et.parse(h)])}const c=["-_exists_:linked_to"];o&&c.push(o);const d=await t.env.data.users.list(a,{page:e,per_page:n,include_totals:r,sort:Vn(i),q:c.join(" ")}),l=d.users.filter(u=>!u.linked_to);return r?t.json(Mu.parse({users:l,length:d.length,start:d.start,limit:d.limit})):t.json(s.z.array(Et).parse(l))}).openapi(s.createRoute({tags:["users"],method:"get",path:"/{user_id}",request:{headers:s.z.object({"tenant-id":s.z.string()}),params:s.z.object({user_id:s.z.string()})},security:[{Bearer:["auth:read"]}],responses:{200:{content:{"application/json":{schema:Et}},description:"List of users"}}}),async t=>{const{user_id:e}=t.req.valid("param"),{"tenant-id":n}=t.req.valid("header"),r=await t.env.data.users.get(n,e);if(!r)throw new A(404);if(r.linked_to)throw new A(404,{message:"User is linked to another user"});return t.json(r)}).openapi(s.createRoute({tags:["users"],method:"delete",path:"/{user_id}",request:{headers:s.z.object({"tenant-id":s.z.string()}),params:s.z.object({user_id:s.z.string()})},security:[{Bearer:["auth:write"]}],responses:{200:{description:"Status"}}}),async t=>{const{user_id:e}=t.req.valid("param"),{"tenant-id":n}=t.req.valid("header");if(!await t.env.data.users.remove(n,e))throw new A(404);return t.text("OK")}).openapi(s.createRoute({tags:["users"],method:"post",path:"/",request:{headers:s.z.object({"tenant-id":s.z.string()}),body:{content:{"application/json":{schema:s.z.object({...vo.shape})}}}},security:[{Bearer:["auth:write"]}],responses:{201:{content:{"application/json":{schema:Et}},description:"Status"}}}),async t=>{const{"tenant-id":e}=t.req.valid("header"),n=t.req.valid("json");t.set("body",n);const{email:r,phone_number:i,name:o,linked_to:a,email_verified:c,provider:d,connection:l}=n,u=`${n.provider}|${n.user_id||$s()}`;try{const f=await t.env.data.users.create(e,{email:r,user_id:u,name:o||r||i,phone_number:i,provider:d,connection:l,linked_to:a??void 0,email_verified:c||!1,last_ip:"",is_social:!1,last_login:new Date().toISOString()});t.set("user_id",f.user_id);const m=we(t,{type:he.SUCCESS_API_OPERATION,description:"User created"});It(t,t.env.data.logs.create(e,m));const w={...f,identities:[{connection:f.connection,provider:f.provider,user_id:Iu(f.user_id),isSocial:f.is_social}]};return t.json(Et.parse(w),{status:201})}catch(f){throw f.message==="User already exists"?new A(409,{message:"User already exists"}):f}}).openapi(s.createRoute({tags:["users"],method:"patch",path:"/{user_id}",request:{headers:s.z.object({"tenant-id":s.z.string()}),body:{content:{"application/json":{schema:s.z.object({...vo.shape,verify_email:s.z.boolean(),password:s.z.string()}).partial()}}},params:s.z.object({user_id:s.z.string()})},security:[{Bearer:["auth:write"]}],responses:{200:{description:"Status"}}}),async t=>{var u;const{data:e}=t.env,{"tenant-id":n}=t.req.valid("header"),r=t.req.valid("json"),{user_id:i}=t.req.valid("param"),{verify_email:o,password:a,...c}=r,d=await e.users.get(n,i);if(!d)throw new A(404);if(c.email&&c.email!==d.email){const f=await Xd(t.env.data.users,n,c.email);if(f.length&&f.some(m=>m.user_id!==i))throw new A(409,{message:"Another user with the same email address already exists."})}if(d.linked_to)throw new A(404,{message:"User is linked to another user"});if(await t.env.data.users.update(n,i,c),a){const f=(u=d.identities)==null?void 0:u.find(h=>h.connection==="Username-Password-Authentication");if(!f)throw new A(400,{message:"User does not have a password identity"});const m={user_id:f.user_id,password:await vi.hash(a,10),algorithm:"bcrypt"};await e.passwords.get(n,f.user_id)?await e.passwords.update(n,m):await e.passwords.create(n,m)}const l=await t.env.data.users.get(n,i);if(!l)throw new A(500);return t.json(l)}).openapi(s.createRoute({tags:["users"],method:"post",path:"/{user_id}/identities",request:{headers:s.z.object({"tenant-id":s.z.string()}),body:{content:{"application/json":{schema:s.z.union([s.z.object({link_with:s.z.string()}),s.z.object({user_id:s.z.string(),provider:s.z.string(),connection:s.z.string().optional()})])}}},params:s.z.object({user_id:s.z.string()})},security:[{Bearer:["auth:write"]}],responses:{201:{content:{"application/json":{schema:s.z.array(s.z.object({connection:s.z.string(),provider:s.z.string(),user_id:s.z.string(),isSocial:s.z.boolean()}))}},description:"Status"}}}),async t=>{const{"tenant-id":e}=t.req.valid("header"),n=t.req.valid("json"),{user_id:r}=t.req.valid("param"),i="link_with"in n?n.link_with:n.user_id,o=await t.env.data.users.get(e,r);if(!o)throw new A(400,{message:"Linking an inexistent identity is not allowed."});await t.env.data.users.update(e,i,{linked_to:r});const a=await t.env.data.users.list(e,{page:0,per_page:10,include_totals:!1,q:`linked_to:${r}`}),c=[o,...a.users].map(d=>({connection:d.connection,provider:d.provider,user_id:Iu(d.user_id),isSocial:d.is_social}));return t.json(c,{status:201})}).openapi(s.createRoute({tags:["users"],method:"delete",path:"/{user_id}/identities/{provider}/{linked_user_id}",request:{headers:s.z.object({"tenant-id":s.z.string()}),params:s.z.object({user_id:s.z.string(),provider:s.z.string(),linked_user_id:s.z.string()})},security:[{Bearer:["auth:write"]}],responses:{200:{content:{"application/json":{schema:s.z.array(Et)}},description:"Status"}}}),async t=>{const{"tenant-id":e}=t.req.valid("header"),{user_id:n,provider:r,linked_user_id:i}=t.req.valid("param");await t.env.data.users.unlink(e,n,r,i);const o=await t.env.data.users.get(e,n);if(!o)throw new A(404);return t.json([Et.parse(o)])}).openapi(s.createRoute({tags:["users"],method:"get",path:"/{user_id}/sessions",request:{query:Dt,headers:s.z.object({"tenant-id":s.z.string()}),params:s.z.object({user_id:s.z.string()})},security:[{Bearer:["auth:read"]}],responses:{200:{content:{"application/json":{schema:s.z.union([s.z.array(bs),$2])}},description:"List of sessions"}}}),async t=>{const{user_id:e}=t.req.valid("param"),{include_totals:n,page:r,per_page:i}=t.req.valid("query"),{"tenant-id":o}=t.req.valid("header"),a=await t.env.data.sessions.list(o,{page:r,per_page:i,include_totals:n,q:`user_id:${e}`});return n?t.json(a):t.json(a.sessions)});/*! *****************************************************************************
30
30
  Copyright (C) Microsoft. All rights reserved.
31
31
  Licensed under the Apache License, Version 2.0 (the "License"); you may not use
32
32
  this file except in compliance with the License. You may obtain a copy of the
package/dist/authhero.mjs CHANGED
@@ -6148,11 +6148,16 @@ async function fn(t, e) {
6148
6148
  }
6149
6149
  const m = n.response_type || _t.CODE;
6150
6150
  if (m === _t.CODE) {
6151
+ if (!e.loginSession)
6152
+ throw new A(500, {
6153
+ message: "Login session not found for code response type."
6154
+ });
6151
6155
  const v = await Fh(t, {
6152
6156
  user: l,
6153
6157
  client: i,
6154
6158
  authParams: n,
6155
- login_id: d
6159
+ login_id: e.loginSession.id
6160
+ // Use login session id instead of session_id
6156
6161
  });
6157
6162
  if (!n.redirect_uri)
6158
6163
  throw new A(400, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "authhero",
3
- "version": "0.143.0",
3
+ "version": "0.144.0",
4
4
  "files": [
5
5
  "dist"
6
6
  ],