authhero 0.147.0 → 0.148.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 +1 -1
- package/dist/authhero.d.ts +4 -0
- package/dist/authhero.mjs +4 -0
- package/package.json +1 -1
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||`_${xe()}`,c=e.assertionId||`_${xe()}`,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 jt(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 Lu=["sub","iss","aud","exp","nbf","iat","jti"];async function As(t,e){var v,b;const{authParams:n,user:r,client:i,session_id:o}=e,c=(await t.env.data.keys.list()).filter(E=>!E.revoked_at||new Date(E.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;(b=t.env.hooks)!=null&&b.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:(E,C)=>{if(Lu.includes(E))throw new Error(`Cannot overwrite reserved claim '${E}'`);f[E]=C}},idToken:{setCustomClaim:(E,C)=>{if(Lu.includes(E))throw new Error(`Cannot overwrite reserved claim '${E}'`);m&&(m[E]=C)}},access:{deny:E=>{throw new A(400,{message:`Access denied: ${E}`})}}});const w={includeIssuedTimestamp:!0,expiresIn:new Hd(1,"d"),headers:{kid:d.kid}},h=await ju("RS256",l,f,w),y=m?await ju("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:xe(),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=jt(t.req);return await t.env.data.refreshTokens.create(n.tenant.id,{id:xe(),session_id:o,client_id:n.id,idle_expires_at:new Date(Date.now()+ks*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:xe(),user_id:e.user_id,idle_expires_at:new Date(Date.now()+ks*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 Zt(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_(),b=xe(12),E=await t.env.data.codes.create(i.tenant.id,{code_id:xe(),code_type:"ticket",login_id:e.loginSession.id,expires_at:new Date(Date.now()+U_).toISOString(),code_verifier:[b,v].join("|")});return t.json({login_ticket:E.code_id,co_verifier:v,co_id:b})}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."});d=(await w0(t,{user:l,client:i,loginSession:e.loginSession})).id;const b=await b2(t,t.env.data,i.tenant.id,r,e.loginSession,{client:i,authParams:n});if(b instanceof Response)return b;l=b}if(e.authParams.response_mode===Dt.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 As(t,{authParams:n,user:l,client:i,session_id:d,refresh_token:c});if(n.response_mode===Dt.WEB_MESSAGE){if(d){const v=rc(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=rc(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 b=new URL(n.redirect_uri);return b.searchParams.set("code",v.code),v.state&&b.searchParams.set("state",v.state),f.set("location",b.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 As(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 Uu(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 Mu(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 zs({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 Es(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&&Uu(u));if(l&&Uu(l))return y2(t,l.form_id,i)}const c=a.filter(l=>l.enabled&&Mu(l));for(const l of c)if(Mu(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 Es(t,t.env.data)}async function Zd(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 zs({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 Io({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 Is(t,e){const{username:n,provider:r,connection:i,client:o,userId:a,isSocial:c,profileData:d={},ip:l=""}=e;let u=await Io({userAdapter:t.env.data.users,tenant_id:e.client.tenant.id,username:n,provider:r});if(!u){const f={user_id:`${r}|${a||xs()}`,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 Vt=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 Fu=Xt.extend({users:s.z.array(Et)}),$2=Xt.extend({sessions:s.z.array($s)}),x2=new s.OpenAPIHono().openapi(s.createRoute({tags:["users"],method:"get",path:"/",request:{query:Vt,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),Fu])}},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(Fu.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({...bo.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||xs()}`;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:Nu(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({...bo.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 Zd(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:Nu(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:Vt,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($s),$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||`_${xe()}`,c=e.assertionId||`_${xe()}`,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 jt(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 Lu=["sub","iss","aud","exp","nbf","iat","jti"];async function As(t,e){var v,b;const{authParams:n,user:r,client:i,session_id:o}=e,c=(await t.env.data.keys.list()).filter(E=>!E.revoked_at||new Date(E.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;(b=t.env.hooks)!=null&&b.onExecuteCredentialsExchange&&await t.env.hooks.onExecuteCredentialsExchange({ctx:t,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:(E,C)=>{if(Lu.includes(E))throw new Error(`Cannot overwrite reserved claim '${E}'`);f[E]=C}},idToken:{setCustomClaim:(E,C)=>{if(Lu.includes(E))throw new Error(`Cannot overwrite reserved claim '${E}'`);m&&(m[E]=C)}},access:{deny:E=>{throw new A(400,{message:`Access denied: ${E}`})}}});const w={includeIssuedTimestamp:!0,expiresIn:new Hd(1,"d"),headers:{kid:d.kid}},h=await ju("RS256",l,f,w),y=m?await ju("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:xe(),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=jt(t.req);return await t.env.data.refreshTokens.create(n.tenant.id,{id:xe(),session_id:o,client_id:n.id,idle_expires_at:new Date(Date.now()+ks*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:xe(),user_id:e.user_id,idle_expires_at:new Date(Date.now()+ks*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 Zt(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_(),b=xe(12),E=await t.env.data.codes.create(i.tenant.id,{code_id:xe(),code_type:"ticket",login_id:e.loginSession.id,expires_at:new Date(Date.now()+U_).toISOString(),code_verifier:[b,v].join("|")});return t.json({login_ticket:E.code_id,co_verifier:v,co_id:b})}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."});d=(await w0(t,{user:l,client:i,loginSession:e.loginSession})).id;const b=await b2(t,t.env.data,i.tenant.id,r,e.loginSession,{client:i,authParams:n});if(b instanceof Response)return b;l=b}if(e.authParams.response_mode===Dt.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 As(t,{authParams:n,user:l,client:i,session_id:d,refresh_token:c});if(n.response_mode===Dt.WEB_MESSAGE){if(d){const v=rc(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=rc(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 b=new URL(n.redirect_uri);return b.searchParams.set("code",v.code),v.state&&b.searchParams.set("state",v.state),f.set("location",b.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 As(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 Uu(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 Mu(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({ctx:t,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({ctx:t,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 zs({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 Es(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({ctx:t,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&&Uu(u));if(l&&Uu(l))return y2(t,l.form_id,i)}const c=a.filter(l=>l.enabled&&Mu(l));for(const l of c)if(Mu(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 Es(t,t.env.data)}async function Zd(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 zs({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 Io({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 Is(t,e){const{username:n,provider:r,connection:i,client:o,userId:a,isSocial:c,profileData:d={},ip:l=""}=e;let u=await Io({userAdapter:t.env.data.users,tenant_id:e.client.tenant.id,username:n,provider:r});if(!u){const f={user_id:`${r}|${a||xs()}`,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 Vt=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 Fu=Xt.extend({users:s.z.array(Et)}),$2=Xt.extend({sessions:s.z.array($s)}),x2=new s.OpenAPIHono().openapi(s.createRoute({tags:["users"],method:"get",path:"/",request:{query:Vt,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),Fu])}},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(Fu.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({...bo.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||xs()}`;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:Nu(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({...bo.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 Zd(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:Nu(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:Vt,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($s),$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.d.ts
CHANGED
|
@@ -13726,6 +13726,10 @@ export type HookRequest = {
|
|
|
13726
13726
|
url: string;
|
|
13727
13727
|
};
|
|
13728
13728
|
export type HookEvent = {
|
|
13729
|
+
ctx: Context<{
|
|
13730
|
+
Bindings: Bindings;
|
|
13731
|
+
Variables: Variables;
|
|
13732
|
+
}>;
|
|
13729
13733
|
client?: Client;
|
|
13730
13734
|
request: HookRequest;
|
|
13731
13735
|
transaction?: Transaction;
|
package/dist/authhero.mjs
CHANGED
|
@@ -5905,6 +5905,7 @@ async function go(t, e) {
|
|
|
5905
5905
|
} : void 0;
|
|
5906
5906
|
(b = t.env.hooks) != null && b.onExecuteCredentialsExchange && await t.env.hooks.onExecuteCredentialsExchange(
|
|
5907
5907
|
{
|
|
5908
|
+
ctx: t,
|
|
5908
5909
|
client: i,
|
|
5909
5910
|
user: r,
|
|
5910
5911
|
request: {
|
|
@@ -6301,6 +6302,7 @@ function Xy(t, e) {
|
|
|
6301
6302
|
try {
|
|
6302
6303
|
await t.env.hooks.onExecutePreUserRegistration(
|
|
6303
6304
|
{
|
|
6305
|
+
ctx: t,
|
|
6304
6306
|
user: r,
|
|
6305
6307
|
request: i
|
|
6306
6308
|
},
|
|
@@ -6324,6 +6326,7 @@ function Xy(t, e) {
|
|
|
6324
6326
|
try {
|
|
6325
6327
|
await t.env.hooks.onExecutePostUserRegistration(
|
|
6326
6328
|
{
|
|
6329
|
+
ctx: t,
|
|
6327
6330
|
user: r,
|
|
6328
6331
|
request: i
|
|
6329
6332
|
},
|
|
@@ -6371,6 +6374,7 @@ async function Yy(t, e, n, r, i, s) {
|
|
|
6371
6374
|
var d;
|
|
6372
6375
|
(d = t.env.hooks) != null && d.onExecutePostLogin && (s != null && s.client) && (s != null && s.authParams) && await t.env.hooks.onExecutePostLogin(
|
|
6373
6376
|
{
|
|
6377
|
+
ctx: t,
|
|
6374
6378
|
client: s.client,
|
|
6375
6379
|
user: r,
|
|
6376
6380
|
request: {
|