diff --git a/apps/cli-go/internal/functions/serve/templates/main.bundled.js b/apps/cli-go/internal/functions/serve/templates/main.bundled.js index 101a7920cd..3abf39bba7 100644 --- a/apps/cli-go/internal/functions/serve/templates/main.bundled.js +++ b/apps/cli-go/internal/functions/serve/templates/main.bundled.js @@ -1,6 +1,6 @@ -var h={OK:200,Unauthorized:401,NotFound:404,InternalServerError:500,ServiceUnavailable:503},Z={[h.OK]:"OK",[h.Unauthorized]:"Unauthorized",[h.NotFound]:"Not Found",[h.InternalServerError]:"Internal Server Error",[h.ServiceUnavailable]:"Service Unavailable"};function Ye(e){let t=e.startsWith("/"),r=[];for(let n of e.split("/"))if(!(n===""||n===".")){if(n===".."){r.length>0&&r[r.length-1]!==".."?r.pop():t||r.push("..");continue}r.push(n)}let o=r.join("/");return t?"/"+o:o===""?".":o}function Q(...e){let t=e.filter(r=>r.length>0).join("/");return t===""?".":Ye(t)}function ee(e){if(e.length===0)return".";let t=e.length;for(;t>1&&e[t-1]==="/";)t-=1;let r=e.slice(0,t),o=r.lastIndexOf("/");return o===-1?".":o===0?"/":r.slice(0,o)}function qe(e){return e.replace(/\s/g,t=>`%${t.charCodeAt(0).toString(16).padStart(2,"0").toUpperCase()}`)}function me(e){if(!e.startsWith("/"))throw new TypeError(`Path must be absolute: received "${e}"`);let t=new URL("file:///");return t.pathname=qe(e.replace(/%/g,"%25").replace(/\\/g,"%5C")),t}var L=new TextEncoder,g=new TextDecoder,Ut=2**32;function ye(...e){let t=e.reduce((n,{length:i})=>n+i,0),r=new Uint8Array(t),o=0;for(let n of e)r.set(n,o),o+=n.length;return r}function k(e){let t=new Uint8Array(e.length);for(let r=0;r127)throw new TypeError("non-ASCII string encountered in encode()");t[r]=o}return t}function Se(e){if(Uint8Array.fromBase64)return Uint8Array.fromBase64(e);let t=atob(e),r=new Uint8Array(t.length);for(let o=0;onew TypeError(`CryptoKey does not support this operation, its ${t} must be ${e}`),W=(e,t)=>e.name===t;function je(e){return parseInt(e.name.slice(4),10)}function te(e,t){if(je(e.hash)!==t)throw T(`SHA-${t}`,"algorithm.hash")}function Ze(e){switch(e){case"ES256":return"P-256";case"ES384":return"P-384";case"ES512":return"P-521";default:throw new Error("unreachable")}}function Qe(e,t){if(t&&!e.usages.includes(t))throw new TypeError(`CryptoKey does not support this operation, its usages must include ${t}.`)}function Ee(e,t,r){switch(t){case"HS256":case"HS384":case"HS512":{if(!W(e.algorithm,"HMAC"))throw T("HMAC");te(e.algorithm,parseInt(t.slice(2),10));break}case"RS256":case"RS384":case"RS512":{if(!W(e.algorithm,"RSASSA-PKCS1-v1_5"))throw T("RSASSA-PKCS1-v1_5");te(e.algorithm,parseInt(t.slice(2),10));break}case"PS256":case"PS384":case"PS512":{if(!W(e.algorithm,"RSA-PSS"))throw T("RSA-PSS");te(e.algorithm,parseInt(t.slice(2),10));break}case"Ed25519":case"EdDSA":{if(!W(e.algorithm,"Ed25519"))throw T("Ed25519");break}case"ML-DSA-44":case"ML-DSA-65":case"ML-DSA-87":{if(!W(e.algorithm,t))throw T(t);break}case"ES256":case"ES384":case"ES512":{if(!W(e.algorithm,"ECDSA"))throw T("ECDSA");let o=Ze(t);if(e.algorithm.namedCurve!==o)throw T(o,"algorithm.namedCurve");break}default:throw new TypeError("CryptoKey does not support this operation")}Qe(e,r)}function we(e,t,...r){if(r=r.filter(Boolean),r.length>2){let o=r.pop();e+=`one of type ${r.join(", ")}, or ${o}.`}else r.length===2?e+=`one of type ${r[0]} or ${r[1]}.`:e+=`of type ${r[0]}.`;return t==null?e+=` Received ${t}`:typeof t=="function"&&t.name?e+=` Received function ${t.name}`:typeof t=="object"&&t!=null&&t.constructor?.name&&(e+=` Received an instance of ${t.constructor.name}`),e}var ge=(e,...t)=>we("Key must be ",e,...t),re=(e,t,...r)=>we(`Key for the ${e} algorithm must be `,t,...r);var m=class extends Error{static code="ERR_JOSE_GENERIC";code="ERR_JOSE_GENERIC";constructor(t,r){super(t,r),this.name=this.constructor.name,Error.captureStackTrace?.(this,this.constructor)}},w=class extends m{static code="ERR_JWT_CLAIM_VALIDATION_FAILED";code="ERR_JWT_CLAIM_VALIDATION_FAILED";claim;reason;payload;constructor(t,r,o="unspecified",n="unspecified"){super(t,{cause:{claim:o,reason:n,payload:r}}),this.claim=o,this.reason=n,this.payload=r}},M=class extends m{static code="ERR_JWT_EXPIRED";code="ERR_JWT_EXPIRED";claim;reason;payload;constructor(t,r,o="unspecified",n="unspecified"){super(t,{cause:{claim:o,reason:n,payload:r}}),this.claim=o,this.reason=n,this.payload=r}},F=class extends m{static code="ERR_JOSE_ALG_NOT_ALLOWED";code="ERR_JOSE_ALG_NOT_ALLOWED"},l=class extends m{static code="ERR_JOSE_NOT_SUPPORTED";code="ERR_JOSE_NOT_SUPPORTED"};var u=class extends m{static code="ERR_JWS_INVALID";code="ERR_JWS_INVALID"},v=class extends m{static code="ERR_JWT_INVALID";code="ERR_JWT_INVALID"};var H=class extends m{static code="ERR_JWKS_INVALID";code="ERR_JWKS_INVALID"},I=class extends m{static code="ERR_JWKS_NO_MATCHING_KEY";code="ERR_JWKS_NO_MATCHING_KEY";constructor(t="no applicable key found in the JSON Web Key Set",r){super(t,r)}},$=class extends m{[Symbol.asyncIterator];static code="ERR_JWKS_MULTIPLE_MATCHING_KEYS";code="ERR_JWKS_MULTIPLE_MATCHING_KEYS";constructor(t="multiple matching keys found in the JSON Web Key Set",r){super(t,r)}},V=class extends m{static code="ERR_JWKS_TIMEOUT";code="ERR_JWKS_TIMEOUT";constructor(t="request timed out",r){super(t,r)}},G=class extends m{static code="ERR_JWS_SIGNATURE_VERIFICATION_FAILED";code="ERR_JWS_SIGNATURE_VERIFICATION_FAILED";constructor(t="signature verification failed",r){super(t,r)}};var oe=e=>{if(e?.[Symbol.toStringTag]==="CryptoKey")return!0;try{return e instanceof CryptoKey}catch{return!1}},ne=e=>e?.[Symbol.toStringTag]==="KeyObject",ie=e=>oe(e)||ne(e);function se(e,t,r){try{return A(e)}catch{throw new r(`Failed to base64url decode the ${t}`)}}var et=e=>typeof e=="object"&&e!==null;function y(e){if(!et(e)||Object.prototype.toString.call(e)!=="[object Object]")return!1;if(Object.getPrototypeOf(e)===null)return!0;let t=e;for(;Object.getPrototypeOf(t)!==null;)t=Object.getPrototypeOf(t);return Object.getPrototypeOf(e)===t}function Ae(...e){let t=e.filter(Boolean);if(t.length===0||t.length===1)return!0;let r;for(let o of t){let n=Object.keys(o);if(!r||r.size===0){r=new Set(n);continue}for(let i of n){if(r.has(i))return!1;r.add(i)}}return!0}var B=e=>y(e)&&typeof e.kty=="string",be=e=>e.kty!=="oct"&&(e.kty==="AKP"&&typeof e.priv=="string"||typeof e.d=="string"),Re=e=>e.kty!=="oct"&&e.d===void 0&&e.priv===void 0,Te=e=>e.kty==="oct"&&typeof e.k=="string";function rt(e,t){if(e.startsWith("RS")||e.startsWith("PS")){let{modulusLength:r}=t.algorithm;if(typeof r!="number"||r<2048)throw new TypeError(`${e} requires key modulusLength to be 2048 bits or larger`)}}function ot(e,t){let r=`SHA-${e.slice(-3)}`;switch(e){case"HS256":case"HS384":case"HS512":return{hash:r,name:"HMAC"};case"PS256":case"PS384":case"PS512":return{hash:r,name:"RSA-PSS",saltLength:parseInt(e.slice(-3),10)>>3};case"RS256":case"RS384":case"RS512":return{hash:r,name:"RSASSA-PKCS1-v1_5"};case"ES256":case"ES384":case"ES512":return{hash:r,name:"ECDSA",namedCurve:t.namedCurve};case"Ed25519":case"EdDSA":return{name:"Ed25519"};case"ML-DSA-44":case"ML-DSA-65":case"ML-DSA-87":return{name:e};default:throw new l(`alg ${e} is not supported either by JOSE or your javascript runtime`)}}async function nt(e,t,r){if(t instanceof Uint8Array){if(!e.startsWith("HS"))throw new TypeError(ge(t,"CryptoKey","KeyObject","JSON Web Key"));return crypto.subtle.importKey("raw",t,{hash:`SHA-${e.slice(-3)}`,name:"HMAC"},!1,[r])}return Ee(t,e,r),t}async function Ke(e,t,r,o){let n=await nt(e,t,"verify");rt(e,n);let i=ot(e,n.algorithm);try{return await crypto.subtle.verify(i,n,r,o)}catch{return!1}}var X='Invalid or unsupported JWK "alg" (Algorithm) Parameter value';function it(e){let t,r;switch(e.kty){case"AKP":{switch(e.alg){case"ML-DSA-44":case"ML-DSA-65":case"ML-DSA-87":t={name:e.alg},r=e.priv?["sign"]:["verify"];break;default:throw new l(X)}break}case"RSA":{switch(e.alg){case"PS256":case"PS384":case"PS512":t={name:"RSA-PSS",hash:`SHA-${e.alg.slice(-3)}`},r=e.d?["sign"]:["verify"];break;case"RS256":case"RS384":case"RS512":t={name:"RSASSA-PKCS1-v1_5",hash:`SHA-${e.alg.slice(-3)}`},r=e.d?["sign"]:["verify"];break;case"RSA-OAEP":case"RSA-OAEP-256":case"RSA-OAEP-384":case"RSA-OAEP-512":t={name:"RSA-OAEP",hash:`SHA-${parseInt(e.alg.slice(-3),10)||1}`},r=e.d?["decrypt","unwrapKey"]:["encrypt","wrapKey"];break;default:throw new l(X)}break}case"EC":{switch(e.alg){case"ES256":case"ES384":case"ES512":t={name:"ECDSA",namedCurve:{ES256:"P-256",ES384:"P-384",ES512:"P-521"}[e.alg]},r=e.d?["sign"]:["verify"];break;case"ECDH-ES":case"ECDH-ES+A128KW":case"ECDH-ES+A192KW":case"ECDH-ES+A256KW":t={name:"ECDH",namedCurve:e.crv},r=e.d?["deriveBits"]:[];break;default:throw new l(X)}break}case"OKP":{switch(e.alg){case"Ed25519":case"EdDSA":t={name:"Ed25519"},r=e.d?["sign"]:["verify"];break;case"ECDH-ES":case"ECDH-ES+A128KW":case"ECDH-ES+A192KW":case"ECDH-ES+A256KW":t={name:e.crv},r=e.d?["deriveBits"]:[];break;default:throw new l(X)}break}default:throw new l('Invalid or unsupported JWK "kty" (Key Type) Parameter value')}return{algorithm:t,keyUsages:r}}async function O(e){if(!e.alg)throw new TypeError('"alg" argument is required when "jwk.alg" is not present');let{algorithm:t,keyUsages:r}=it(e),o={...e};return o.kty!=="AKP"&&delete o.alg,delete o.use,crypto.subtle.importKey("jwk",o,t,e.ext??!(e.d||e.priv),e.key_ops??r)}var J="given KeyObject instance cannot be used for this algorithm",N,_e=async(e,t,r,o=!1)=>{N||=new WeakMap;let n=N.get(e);if(n?.[r])return n[r];let i=await O({...t,alg:r});return o&&Object.freeze(e),n?n[r]=i:N.set(e,{[r]:i}),i},st=(e,t)=>{N||=new WeakMap;let r=N.get(e);if(r?.[t])return r[t];let o=e.type==="public",n=!!o,i;if(e.asymmetricKeyType==="x25519"){switch(t){case"ECDH-ES":case"ECDH-ES+A128KW":case"ECDH-ES+A192KW":case"ECDH-ES+A256KW":break;default:throw new TypeError(J)}i=e.toCryptoKey(e.asymmetricKeyType,n,o?[]:["deriveBits"])}if(e.asymmetricKeyType==="ed25519"){if(t!=="EdDSA"&&t!=="Ed25519")throw new TypeError(J);i=e.toCryptoKey(e.asymmetricKeyType,n,[o?"verify":"sign"])}switch(e.asymmetricKeyType){case"ml-dsa-44":case"ml-dsa-65":case"ml-dsa-87":{if(t!==e.asymmetricKeyType.toUpperCase())throw new TypeError(J);i=e.toCryptoKey(e.asymmetricKeyType,n,[o?"verify":"sign"])}}if(e.asymmetricKeyType==="rsa"){let s;switch(t){case"RSA-OAEP":s="SHA-1";break;case"RS256":case"PS256":case"RSA-OAEP-256":s="SHA-256";break;case"RS384":case"PS384":case"RSA-OAEP-384":s="SHA-384";break;case"RS512":case"PS512":case"RSA-OAEP-512":s="SHA-512";break;default:throw new TypeError(J)}if(t.startsWith("RSA-OAEP"))return e.toCryptoKey({name:"RSA-OAEP",hash:s},n,o?["encrypt"]:["decrypt"]);i=e.toCryptoKey({name:t.startsWith("PS")?"RSA-PSS":"RSASSA-PKCS1-v1_5",hash:s},n,[o?"verify":"sign"])}if(e.asymmetricKeyType==="ec"){let f=new Map([["prime256v1","P-256"],["secp384r1","P-384"],["secp521r1","P-521"]]).get(e.asymmetricKeyDetails?.namedCurve);if(!f)throw new TypeError(J);let p={ES256:"P-256",ES384:"P-384",ES512:"P-521"};p[t]&&f===p[t]&&(i=e.toCryptoKey({name:"ECDSA",namedCurve:f},n,[o?"verify":"sign"])),t.startsWith("ECDH-ES")&&(i=e.toCryptoKey({name:"ECDH",namedCurve:f},n,o?[]:["deriveBits"]))}if(!i)throw new TypeError(J);return r?r[t]=i:N.set(e,{[t]:i}),i};async function Pe(e,t){if(e instanceof Uint8Array||oe(e))return e;if(ne(e)){if(e.type==="secret")return e.export();if("toCryptoKey"in e&&typeof e.toCryptoKey=="function")try{return st(e,t)}catch(o){if(o instanceof TypeError)throw o}let r=e.export({format:"jwk"});return _e(e,r,t)}if(B(e))return e.k?A(e.k):_e(e,e,t,!0);throw new Error("unreachable")}async function Ce(e,t,r){if(!y(e))throw new TypeError("JWK must be an object");let o;switch(t??=e.alg,o??=r?.extractable??e.ext,e.kty){case"oct":if(typeof e.k!="string"||!e.k)throw new TypeError('missing "k" (Key Value) Parameter value');return A(e.k);case"RSA":if("oth"in e&&e.oth!==void 0)throw new l('RSA JWK "oth" (Other Primes Info) Parameter value is not supported');return O({...e,alg:t,ext:o});case"AKP":{if(typeof e.alg!="string"||!e.alg)throw new TypeError('missing "alg" (Algorithm) Parameter value');if(t!==void 0&&t!==e.alg)throw new TypeError("JWK alg and alg option value mismatch");return O({...e,ext:o})}case"EC":case"OKP":return O({...e,alg:t,ext:o});default:throw new l('Unsupported "kty" (Key Type) Parameter value')}}function xe(e,t,r,o,n){if(n.crit!==void 0&&o?.crit===void 0)throw new e('"crit" (Critical) Header Parameter MUST be integrity protected');if(!o||o.crit===void 0)return new Set;if(!Array.isArray(o.crit)||o.crit.length===0||o.crit.some(s=>typeof s!="string"||s.length===0))throw new e('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present');let i;r!==void 0?i=new Map([...Object.entries(r),...t.entries()]):i=t;for(let s of o.crit){if(!i.has(s))throw new l(`Extension Header Parameter "${s}" is not recognized`);if(n[s]===void 0)throw new e(`Extension Header Parameter "${s}" is missing`);if(i.get(s)&&o[s]===void 0)throw new e(`Extension Header Parameter "${s}" MUST be integrity protected`)}return new Set(o.crit)}function We(e,t){if(t!==void 0&&(!Array.isArray(t)||t.some(r=>typeof r!="string")))throw new TypeError(`"${e}" option must be an array of strings`);if(t)return new Set(t)}var D=e=>e?.[Symbol.toStringTag],ae=(e,t,r)=>{if(t.use!==void 0){let o;switch(r){case"sign":case"verify":o="sig";break;case"encrypt":case"decrypt":o="enc";break}if(t.use!==o)throw new TypeError(`Invalid key for this operation, its "use" must be "${o}" when present`)}if(t.alg!==void 0&&t.alg!==e)throw new TypeError(`Invalid key for this operation, its "alg" must be "${e}" when present`);if(Array.isArray(t.key_ops)){let o;switch(!0){case(r==="sign"||r==="verify"):case e==="dir":case e.includes("CBC-HS"):o=r;break;case e.startsWith("PBES2"):o="deriveBits";break;case/^A\d{3}(?:GCM)?(?:KW)?$/.test(e):!e.includes("GCM")&&e.endsWith("KW")?o=r==="encrypt"?"wrapKey":"unwrapKey":o=r;break;case(r==="encrypt"&&e.startsWith("RSA")):o="wrapKey";break;case r==="decrypt":o=e.startsWith("RSA")?"unwrapKey":"deriveBits";break}if(o&&t.key_ops?.includes?.(o)===!1)throw new TypeError(`Invalid key for this operation, its "key_ops" must include "${o}" when present`)}return!0},at=(e,t,r)=>{if(!(t instanceof Uint8Array)){if(B(t)){if(Te(t)&&ae(e,t,r))return;throw new TypeError('JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present')}if(!ie(t))throw new TypeError(re(e,t,"CryptoKey","KeyObject","JSON Web Key","Uint8Array"));if(t.type!=="secret")throw new TypeError(`${D(t)} instances for symmetric algorithms must be of type "secret"`)}},ct=(e,t,r)=>{if(B(t))switch(r){case"decrypt":case"sign":if(be(t)&&ae(e,t,r))return;throw new TypeError("JSON Web Key for this operation must be a private JWK");case"encrypt":case"verify":if(Re(t)&&ae(e,t,r))return;throw new TypeError("JSON Web Key for this operation must be a public JWK")}if(!ie(t))throw new TypeError(re(e,t,"CryptoKey","KeyObject","JSON Web Key"));if(t.type==="secret")throw new TypeError(`${D(t)} instances for asymmetric algorithms must not be of type "secret"`);if(t.type==="public")switch(r){case"sign":throw new TypeError(`${D(t)} instances for asymmetric algorithm signing must be of type "private"`);case"decrypt":throw new TypeError(`${D(t)} instances for asymmetric algorithm decryption must be of type "private"`)}if(t.type==="private")switch(r){case"verify":throw new TypeError(`${D(t)} instances for asymmetric algorithm verifying must be of type "public"`);case"encrypt":throw new TypeError(`${D(t)} instances for asymmetric algorithm encryption must be of type "public"`)}};function ve(e,t,r){switch(e.substring(0,2)){case"A1":case"A2":case"di":case"HS":case"PB":at(e,t,r);break;default:ct(e,t,r)}}async function Ie(e,t,r){if(!y(e))throw new u("Flattened JWS must be an object");if(e.protected===void 0&&e.header===void 0)throw new u('Flattened JWS must have either of the "protected" or "header" members');if(e.protected!==void 0&&typeof e.protected!="string")throw new u("JWS Protected Header incorrect type");if(e.payload===void 0)throw new u("JWS Payload missing");if(typeof e.signature!="string")throw new u("JWS Signature missing or incorrect type");if(e.header!==void 0&&!y(e.header))throw new u("JWS Unprotected Header incorrect type");let o={};if(e.protected)try{let q=A(e.protected);o=JSON.parse(g.decode(q))}catch{throw new u("JWS Protected Header is invalid")}if(!Ae(o,e.header))throw new u("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");let n={...o,...e.header},i=xe(u,new Map([["b64",!0]]),r?.crit,o,n),s=!0;if(i.has("b64")&&(s=o.b64,typeof s!="boolean"))throw new u('The "b64" (base64url-encode payload) Header Parameter must be a boolean');let{alg:f}=n;if(typeof f!="string"||!f)throw new u('JWS "alg" (Algorithm) Header Parameter missing or invalid');let p=r&&We("algorithms",r.algorithms);if(p&&!p.has(f))throw new F('"alg" (Algorithm) Header Parameter value not allowed');if(s){if(typeof e.payload!="string")throw new u("JWS Payload must be a string")}else if(typeof e.payload!="string"&&!(e.payload instanceof Uint8Array))throw new u("JWS Payload must be a string or an Uint8Array instance");let a=!1;typeof t=="function"&&(t=await t(o,e),a=!0),ve(f,t,"verify");let c=ye(e.protected!==void 0?k(e.protected):new Uint8Array,k("."),typeof e.payload=="string"?s?k(e.payload):L.encode(e.payload):e.payload),S=se(e.signature,"signature",u),C=await Pe(t,f);if(!await Ke(f,C,S,c))throw new G;let E;s?E=se(e.payload,"payload",u):typeof e.payload=="string"?E=L.encode(e.payload):E=e.payload;let R={payload:E};return e.protected!==void 0&&(R.protectedHeader=o),e.header!==void 0&&(R.unprotectedHeader=e.header),a?{...R,key:C}:R}async function Oe(e,t,r){if(e instanceof Uint8Array&&(e=g.decode(e)),typeof e!="string")throw new u("Compact JWS must be a string or Uint8Array");let{0:o,1:n,2:i,length:s}=e.split(".");if(s!==3)throw new u("Invalid Compact JWS");let f=await Ie({payload:n,protected:o,signature:i},t,r),p={payload:f.payload,protectedHeader:f.protectedHeader};return typeof t=="function"?{...p,key:f.key}:p}var ft=e=>Math.floor(e.getTime()/1e3),De=60,Ue=De*60,ce=Ue*24,ut=ce*7,pt=ce*365.25,dt=/^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i;function Je(e){let t=dt.exec(e);if(!t||t[4]&&t[1])throw new TypeError("Invalid time period format");let r=parseFloat(t[2]),o=t[3].toLowerCase(),n;switch(o){case"sec":case"secs":case"second":case"seconds":case"s":n=Math.round(r);break;case"minute":case"minutes":case"min":case"mins":case"m":n=Math.round(r*De);break;case"hour":case"hours":case"hr":case"hrs":case"h":n=Math.round(r*Ue);break;case"day":case"days":case"d":n=Math.round(r*ce);break;case"week":case"weeks":case"w":n=Math.round(r*ut);break;default:n=Math.round(r*pt);break}return t[1]==="-"||t[4]==="ago"?-n:n}var Ne=e=>e.includes("/")?e.toLowerCase():`application/${e.toLowerCase()}`,lt=(e,t)=>typeof e=="string"?t.includes(e):Array.isArray(e)?t.some(Set.prototype.has.bind(new Set(e))):!1;function Le(e,t,r={}){let o;try{o=JSON.parse(g.decode(t))}catch{}if(!y(o))throw new v("JWT Claims Set must be a top-level JSON object");let{typ:n}=r;if(n&&(typeof e.typ!="string"||Ne(e.typ)!==Ne(n)))throw new w('unexpected "typ" JWT header value',o,"typ","check_failed");let{requiredClaims:i=[],issuer:s,subject:f,audience:p,maxTokenAge:a}=r,c=[...i];a!==void 0&&c.push("iat"),p!==void 0&&c.push("aud"),f!==void 0&&c.push("sub"),s!==void 0&&c.push("iss");for(let E of new Set(c.reverse()))if(!(E in o))throw new w(`missing required "${E}" claim`,o,E,"missing");if(s&&!(Array.isArray(s)?s:[s]).includes(o.iss))throw new w('unexpected "iss" claim value',o,"iss","check_failed");if(f&&o.sub!==f)throw new w('unexpected "sub" claim value',o,"sub","check_failed");if(p&&!lt(o.aud,typeof p=="string"?[p]:p))throw new w('unexpected "aud" claim value',o,"aud","check_failed");let S;switch(typeof r.clockTolerance){case"string":S=Je(r.clockTolerance);break;case"number":S=r.clockTolerance;break;case"undefined":S=0;break;default:throw new TypeError("Invalid clockTolerance option type")}let{currentDate:C}=r,x=ft(C||new Date);if((o.iat!==void 0||a)&&typeof o.iat!="number")throw new w('"iat" claim must be a number',o,"iat","invalid");if(o.nbf!==void 0){if(typeof o.nbf!="number")throw new w('"nbf" claim must be a number',o,"nbf","invalid");if(o.nbf>x+S)throw new w('"nbf" claim timestamp check failed',o,"nbf","check_failed")}if(o.exp!==void 0){if(typeof o.exp!="number")throw new w('"exp" claim must be a number',o,"exp","invalid");if(o.exp<=x-S)throw new M('"exp" claim timestamp check failed',o,"exp","check_failed")}if(a){let E=x-o.iat,R=typeof a=="number"?a:Je(a);if(E-S>R)throw new M('"iat" claim timestamp check failed (too far in the past)',o,"iat","check_failed");if(E<0-S)throw new w('"iat" claim timestamp check failed (it should be in the past)',o,"iat","check_failed")}return o}async function z(e,t,r){let o=await Oe(e,t,r);if(o.protectedHeader.crit?.includes("b64")&&o.protectedHeader.b64===!1)throw new v("JWTs MUST NOT use unencoded payload");let i={payload:Le(o.protectedHeader,o.payload,r),protectedHeader:o.protectedHeader};return typeof t=="function"?{...i,key:o.key}:i}function ht(e){switch(typeof e=="string"&&e.slice(0,2)){case"RS":case"PS":return"RSA";case"ES":return"EC";case"Ed":return"OKP";case"ML":return"AKP";default:throw new l('Unsupported "alg" value for a JSON Web Key Set')}}function mt(e){return e&&typeof e=="object"&&Array.isArray(e.keys)&&e.keys.every(yt)}function yt(e){return y(e)}var fe=class{#r;#s=new WeakMap;constructor(t){if(!mt(t))throw new H("JSON Web Key Set malformed");this.#r=structuredClone(t)}jwks(){return this.#r}async getKey(t,r){let{alg:o,kid:n}={...t,...r?.header},i=ht(o),s=this.#r.keys.filter(a=>{let c=i===a.kty;if(c&&typeof n=="string"&&(c=n===a.kid),c&&(typeof a.alg=="string"||i==="AKP")&&(c=o===a.alg),c&&typeof a.use=="string"&&(c=a.use==="sig"),c&&Array.isArray(a.key_ops)&&(c=a.key_ops.includes("verify")),c)switch(o){case"ES256":c=a.crv==="P-256";break;case"ES384":c=a.crv==="P-384";break;case"ES512":c=a.crv==="P-521";break;case"Ed25519":case"EdDSA":c=a.crv==="Ed25519";break}return c}),{0:f,length:p}=s;if(p===0)throw new I;if(p!==1){let a=new $,c=this.#s;throw a[Symbol.asyncIterator]=async function*(){for(let S of s)try{yield await Me(c,S,o)}catch{}},a}return Me(this.#s,f,o)}};async function Me(e,t,r){let o=e.get(t)||e.set(t,{}).get(t);if(o[r]===void 0){let n=await Ce({...t,ext:!0},r);if(n instanceof Uint8Array||n.type!=="public")throw new H("JSON Web Key Set members must be public keys");o[r]=n}return o[r]}function U(e){let t=new fe(e),r=async(o,n)=>t.getKey(o,n);return Object.defineProperties(r,{jwks:{value:()=>structuredClone(t.jwks()),enumerable:!1,configurable:!1,writable:!1}}),r}function St(){return typeof WebSocketPair<"u"||typeof navigator<"u"&&navigator.userAgent==="Cloudflare-Workers"||typeof EdgeRuntime<"u"&&EdgeRuntime==="vercel"}var ue;(typeof navigator>"u"||!navigator.userAgent?.startsWith?.("Mozilla/5.0 "))&&(ue="jose/v6.2.3");var He=Symbol();async function Et(e,t,r,o=fetch){let n=await o(e,{method:"GET",signal:r,redirect:"manual",headers:t}).catch(i=>{throw i.name==="TimeoutError"?new V:i});if(n.status!==200)throw new m("Expected 200 OK from the JSON Web Key Set HTTP response");try{return await n.json()}catch{throw new m("Failed to parse the JSON Web Key Set HTTP response as JSON")}}var Y=Symbol();function wt(e,t){return!(typeof e!="object"||e===null||!("uat"in e)||typeof e.uat!="number"||Date.now()-e.uat>=t||!("jwks"in e)||!y(e.jwks)||!Array.isArray(e.jwks.keys)||!Array.prototype.every.call(e.jwks.keys,y))}var pe=class{#r;#s;#c;#a;#o;#e;#t;#f;#n;#i;constructor(t,r){if(!(t instanceof URL))throw new TypeError("url must be an instance of URL");this.#r=new URL(t.href),this.#s=typeof r?.timeoutDuration=="number"?r?.timeoutDuration:5e3,this.#c=typeof r?.cooldownDuration=="number"?r?.cooldownDuration:3e4,this.#a=typeof r?.cacheMaxAge=="number"?r?.cacheMaxAge:6e5,this.#t=new Headers(r?.headers),ue&&!this.#t.has("User-Agent")&&this.#t.set("User-Agent",ue),this.#t.has("accept")||(this.#t.set("accept","application/json"),this.#t.append("accept","application/jwk-set+json")),this.#f=r?.[He],r?.[Y]!==void 0&&(this.#i=r?.[Y],wt(r?.[Y],this.#a)&&(this.#o=this.#i.uat,this.#n=U(this.#i.jwks)))}pendingFetch(){return!!this.#e}coolingDown(){return typeof this.#o=="number"?Date.now(){this.#n=U(t),this.#i&&(this.#i.uat=Date.now(),this.#i.jwks=t),this.#o=Date.now(),this.#e=void 0}).catch(t=>{throw this.#e=void 0,t}),await this.#e}};function de(e,t){let r=new pe(e,t),o=async(n,i)=>r.getKey(n,i);return Object.defineProperties(o,{coolingDown:{get:()=>r.coolingDown(),enumerable:!0,configurable:!1},fresh:{get:()=>r.fresh(),enumerable:!0,configurable:!1},reload:{value:()=>r.reload(),enumerable:!0,configurable:!1,writable:!1},reloading:{get:()=>r.pendingFetch(),enumerable:!0,configurable:!1},jwks:{value:()=>r.jwks(),enumerable:!0,configurable:!1,writable:!1}}),o}function le(e){let t;if(typeof e=="string"){let r=e.split(".");(r.length===3||r.length===5)&&([t]=r)}else if(typeof e=="object"&&e)if("protected"in e)t=e.protected;else throw new TypeError("Token does not contain a Protected Header");try{if(typeof t!="string"||!t)throw new Error;let r=JSON.parse(g.decode(A(t)));if(!y(r))throw new Error;return r}catch{throw new TypeError("Invalid Token or Protected Header formatting")}}var b={BootError:h.ServiceUnavailable,InvalidWorkerResponse:h.InternalServerError,WorkerLimit:546},At={[b.BootError]:"BOOT_ERROR",[b.InvalidWorkerResponse]:"WORKER_ERROR",[b.WorkerLimit]:"WORKER_LIMIT"},bt={[b.BootError]:"Worker failed to boot (please check logs)",[b.InvalidWorkerResponse]:"Function exited due to an error (please check logs)",[b.WorkerLimit]:"Worker failed to respond due to a resource limit (please check logs)"},Rt=["HOME","HOSTNAME","PATH","PWD"],Ve=Deno.env.get("SUPABASE_INTERNAL_HOST_PORT"),Tt=Deno.env.get("SUPABASE_INTERNAL_JWT_SECRET"),Kt=new URL("/auth/v1/.well-known/jwks.json",Deno.env.get("SUPABASE_URL")),_t=Deno.env.get("SUPABASE_INTERNAL_DEBUG")==="true",Pt=Deno.env.get("SUPABASE_INTERNAL_FUNCTIONS_CONFIG"),Be=Deno.env.get("SUPABASE_INTERNAL_PUBLISHABLE_KEY"),ke=Deno.env.get("SUPABASE_INTERNAL_SECRET_KEY"),Fe=parseInt(Deno.env.get("SUPABASE_INTERNAL_WALLCLOCK_LIMIT_SEC")),Ct=new Map([[Deno.errors.InvalidWorkerCreation,b.BootError],[Deno.errors.InvalidWorkerResponse,b.InvalidWorkerResponse],[Deno.errors.WorkerRequestCancelled,b.WorkerLimit]]),$e=`Serving functions on http://127.0.0.1:${Ve}/functions/v1/`;function P(e,t,r={}){let o={...r},n=null;return e&&(typeof e=="object"?(o["Content-Type"]="application/json",n=JSON.stringify(e)):typeof e=="string"?(o["Content-Type"]="text/plain",n=e):n=null),new Response(n,{status:t,headers:o})}var K=(()=>{try{let e=JSON.parse(Pt);return _t&&console.log("Functions config:",JSON.stringify(e,null,2)),e}catch(e){throw new Error("Failed to parse functions config",{cause:e})}})();function xt(e){let t=e.split(" "),[r,o]=t;return r!=="Bearer"||t.length!==2?null:o}function Wt(e){let t=e.headers.get("authorization"),o=e.headers.get("sb-api-key")?.replace("Bearer","")?.trim();if(!t&&!o)throw new Error("Missing authorization header");let n=xt(t??""),i=!n||n.startsWith("sb_")?o:n;if(!i)throw new Error("Auth header is not 'Bearer {token}'");return i}async function vt(e,t){let o=new TextEncoder().encode(e);try{await z(t,o)}catch(n){return console.error("Symmetric Legacy JWT verification error",n),!1}return!0}var he=(()=>{try{return U(JSON.parse(Deno.env.get("SUPABASE_JWKS")))}catch{return null}})();async function It(e,t){try{he||(he=de(new URL(e))),await z(t,he)}catch(r){return console.error("Asymmetric JWT verification error",r),!1}return!0}async function Ot(e,t,r){let{alg:o}=le(r);return o==="HS256"?(console.log(`Legacy token type detected, attempting ${o} verification.`),await vt(e,r)):o==="ES256"||o==="RS256"?await It(t,r):!1}async function Jt({entrypointPath:e,importMapPath:t}){if(t)return!1;let r=Q(ee(e),"package.json");try{await Deno.lstat(r)}catch(o){if(o instanceof Deno.errors.NotFound)return!1}return!0}function Nt(e){let t=new URL(e.url),r=e.headers.get("x-forwarded-host");t.hostname=r??t.hostname;let o=new Request(t,e.clone());return o.headers.delete("sb-api-key"),EdgeRuntime.applySupabaseTag(e,o),o}Deno.serve({handler:async e=>{let t=new URL(e.url),{pathname:r}=t;if(r==="/_internal/health")return P({message:"ok"},h.OK);if(r==="/_internal/metric"){let d=await EdgeRuntime.getRuntimeMetrics();return Response.json(d)}let n=r.split("/")[1];if(!n||!(n in K))return P("Function not found",h.NotFound);if(e.method!=="OPTIONS"&&K[n].verifyJWT)try{let d=Wt(e);if(!await Ot(Tt,Kt,d))return P({msg:"Invalid JWT"},h.Unauthorized)}catch(d){return console.error(d),P({msg:d.toString()},h.Unauthorized)}let i=ee(K[n].entrypointPath);console.error(`serving the request with ${i}`);let s=256,f=isFinite(Fe)?Fe*1e3:400*1e3,p=!1,a={...Deno.env.toObject(),...Object.fromEntries(Object.entries(K[n].env??{}).filter(([d,_])=>!d.startsWith("SUPABASE_")))};Be&&(a.SUPABASE_PUBLISHABLE_KEYS=JSON.stringify({default:Be})),ke&&(a.SUPABASE_SECRET_KEYS=JSON.stringify({default:ke}));let c=Object.entries(a).filter(([d,_])=>!Rt.includes(d)&&!d.startsWith("SUPABASE_INTERNAL_")),S=!1,C="",x=1e3,E=2e3,R="tc39",q=Q(Deno.cwd(),K[n].entrypointPath),Ge=me(q).href,Xe=await Jt(K[n]),ze=K[n].staticFiles;try{let d=await EdgeRuntime.userWorkers.create({servicePath:i,memoryLimitMb:s,workerTimeoutMs:f,noModuleCache:p,noNpm:!Xe,importMapPath:K[n].importMapPath,envVars:c,forceCreate:S,customModuleRoot:C,cpuTimeSoftLimitMs:x,cpuTimeHardLimitMs:E,decoratorType:R,maybeEntrypoint:Ge,context:{useReadSyncFileAPI:!0},staticPatterns:ze}),_=Nt(e);return await d.fetch(_)}catch(d){console.error(d);for(let[_,j]of Ct.entries())if(_!==void 0&&d instanceof _)return P({code:At[j],message:bt[j]},j);return P({code:Z[h.InternalServerError],message:"Request failed due to an internal server error",trace:JSON.stringify(d.stack)},h.InternalServerError)}},onListen:()=>{try{let e=Deno.env.get("SUPABASE_INTERNAL_FUNCTIONS_CONFIG");if(e){let r=JSON.parse(e),o=Object.keys(r),i=o.slice(0,5).map(f=>` - http://127.0.0.1:${Ve}/functions/v1/${f}`),s=o.length>0?` +var m={OK:200,Unauthorized:401,NotFound:404,InternalServerError:500,ServiceUnavailable:503},ee={[m.OK]:"OK",[m.Unauthorized]:"Unauthorized",[m.NotFound]:"Not Found",[m.InternalServerError]:"Internal Server Error",[m.ServiceUnavailable]:"Service Unavailable"};function je(e){let t=e.startsWith("/"),r=[];for(let n of e.split("/"))if(!(n===""||n===".")){if(n===".."){r.length>0&&r[r.length-1]!==".."?r.pop():t||r.push("..");continue}r.push(n)}let o=r.join("/");return t?"/"+o:o===""?".":o}function te(...e){let t=e.filter(r=>r.length>0).join("/");return t===""?".":je(t)}function re(e){if(e.length===0)return".";let t=e.length;for(;t>1&&e[t-1]==="/";)t-=1;let r=e.slice(0,t),o=r.lastIndexOf("/");return o===-1?".":o===0?"/":r.slice(0,o)}function Qe(e){return e.replace(/\s/g,t=>`%${t.charCodeAt(0).toString(16).padStart(2,"0").toUpperCase()}`)}function Ee(e){if(!e.startsWith("/"))throw new TypeError(`Path must be absolute: received "${e}"`);let t=new URL("file:///");return t.pathname=Qe(e.replace(/%/g,"%25").replace(/\\/g,"%5C")),t}var M=new TextEncoder,A=new TextDecoder,Mt=2**32;function we(...e){let t=e.reduce((n,{length:i})=>n+i,0),r=new Uint8Array(t),o=0;for(let n of e)r.set(n,o),o+=n.length;return r}function $(e){let t=new Uint8Array(e.length);for(let r=0;r127)throw new TypeError("non-ASCII string encountered in encode()");t[r]=o}return t}function Ae(e){if(Uint8Array.fromBase64)return Uint8Array.fromBase64(e);let t=atob(e),r=new Uint8Array(t.length);for(let o=0;onew TypeError(`CryptoKey does not support this operation, its ${t} must be ${e}`),I=(e,t)=>e.name===t;function et(e){return parseInt(e.name.slice(4),10)}function oe(e,t){if(et(e.hash)!==t)throw K(`SHA-${t}`,"algorithm.hash")}function tt(e){switch(e){case"ES256":return"P-256";case"ES384":return"P-384";case"ES512":return"P-521";default:throw new Error("unreachable")}}function rt(e,t){if(t&&!e.usages.includes(t))throw new TypeError(`CryptoKey does not support this operation, its usages must include ${t}.`)}function ge(e,t,r){switch(t){case"HS256":case"HS384":case"HS512":{if(!I(e.algorithm,"HMAC"))throw K("HMAC");oe(e.algorithm,parseInt(t.slice(2),10));break}case"RS256":case"RS384":case"RS512":{if(!I(e.algorithm,"RSASSA-PKCS1-v1_5"))throw K("RSASSA-PKCS1-v1_5");oe(e.algorithm,parseInt(t.slice(2),10));break}case"PS256":case"PS384":case"PS512":{if(!I(e.algorithm,"RSA-PSS"))throw K("RSA-PSS");oe(e.algorithm,parseInt(t.slice(2),10));break}case"Ed25519":case"EdDSA":{if(!I(e.algorithm,"Ed25519"))throw K("Ed25519");break}case"ML-DSA-44":case"ML-DSA-65":case"ML-DSA-87":{if(!I(e.algorithm,t))throw K(t);break}case"ES256":case"ES384":case"ES512":{if(!I(e.algorithm,"ECDSA"))throw K("ECDSA");let o=tt(t);if(e.algorithm.namedCurve!==o)throw K(o,"algorithm.namedCurve");break}default:throw new TypeError("CryptoKey does not support this operation")}rt(e,r)}function be(e,t,...r){if(r=r.filter(Boolean),r.length>2){let o=r.pop();e+=`one of type ${r.join(", ")}, or ${o}.`}else r.length===2?e+=`one of type ${r[0]} or ${r[1]}.`:e+=`of type ${r[0]}.`;return t==null?e+=` Received ${t}`:typeof t=="function"&&t.name?e+=` Received function ${t.name}`:typeof t=="object"&&t!=null&&t.constructor?.name&&(e+=` Received an instance of ${t.constructor.name}`),e}var Re=(e,...t)=>be("Key must be ",e,...t),ne=(e,t,...r)=>be(`Key for the ${e} algorithm must be `,t,...r);var h=class extends Error{static code="ERR_JOSE_GENERIC";code="ERR_JOSE_GENERIC";constructor(t,r){super(t,r),this.name=this.constructor.name,Error.captureStackTrace?.(this,this.constructor)}},w=class extends h{static code="ERR_JWT_CLAIM_VALIDATION_FAILED";code="ERR_JWT_CLAIM_VALIDATION_FAILED";claim;reason;payload;constructor(t,r,o="unspecified",n="unspecified"){super(t,{cause:{claim:o,reason:n,payload:r}}),this.claim=o,this.reason=n,this.payload=r}},F=class extends h{static code="ERR_JWT_EXPIRED";code="ERR_JWT_EXPIRED";claim;reason;payload;constructor(t,r,o="unspecified",n="unspecified"){super(t,{cause:{claim:o,reason:n,payload:r}}),this.claim=o,this.reason=n,this.payload=r}},V=class extends h{static code="ERR_JOSE_ALG_NOT_ALLOWED";code="ERR_JOSE_ALG_NOT_ALLOWED"},l=class extends h{static code="ERR_JOSE_NOT_SUPPORTED";code="ERR_JOSE_NOT_SUPPORTED"};var u=class extends h{static code="ERR_JWS_INVALID";code="ERR_JWS_INVALID"},W=class extends h{static code="ERR_JWT_INVALID";code="ERR_JWT_INVALID"};var B=class extends h{static code="ERR_JWKS_INVALID";code="ERR_JWKS_INVALID"},v=class extends h{static code="ERR_JWKS_NO_MATCHING_KEY";code="ERR_JWKS_NO_MATCHING_KEY";constructor(t="no applicable key found in the JSON Web Key Set",r){super(t,r)}},G=class extends h{[Symbol.asyncIterator];static code="ERR_JWKS_MULTIPLE_MATCHING_KEYS";code="ERR_JWKS_MULTIPLE_MATCHING_KEYS";constructor(t="multiple matching keys found in the JSON Web Key Set",r){super(t,r)}},X=class extends h{static code="ERR_JWKS_TIMEOUT";code="ERR_JWKS_TIMEOUT";constructor(t="request timed out",r){super(t,r)}},Y=class extends h{static code="ERR_JWS_SIGNATURE_VERIFICATION_FAILED";code="ERR_JWS_SIGNATURE_VERIFICATION_FAILED";constructor(t="signature verification failed",r){super(t,r)}};var ie=e=>{if(e?.[Symbol.toStringTag]==="CryptoKey")return!0;try{return e instanceof CryptoKey}catch{return!1}},se=e=>e?.[Symbol.toStringTag]==="KeyObject",ae=e=>ie(e)||se(e);function ce(e,t,r){try{return g(e)}catch{throw new r(`Failed to base64url decode the ${t}`)}}var ot=e=>typeof e=="object"&&e!==null;function y(e){if(!ot(e)||Object.prototype.toString.call(e)!=="[object Object]")return!1;if(Object.getPrototypeOf(e)===null)return!0;let t=e;for(;Object.getPrototypeOf(t)!==null;)t=Object.getPrototypeOf(t);return Object.getPrototypeOf(e)===t}function Te(...e){let t=e.filter(Boolean);if(t.length===0||t.length===1)return!0;let r;for(let o of t){let n=Object.keys(o);if(!r||r.size===0){r=new Set(n);continue}for(let i of n){if(r.has(i))return!1;r.add(i)}}return!0}var k=e=>y(e)&&typeof e.kty=="string",Ke=e=>e.kty!=="oct"&&(e.kty==="AKP"&&typeof e.priv=="string"||typeof e.d=="string"),_e=e=>e.kty!=="oct"&&e.d===void 0&&e.priv===void 0,Pe=e=>e.kty==="oct"&&typeof e.k=="string";function it(e,t){if(e.startsWith("RS")||e.startsWith("PS")){let{modulusLength:r}=t.algorithm;if(typeof r!="number"||r<2048)throw new TypeError(`${e} requires key modulusLength to be 2048 bits or larger`)}}function st(e,t){let r=`SHA-${e.slice(-3)}`;switch(e){case"HS256":case"HS384":case"HS512":return{hash:r,name:"HMAC"};case"PS256":case"PS384":case"PS512":return{hash:r,name:"RSA-PSS",saltLength:parseInt(e.slice(-3),10)>>3};case"RS256":case"RS384":case"RS512":return{hash:r,name:"RSASSA-PKCS1-v1_5"};case"ES256":case"ES384":case"ES512":return{hash:r,name:"ECDSA",namedCurve:t.namedCurve};case"Ed25519":case"EdDSA":return{name:"Ed25519"};case"ML-DSA-44":case"ML-DSA-65":case"ML-DSA-87":return{name:e};default:throw new l(`alg ${e} is not supported either by JOSE or your javascript runtime`)}}async function at(e,t,r){if(t instanceof Uint8Array){if(!e.startsWith("HS"))throw new TypeError(Re(t,"CryptoKey","KeyObject","JSON Web Key"));return crypto.subtle.importKey("raw",t,{hash:`SHA-${e.slice(-3)}`,name:"HMAC"},!1,[r])}return ge(t,e,r),t}async function Ce(e,t,r,o){let n=await at(e,t,"verify");it(e,n);let i=st(e,n.algorithm);try{return await crypto.subtle.verify(i,n,r,o)}catch{return!1}}var z='Invalid or unsupported JWK "alg" (Algorithm) Parameter value';function ct(e){let t,r;switch(e.kty){case"AKP":{switch(e.alg){case"ML-DSA-44":case"ML-DSA-65":case"ML-DSA-87":t={name:e.alg},r=e.priv?["sign"]:["verify"];break;default:throw new l(z)}break}case"RSA":{switch(e.alg){case"PS256":case"PS384":case"PS512":t={name:"RSA-PSS",hash:`SHA-${e.alg.slice(-3)}`},r=e.d?["sign"]:["verify"];break;case"RS256":case"RS384":case"RS512":t={name:"RSASSA-PKCS1-v1_5",hash:`SHA-${e.alg.slice(-3)}`},r=e.d?["sign"]:["verify"];break;case"RSA-OAEP":case"RSA-OAEP-256":case"RSA-OAEP-384":case"RSA-OAEP-512":t={name:"RSA-OAEP",hash:`SHA-${parseInt(e.alg.slice(-3),10)||1}`},r=e.d?["decrypt","unwrapKey"]:["encrypt","wrapKey"];break;default:throw new l(z)}break}case"EC":{switch(e.alg){case"ES256":case"ES384":case"ES512":t={name:"ECDSA",namedCurve:{ES256:"P-256",ES384:"P-384",ES512:"P-521"}[e.alg]},r=e.d?["sign"]:["verify"];break;case"ECDH-ES":case"ECDH-ES+A128KW":case"ECDH-ES+A192KW":case"ECDH-ES+A256KW":t={name:"ECDH",namedCurve:e.crv},r=e.d?["deriveBits"]:[];break;default:throw new l(z)}break}case"OKP":{switch(e.alg){case"Ed25519":case"EdDSA":t={name:"Ed25519"},r=e.d?["sign"]:["verify"];break;case"ECDH-ES":case"ECDH-ES+A128KW":case"ECDH-ES+A192KW":case"ECDH-ES+A256KW":t={name:e.crv},r=e.d?["deriveBits"]:[];break;default:throw new l(z)}break}default:throw new l('Invalid or unsupported JWK "kty" (Key Type) Parameter value')}return{algorithm:t,keyUsages:r}}async function J(e){if(!e.alg)throw new TypeError('"alg" argument is required when "jwk.alg" is not present');let{algorithm:t,keyUsages:r}=ct(e),o={...e};return o.kty!=="AKP"&&delete o.alg,delete o.use,crypto.subtle.importKey("jwk",o,t,e.ext??!(e.d||e.priv),e.key_ops??r)}var O="given KeyObject instance cannot be used for this algorithm",N,xe=async(e,t,r,o=!1)=>{N||=new WeakMap;let n=N.get(e);if(n?.[r])return n[r];let i=await J({...t,alg:r});return o&&Object.freeze(e),n?n[r]=i:N.set(e,{[r]:i}),i},ft=(e,t)=>{N||=new WeakMap;let r=N.get(e);if(r?.[t])return r[t];let o=e.type==="public",n=!!o,i;if(e.asymmetricKeyType==="x25519"){switch(t){case"ECDH-ES":case"ECDH-ES+A128KW":case"ECDH-ES+A192KW":case"ECDH-ES+A256KW":break;default:throw new TypeError(O)}i=e.toCryptoKey(e.asymmetricKeyType,n,o?[]:["deriveBits"])}if(e.asymmetricKeyType==="ed25519"){if(t!=="EdDSA"&&t!=="Ed25519")throw new TypeError(O);i=e.toCryptoKey(e.asymmetricKeyType,n,[o?"verify":"sign"])}switch(e.asymmetricKeyType){case"ml-dsa-44":case"ml-dsa-65":case"ml-dsa-87":{if(t!==e.asymmetricKeyType.toUpperCase())throw new TypeError(O);i=e.toCryptoKey(e.asymmetricKeyType,n,[o?"verify":"sign"])}}if(e.asymmetricKeyType==="rsa"){let s;switch(t){case"RSA-OAEP":s="SHA-1";break;case"RS256":case"PS256":case"RSA-OAEP-256":s="SHA-256";break;case"RS384":case"PS384":case"RSA-OAEP-384":s="SHA-384";break;case"RS512":case"PS512":case"RSA-OAEP-512":s="SHA-512";break;default:throw new TypeError(O)}if(t.startsWith("RSA-OAEP"))return e.toCryptoKey({name:"RSA-OAEP",hash:s},n,o?["encrypt"]:["decrypt"]);i=e.toCryptoKey({name:t.startsWith("PS")?"RSA-PSS":"RSASSA-PKCS1-v1_5",hash:s},n,[o?"verify":"sign"])}if(e.asymmetricKeyType==="ec"){let f=new Map([["prime256v1","P-256"],["secp384r1","P-384"],["secp521r1","P-521"]]).get(e.asymmetricKeyDetails?.namedCurve);if(!f)throw new TypeError(O);let d={ES256:"P-256",ES384:"P-384",ES512:"P-521"};d[t]&&f===d[t]&&(i=e.toCryptoKey({name:"ECDSA",namedCurve:f},n,[o?"verify":"sign"])),t.startsWith("ECDH-ES")&&(i=e.toCryptoKey({name:"ECDH",namedCurve:f},n,o?[]:["deriveBits"]))}if(!i)throw new TypeError(O);return r?r[t]=i:N.set(e,{[t]:i}),i};async function Ie(e,t){if(e instanceof Uint8Array||ie(e))return e;if(se(e)){if(e.type==="secret")return e.export();if("toCryptoKey"in e&&typeof e.toCryptoKey=="function")try{return ft(e,t)}catch(o){if(o instanceof TypeError)throw o}let r=e.export({format:"jwk"});return xe(e,r,t)}if(k(e))return e.k?g(e.k):xe(e,e,t,!0);throw new Error("unreachable")}async function We(e,t,r){if(!y(e))throw new TypeError("JWK must be an object");let o;switch(t??=e.alg,o??=r?.extractable??e.ext,e.kty){case"oct":if(typeof e.k!="string"||!e.k)throw new TypeError('missing "k" (Key Value) Parameter value');return g(e.k);case"RSA":if("oth"in e&&e.oth!==void 0)throw new l('RSA JWK "oth" (Other Primes Info) Parameter value is not supported');return J({...e,alg:t,ext:o});case"AKP":{if(typeof e.alg!="string"||!e.alg)throw new TypeError('missing "alg" (Algorithm) Parameter value');if(t!==void 0&&t!==e.alg)throw new TypeError("JWK alg and alg option value mismatch");return J({...e,ext:o})}case"EC":case"OKP":return J({...e,alg:t,ext:o});default:throw new l('Unsupported "kty" (Key Type) Parameter value')}}function ve(e,t,r,o,n){if(n.crit!==void 0&&o?.crit===void 0)throw new e('"crit" (Critical) Header Parameter MUST be integrity protected');if(!o||o.crit===void 0)return new Set;if(!Array.isArray(o.crit)||o.crit.length===0||o.crit.some(s=>typeof s!="string"||s.length===0))throw new e('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present');let i;r!==void 0?i=new Map([...Object.entries(r),...t.entries()]):i=t;for(let s of o.crit){if(!i.has(s))throw new l(`Extension Header Parameter "${s}" is not recognized`);if(n[s]===void 0)throw new e(`Extension Header Parameter "${s}" is missing`);if(i.get(s)&&o[s]===void 0)throw new e(`Extension Header Parameter "${s}" MUST be integrity protected`)}return new Set(o.crit)}function Je(e,t){if(t!==void 0&&(!Array.isArray(t)||t.some(r=>typeof r!="string")))throw new TypeError(`"${e}" option must be an array of strings`);if(t)return new Set(t)}var U=e=>e?.[Symbol.toStringTag],fe=(e,t,r)=>{if(t.use!==void 0){let o;switch(r){case"sign":case"verify":o="sig";break;case"encrypt":case"decrypt":o="enc";break}if(t.use!==o)throw new TypeError(`Invalid key for this operation, its "use" must be "${o}" when present`)}if(t.alg!==void 0&&t.alg!==e)throw new TypeError(`Invalid key for this operation, its "alg" must be "${e}" when present`);if(Array.isArray(t.key_ops)){let o;switch(!0){case(r==="sign"||r==="verify"):case e==="dir":case e.includes("CBC-HS"):o=r;break;case e.startsWith("PBES2"):o="deriveBits";break;case/^A\d{3}(?:GCM)?(?:KW)?$/.test(e):!e.includes("GCM")&&e.endsWith("KW")?o=r==="encrypt"?"wrapKey":"unwrapKey":o=r;break;case(r==="encrypt"&&e.startsWith("RSA")):o="wrapKey";break;case r==="decrypt":o=e.startsWith("RSA")?"unwrapKey":"deriveBits";break}if(o&&t.key_ops?.includes?.(o)===!1)throw new TypeError(`Invalid key for this operation, its "key_ops" must include "${o}" when present`)}return!0},ut=(e,t,r)=>{if(!(t instanceof Uint8Array)){if(k(t)){if(Pe(t)&&fe(e,t,r))return;throw new TypeError('JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present')}if(!ae(t))throw new TypeError(ne(e,t,"CryptoKey","KeyObject","JSON Web Key","Uint8Array"));if(t.type!=="secret")throw new TypeError(`${U(t)} instances for symmetric algorithms must be of type "secret"`)}},dt=(e,t,r)=>{if(k(t))switch(r){case"decrypt":case"sign":if(Ke(t)&&fe(e,t,r))return;throw new TypeError("JSON Web Key for this operation must be a private JWK");case"encrypt":case"verify":if(_e(t)&&fe(e,t,r))return;throw new TypeError("JSON Web Key for this operation must be a public JWK")}if(!ae(t))throw new TypeError(ne(e,t,"CryptoKey","KeyObject","JSON Web Key"));if(t.type==="secret")throw new TypeError(`${U(t)} instances for asymmetric algorithms must not be of type "secret"`);if(t.type==="public")switch(r){case"sign":throw new TypeError(`${U(t)} instances for asymmetric algorithm signing must be of type "private"`);case"decrypt":throw new TypeError(`${U(t)} instances for asymmetric algorithm decryption must be of type "private"`)}if(t.type==="private")switch(r){case"verify":throw new TypeError(`${U(t)} instances for asymmetric algorithm verifying must be of type "public"`);case"encrypt":throw new TypeError(`${U(t)} instances for asymmetric algorithm encryption must be of type "public"`)}};function Oe(e,t,r){switch(e.substring(0,2)){case"A1":case"A2":case"di":case"HS":case"PB":ut(e,t,r);break;default:dt(e,t,r)}}async function Ne(e,t,r){if(!y(e))throw new u("Flattened JWS must be an object");if(e.protected===void 0&&e.header===void 0)throw new u('Flattened JWS must have either of the "protected" or "header" members');if(e.protected!==void 0&&typeof e.protected!="string")throw new u("JWS Protected Header incorrect type");if(e.payload===void 0)throw new u("JWS Payload missing");if(typeof e.signature!="string")throw new u("JWS Signature missing or incorrect type");if(e.header!==void 0&&!y(e.header))throw new u("JWS Unprotected Header incorrect type");let o={};if(e.protected)try{let j=g(e.protected);o=JSON.parse(A.decode(j))}catch{throw new u("JWS Protected Header is invalid")}if(!Te(o,e.header))throw new u("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");let n={...o,...e.header},i=ve(u,new Map([["b64",!0]]),r?.crit,o,n),s=!0;if(i.has("b64")&&(s=o.b64,typeof s!="boolean"))throw new u('The "b64" (base64url-encode payload) Header Parameter must be a boolean');let{alg:f}=n;if(typeof f!="string"||!f)throw new u('JWS "alg" (Algorithm) Header Parameter missing or invalid');let d=r&&Je("algorithms",r.algorithms);if(d&&!d.has(f))throw new V('"alg" (Algorithm) Header Parameter value not allowed');if(s){if(typeof e.payload!="string")throw new u("JWS Payload must be a string")}else if(typeof e.payload!="string"&&!(e.payload instanceof Uint8Array))throw new u("JWS Payload must be a string or an Uint8Array instance");let a=!1;typeof t=="function"&&(t=await t(o,e),a=!0),Oe(f,t,"verify");let c=we(e.protected!==void 0?$(e.protected):new Uint8Array,$("."),typeof e.payload=="string"?s?$(e.payload):M.encode(e.payload):e.payload),S=ce(e.signature,"signature",u),C=await Ie(t,f);if(!await Ce(f,C,S,c))throw new Y;let E;s?E=ce(e.payload,"payload",u):typeof e.payload=="string"?E=M.encode(e.payload):E=e.payload;let T={payload:E};return e.protected!==void 0&&(T.protectedHeader=o),e.header!==void 0&&(T.unprotectedHeader=e.header),a?{...T,key:C}:T}async function Ue(e,t,r){if(e instanceof Uint8Array&&(e=A.decode(e)),typeof e!="string")throw new u("Compact JWS must be a string or Uint8Array");let{0:o,1:n,2:i,length:s}=e.split(".");if(s!==3)throw new u("Invalid Compact JWS");let f=await Ne({payload:n,protected:o,signature:i},t,r),d={payload:f.payload,protectedHeader:f.protectedHeader};return typeof t=="function"?{...d,key:f.key}:d}var pt=e=>Math.floor(e.getTime()/1e3),He=60,Me=He*60,ue=Me*24,lt=ue*7,ht=ue*365.25,mt=/^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i;function De(e){let t=mt.exec(e);if(!t||t[4]&&t[1])throw new TypeError("Invalid time period format");let r=parseFloat(t[2]),o=t[3].toLowerCase(),n;switch(o){case"sec":case"secs":case"second":case"seconds":case"s":n=Math.round(r);break;case"minute":case"minutes":case"min":case"mins":case"m":n=Math.round(r*He);break;case"hour":case"hours":case"hr":case"hrs":case"h":n=Math.round(r*Me);break;case"day":case"days":case"d":n=Math.round(r*ue);break;case"week":case"weeks":case"w":n=Math.round(r*lt);break;default:n=Math.round(r*ht);break}return t[1]==="-"||t[4]==="ago"?-n:n}var Le=e=>e.includes("/")?e.toLowerCase():`application/${e.toLowerCase()}`,yt=(e,t)=>typeof e=="string"?t.includes(e):Array.isArray(e)?t.some(Set.prototype.has.bind(new Set(e))):!1;function Fe(e,t,r={}){let o;try{o=JSON.parse(A.decode(t))}catch{}if(!y(o))throw new W("JWT Claims Set must be a top-level JSON object");let{typ:n}=r;if(n&&(typeof e.typ!="string"||Le(e.typ)!==Le(n)))throw new w('unexpected "typ" JWT header value',o,"typ","check_failed");let{requiredClaims:i=[],issuer:s,subject:f,audience:d,maxTokenAge:a}=r,c=[...i];a!==void 0&&c.push("iat"),d!==void 0&&c.push("aud"),f!==void 0&&c.push("sub"),s!==void 0&&c.push("iss");for(let E of new Set(c.reverse()))if(!(E in o))throw new w(`missing required "${E}" claim`,o,E,"missing");if(s&&!(Array.isArray(s)?s:[s]).includes(o.iss))throw new w('unexpected "iss" claim value',o,"iss","check_failed");if(f&&o.sub!==f)throw new w('unexpected "sub" claim value',o,"sub","check_failed");if(d&&!yt(o.aud,typeof d=="string"?[d]:d))throw new w('unexpected "aud" claim value',o,"aud","check_failed");let S;switch(typeof r.clockTolerance){case"string":S=De(r.clockTolerance);break;case"number":S=r.clockTolerance;break;case"undefined":S=0;break;default:throw new TypeError("Invalid clockTolerance option type")}let{currentDate:C}=r,x=pt(C||new Date);if((o.iat!==void 0||a)&&typeof o.iat!="number")throw new w('"iat" claim must be a number',o,"iat","invalid");if(o.nbf!==void 0){if(typeof o.nbf!="number")throw new w('"nbf" claim must be a number',o,"nbf","invalid");if(o.nbf>x+S)throw new w('"nbf" claim timestamp check failed',o,"nbf","check_failed")}if(o.exp!==void 0){if(typeof o.exp!="number")throw new w('"exp" claim must be a number',o,"exp","invalid");if(o.exp<=x-S)throw new F('"exp" claim timestamp check failed',o,"exp","check_failed")}if(a){let E=x-o.iat,T=typeof a=="number"?a:De(a);if(E-S>T)throw new F('"iat" claim timestamp check failed (too far in the past)',o,"iat","check_failed");if(E<0-S)throw new w('"iat" claim timestamp check failed (it should be in the past)',o,"iat","check_failed")}return o}async function q(e,t,r){let o=await Ue(e,t,r);if(o.protectedHeader.crit?.includes("b64")&&o.protectedHeader.b64===!1)throw new W("JWTs MUST NOT use unencoded payload");let i={payload:Fe(o.protectedHeader,o.payload,r),protectedHeader:o.protectedHeader};return typeof t=="function"?{...i,key:o.key}:i}function St(e){switch(typeof e=="string"&&e.slice(0,2)){case"RS":case"PS":return"RSA";case"ES":return"EC";case"Ed":return"OKP";case"ML":return"AKP";default:throw new l('Unsupported "alg" value for a JSON Web Key Set')}}function Et(e){return e&&typeof e=="object"&&Array.isArray(e.keys)&&e.keys.every(wt)}function wt(e){return y(e)}var de=class{#r;#s=new WeakMap;constructor(t){if(!Et(t))throw new B("JSON Web Key Set malformed");this.#r=structuredClone(t)}jwks(){return this.#r}async getKey(t,r){let{alg:o,kid:n}={...t,...r?.header},i=St(o),s=this.#r.keys.filter(a=>{let c=i===a.kty;if(c&&typeof n=="string"&&(c=n===a.kid),c&&(typeof a.alg=="string"||i==="AKP")&&(c=o===a.alg),c&&typeof a.use=="string"&&(c=a.use==="sig"),c&&Array.isArray(a.key_ops)&&(c=a.key_ops.includes("verify")),c)switch(o){case"ES256":c=a.crv==="P-256";break;case"ES384":c=a.crv==="P-384";break;case"ES512":c=a.crv==="P-521";break;case"Ed25519":case"EdDSA":c=a.crv==="Ed25519";break}return c}),{0:f,length:d}=s;if(d===0)throw new v;if(d!==1){let a=new G,c=this.#s;throw a[Symbol.asyncIterator]=async function*(){for(let S of s)try{yield await Be(c,S,o)}catch{}},a}return Be(this.#s,f,o)}};async function Be(e,t,r){let o=e.get(t)||e.set(t,{}).get(t);if(o[r]===void 0){let n=await We({...t,ext:!0},r);if(n instanceof Uint8Array||n.type!=="public")throw new B("JSON Web Key Set members must be public keys");o[r]=n}return o[r]}function D(e){let t=new de(e),r=async(o,n)=>t.getKey(o,n);return Object.defineProperties(r,{jwks:{value:()=>structuredClone(t.jwks()),enumerable:!1,configurable:!1,writable:!1}}),r}function At(){return typeof WebSocketPair<"u"||typeof navigator<"u"&&navigator.userAgent==="Cloudflare-Workers"||typeof EdgeRuntime<"u"&&EdgeRuntime==="vercel"}var pe;(typeof navigator>"u"||!navigator.userAgent?.startsWith?.("Mozilla/5.0 "))&&(pe="jose/v6.2.3");var ke=Symbol();async function gt(e,t,r,o=fetch){let n=await o(e,{method:"GET",signal:r,redirect:"manual",headers:t}).catch(i=>{throw i.name==="TimeoutError"?new X:i});if(n.status!==200)throw new h("Expected 200 OK from the JSON Web Key Set HTTP response");try{return await n.json()}catch{throw new h("Failed to parse the JSON Web Key Set HTTP response as JSON")}}var Z=Symbol();function bt(e,t){return!(typeof e!="object"||e===null||!("uat"in e)||typeof e.uat!="number"||Date.now()-e.uat>=t||!("jwks"in e)||!y(e.jwks)||!Array.isArray(e.jwks.keys)||!Array.prototype.every.call(e.jwks.keys,y))}var le=class{#r;#s;#c;#a;#o;#e;#t;#f;#n;#i;constructor(t,r){if(!(t instanceof URL))throw new TypeError("url must be an instance of URL");this.#r=new URL(t.href),this.#s=typeof r?.timeoutDuration=="number"?r?.timeoutDuration:5e3,this.#c=typeof r?.cooldownDuration=="number"?r?.cooldownDuration:3e4,this.#a=typeof r?.cacheMaxAge=="number"?r?.cacheMaxAge:6e5,this.#t=new Headers(r?.headers),pe&&!this.#t.has("User-Agent")&&this.#t.set("User-Agent",pe),this.#t.has("accept")||(this.#t.set("accept","application/json"),this.#t.append("accept","application/jwk-set+json")),this.#f=r?.[ke],r?.[Z]!==void 0&&(this.#i=r?.[Z],bt(r?.[Z],this.#a)&&(this.#o=this.#i.uat,this.#n=D(this.#i.jwks)))}pendingFetch(){return!!this.#e}coolingDown(){return typeof this.#o=="number"?Date.now(){this.#n=D(t),this.#i&&(this.#i.uat=Date.now(),this.#i.jwks=t),this.#o=Date.now(),this.#e=void 0}).catch(t=>{throw this.#e=void 0,t}),await this.#e}};function he(e,t){let r=new le(e,t),o=async(n,i)=>r.getKey(n,i);return Object.defineProperties(o,{coolingDown:{get:()=>r.coolingDown(),enumerable:!0,configurable:!1},fresh:{get:()=>r.fresh(),enumerable:!0,configurable:!1},reload:{value:()=>r.reload(),enumerable:!0,configurable:!1,writable:!1},reloading:{get:()=>r.pendingFetch(),enumerable:!0,configurable:!1},jwks:{value:()=>r.jwks(),enumerable:!0,configurable:!1,writable:!1}}),o}function me(e){let t;if(typeof e=="string"){let r=e.split(".");(r.length===3||r.length===5)&&([t]=r)}else if(typeof e=="object"&&e)if("protected"in e)t=e.protected;else throw new TypeError("Token does not contain a Protected Header");try{if(typeof t!="string"||!t)throw new Error;let r=JSON.parse(A.decode(g(t)));if(!y(r))throw new Error;return r}catch{throw new TypeError("Invalid Token or Protected Header formatting")}}var R={BootError:m.ServiceUnavailable,InvalidWorkerResponse:m.InternalServerError,WorkerLimit:546},Tt={[R.BootError]:"BOOT_ERROR",[R.InvalidWorkerResponse]:"WORKER_ERROR",[R.WorkerLimit]:"WORKER_LIMIT"},Kt={[R.BootError]:"Worker failed to boot (please check logs)",[R.InvalidWorkerResponse]:"Function exited due to an error (please check logs)",[R.WorkerLimit]:"Worker failed to respond due to a resource limit (please check logs)"},_t=["HOME","HOSTNAME","PATH","PWD"],Ye=Deno.env.get("SUPABASE_INTERNAL_HOST_PORT"),Pt=Deno.env.get("SUPABASE_INTERNAL_JWT_SECRET"),Ct=new URL("/auth/v1/.well-known/jwks.json",Deno.env.get("SUPABASE_URL")),xt=Deno.env.get("SUPABASE_INTERNAL_DEBUG")==="true",It=Deno.env.get("SUPABASE_INTERNAL_FUNCTIONS_CONFIG"),$e=Deno.env.get("SUPABASE_INTERNAL_PUBLISHABLE_KEY"),Ve=Deno.env.get("SUPABASE_INTERNAL_SECRET_KEY"),Ge=parseInt(Deno.env.get("SUPABASE_INTERNAL_WALLCLOCK_LIMIT_SEC")),Wt=new Map([[Deno.errors.InvalidWorkerCreation,R.BootError],[Deno.errors.InvalidWorkerResponse,R.InvalidWorkerResponse],[Deno.errors.WorkerRequestCancelled,R.WorkerLimit]]),Xe=`Serving functions on http://127.0.0.1:${Ye}/functions/v1/`,L={MissingAuthHeader:"UNAUTHORIZED_NO_AUTH_HEADER",InvalidJwtFormat:"UNAUTHORIZED_INVALID_JWT_FORMAT",LegacyJwt:"UNAUTHORIZED_LEGACY_JWT",AsymmetricJwt:"UNAUTHORIZED_ASYMMETRIC_JWT",UnsupportedTokenAlgorithm:"UNAUTHORIZED_UNSUPPORTED_TOKEN_ALGORITHM"},P={MissingAuthHeader:{code:L.MissingAuthHeader,message:"Missing authorization header"},InvalidJwtFormat:{code:L.InvalidJwtFormat,message:"Invalid JWT format"},LegacyJwt:{code:L.LegacyJwt,message:"Invalid JWT"},AsymmetricJwt:{code:L.AsymmetricJwt,message:"Invalid JWT"},UnsupportedTokenAlgorithm:e=>({code:L.UnsupportedTokenAlgorithm,message:`Unsupported JWT algorithm ${e}`})};function H(e,t,r={}){let o={...r},n=null;return e&&(typeof e=="object"?(o["Content-Type"]="application/json",n=JSON.stringify(e)):typeof e=="string"?(o["Content-Type"]="text/plain",n=e):n=null),new Response(n,{status:t,headers:o})}function ye({code:e,message:t}){return H({code:e,message:t,msg:t},m.Unauthorized,{"sb-error-code":e,"Access-Control-Expose-Headers":"sb-error-code"})}var _=(()=>{try{let e=JSON.parse(It);return xt&&console.log("Functions config:",JSON.stringify(e,null,2)),e}catch(e){throw new Error("Failed to parse functions config",{cause:e})}})();function vt(e){let t=e.split(" "),[r,o]=t;return r!=="Bearer"||t.length!==2?null:o}function Jt(e){let t=e.headers.get("authorization"),o=e.headers.get("sb-api-key")?.replace("Bearer","")?.trim();if(!t&&!o)return P.MissingAuthHeader;let n=vt(t??""),i=!n||n.startsWith("sb_")?o:n;return i||P.InvalidJwtFormat}async function Ot(e,t){let o=new TextEncoder().encode(e);try{await q(t,o)}catch(n){return console.error("Symmetric Legacy JWT verification error",n),P.LegacyJwt}return null}var Se=(()=>{try{return D(JSON.parse(Deno.env.get("SUPABASE_JWKS")))}catch{return null}})();async function Nt(e,t){try{Se||(Se=he(new URL(e))),await q(t,Se)}catch(r){return console.error("Asymmetric JWT verification error",r),P.AsymmetricJwt}return null}async function Ut(e,t,r){let o;try{o=me(r).alg}catch(n){return console.error("JWT format error",n),P.InvalidJwtFormat}return o?o==="HS256"?(console.log(`Legacy token type detected, attempting ${o} verification.`),await Ot(e,r)):o==="ES256"||o==="RS256"?await Nt(t,r):P.UnsupportedTokenAlgorithm(o):P.InvalidJwtFormat}async function Dt({entrypointPath:e,importMapPath:t}){if(t)return!1;let r=te(re(e),"package.json");try{await Deno.lstat(r)}catch(o){if(o instanceof Deno.errors.NotFound)return!1}return!0}function Lt(e){let t=new URL(e.url),r=e.headers.get("x-forwarded-host");t.hostname=r??t.hostname;let o=new Request(t,e.clone());return o.headers.delete("sb-api-key"),EdgeRuntime.applySupabaseTag(e,o),o}Deno.serve({handler:async e=>{let t=new URL(e.url),{pathname:r}=t;if(r==="/_internal/health")return H({message:"ok"},m.OK);if(r==="/_internal/metric"){let p=await EdgeRuntime.getRuntimeMetrics();return Response.json(p)}let n=r.split("/")[1];if(!n||!(n in _))return H("Function not found",m.NotFound);if(e.method!=="OPTIONS"&&_[n].verifyJWT)try{let p=Jt(e);if(typeof p!="string")return ye(p);let b=await Ut(Pt,Ct,p);if(b)return ye(b)}catch(p){return console.error(p),ye({code:L.InvalidJwtFormat,message:"Invalid JWT format"})}let i=re(_[n].entrypointPath);console.error(`serving the request with ${i}`);let s=256,f=isFinite(Ge)?Ge*1e3:400*1e3,d=!1,a={...Deno.env.toObject(),...Object.fromEntries(Object.entries(_[n].env??{}).filter(([p,b])=>!p.startsWith("SUPABASE_")))};$e&&(a.SUPABASE_PUBLISHABLE_KEYS=JSON.stringify({default:$e})),Ve&&(a.SUPABASE_SECRET_KEYS=JSON.stringify({default:Ve}));let c=Object.entries(a).filter(([p,b])=>!_t.includes(p)&&!p.startsWith("SUPABASE_INTERNAL_")),S=!1,C="",x=1e3,E=2e3,T="tc39",j=te(Deno.cwd(),_[n].entrypointPath),ze=Ee(j).href,qe=await Dt(_[n]),Ze=_[n].staticFiles;try{let p=await EdgeRuntime.userWorkers.create({servicePath:i,memoryLimitMb:s,workerTimeoutMs:f,noModuleCache:d,noNpm:!qe,importMapPath:_[n].importMapPath,envVars:c,forceCreate:S,customModuleRoot:C,cpuTimeSoftLimitMs:x,cpuTimeHardLimitMs:E,decoratorType:T,maybeEntrypoint:ze,context:{useReadSyncFileAPI:!0},staticPatterns:Ze}),b=Lt(e);return await p.fetch(b)}catch(p){console.error(p);for(let[b,Q]of Wt.entries())if(b!==void 0&&p instanceof b)return H({code:Tt[Q],message:Kt[Q]},Q);return H({code:ee[m.InternalServerError],message:"Request failed due to an internal server error",trace:JSON.stringify(p.stack)},m.InternalServerError)}},onListen:()=>{try{let e=Deno.env.get("SUPABASE_INTERNAL_FUNCTIONS_CONFIG");if(e){let r=JSON.parse(e),o=Object.keys(r),i=o.slice(0,5).map(f=>` - http://127.0.0.1:${Ye}/functions/v1/${f}`),s=o.length>0?` ${i.join(` `)}${o.length>5?` -... and ${o.length-5} more functions`:""}`:"";console.log(`${$e}${s} -Using ${Deno.version.deno}`)}}catch{console.log(`${$e} -Using ${Deno.version.deno}`)}},onError:e=>P({code:Z[h.InternalServerError],message:"Request failed due to an internal server error",trace:JSON.stringify(e.stack)},h.InternalServerError)});export{xt as extractBearerToken,Nt as prepareUserRequest,Ot as verifyHybridJWT}; +... and ${o.length-5} more functions`:""}`:"";console.log(`${Xe}${s} +Using ${Deno.version.deno}`)}}catch{console.log(`${Xe} +Using ${Deno.version.deno}`)}},onError:e=>H({code:ee[m.InternalServerError],message:"Request failed due to an internal server error",trace:JSON.stringify(e.stack)},m.InternalServerError)});export{vt as extractBearerToken,Lt as prepareUserRequest,Ut as verifyHybridJWT}; diff --git a/apps/cli/src/shared/functions/serve-main-offline.e2e.test.ts b/apps/cli/src/shared/functions/serve-main-offline.e2e.test.ts index dad054aaf1..bccd99d091 100644 --- a/apps/cli/src/shared/functions/serve-main-offline.e2e.test.ts +++ b/apps/cli/src/shared/functions/serve-main-offline.e2e.test.ts @@ -1,11 +1,12 @@ import { execSync, spawnSync } from "node:child_process"; -import { mkdtemp, rm, writeFile } from "node:fs/promises"; +import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { describe, expect, test } from "vitest"; import { LEGACY_EDGE_RUNTIME_IMAGE } from "../../legacy/shared/legacy-edge-runtime-image.ts"; +import { dockerfileServiceImage } from "../services/dockerfile-images.ts"; import { bundleServeMainTemplate } from "./serve-main-bundler.ts"; /** @@ -33,12 +34,98 @@ function hasDocker(): boolean { const dockerAvailable = hasDocker(); const SERVE_OFFLINE_STARTUP_TIMEOUT_MS = 60_000; const SERVE_OFFLINE_TEST_TIMEOUT_MS = 120_000; +const LEGACY_KONG_IMAGE = `public.ecr.aws/supabase/${dockerfileServiceImage("kong").replace(/^.*\//, "")}`; +const AUTH_FUNCTIONS_CONFIG = JSON.stringify({ + test: { + entrypointPath: "/tmp/test/index.ts", + importMapPath: "", + staticFiles: [], + verifyJWT: true, + }, +}); +const KONG_FUNCTIONS_CONFIG = JSON.stringify({ + test: { + entrypointPath: "/app/functions/custom/index.ts", + importMapPath: "", + staticFiles: [], + verifyJWT: true, + }, + custom: { + entrypointPath: "/app/functions/custom/index.ts", + importMapPath: "", + staticFiles: [], + verifyJWT: false, + }, +}); +const CUSTOM_FUNCTION = `Deno.serve(() => new Response("ok", { + headers: { + "X-Custom-Id": "abc123", + "Access-Control-Expose-Headers": "X-Custom-Id", + }, +}));`; + +function jwtWithInvalidSignature(algorithm?: string): string { + const header = Buffer.from(JSON.stringify({ alg: algorithm, typ: "JWT" })).toString("base64url"); + const payload = Buffer.from(JSON.stringify({ sub: "test-user" })).toString("base64url"); + return `${header}.${payload}.invalid`; +} + +const authFailureCases = [ + { + name: "missing authorization", + code: "UNAUTHORIZED_NO_AUTH_HEADER", + message: "Missing authorization header", + }, + { + name: "invalid JWT format", + authorization: "Bearer not-a-jwt", + code: "UNAUTHORIZED_INVALID_JWT_FORMAT", + message: "Invalid JWT format", + }, + { + name: "missing JWT algorithm", + authorization: `Bearer ${jwtWithInvalidSignature()}`, + code: "UNAUTHORIZED_INVALID_JWT_FORMAT", + message: "Invalid JWT format", + }, + { + name: "invalid legacy JWT", + authorization: `Bearer ${jwtWithInvalidSignature("HS256")}`, + code: "UNAUTHORIZED_LEGACY_JWT", + message: "Invalid JWT", + }, + { + name: "invalid asymmetric JWT", + authorization: `Bearer ${jwtWithInvalidSignature("ES256")}`, + code: "UNAUTHORIZED_ASYMMETRIC_JWT", + message: "Invalid JWT", + }, + { + name: "unsupported JWT algorithm", + authorization: `Bearer ${jwtWithInvalidSignature("none")}`, + code: "UNAUTHORIZED_UNSUPPORTED_TOKEN_ALGORITHM", + message: "Unsupported JWT algorithm none", + }, +]; function containerLogs(container: string): string { const result = spawnSync("docker", ["logs", container], { encoding: "utf8" }); return `${result.stdout ?? ""}\n${result.stderr ?? ""}`; } +async function writeKongConfig(dir: string, edgeRuntimeContainer: string) { + const template = await readFile( + new URL("../../../../cli-go/internal/start/templates/kong.yml", import.meta.url), + "utf8", + ); + const config = template + .replaceAll("{{ .EdgeRuntimeId }}", edgeRuntimeContainer) + .replaceAll("{{ .BearerToken }}", "$((headers.authorization or headers.apikey))") + .replaceAll("{{ .QueryToken }}", "$((query_params.apikey))") + .replace(/{{ \.[A-Za-z]+ }}/g, "unused"); + await writeFile(join(dir, "kong.yml"), config); +} + describe("functions serve runtime template (offline)", () => { test.skipIf(!dockerAvailable)( "boots under edge-runtime with networking disabled and fetches nothing remote", @@ -102,4 +189,222 @@ describe("functions serve runtime template (offline)", () => { } }, ); + + test.skipIf(!dockerAvailable)( + "returns canonical JWT auth failures", + { timeout: SERVE_OFFLINE_TEST_TIMEOUT_MS }, + async () => { + const dir = await mkdtemp(join(tmpdir(), "supabase-serve-auth-e2e-")); + const container = `supabase-serve-auth-e2e-${process.pid.toString()}`; + try { + await writeFile(join(dir, "index.ts"), await bundleServeMainTemplate()); + + const run = spawnSync( + "docker", + [ + "run", + "-d", + "--name", + container, + "-p", + "127.0.0.1::8081", + "-e", + "SUPABASE_INTERNAL_HOST_PORT=8081", + "-e", + "SUPABASE_INTERNAL_JWT_SECRET=auth-e2e", + "-e", + "SUPABASE_URL=http://127.0.0.1:54321", + "-e", + `SUPABASE_INTERNAL_FUNCTIONS_CONFIG=${AUTH_FUNCTIONS_CONFIG}`, + "-e", + "SUPABASE_INTERNAL_WALLCLOCK_LIMIT_SEC=400", + "-e", + 'SUPABASE_JWKS={"keys":[]}', + "-v", + `${dir}:/app:ro`, + "--entrypoint", + "edge-runtime", + LEGACY_EDGE_RUNTIME_IMAGE, + "start", + "--main-service=/app", + "--port=8081", + ], + { encoding: "utf8" }, + ); + expect(run.status, run.stderr).toBe(0); + + const portResult = spawnSync("docker", ["port", container, "8081/tcp"], { + encoding: "utf8", + }); + expect(portResult.status, portResult.stderr).toBe(0); + const port = Number(portResult.stdout.trim().split(":").at(-1)); + expect(port).toBeGreaterThan(0); + const url = `http://127.0.0.1:${port}/test`; + + const deadline = Date.now() + SERVE_OFFLINE_STARTUP_TIMEOUT_MS; + let ready = false; + while (Date.now() < deadline) { + try { + const response = await fetch(url); + if (response.status === 401) { + ready = true; + break; + } + } catch {} + await new Promise((resolve) => setTimeout(resolve, 250)); + } + expect(ready, containerLogs(container)).toBe(true); + + for (const { name, authorization, code, message } of authFailureCases) { + const response = await fetch(url, { + headers: authorization === undefined ? undefined : { authorization }, + }); + expect(response.status, name).toBe(401); + expect(response.headers.get("content-type"), name).toContain("application/json"); + expect(response.headers.get("sb-error-code"), name).toBe(code); + expect(await response.json(), name).toEqual({ code, message, msg: message }); + } + } finally { + spawnSync("docker", ["rm", "-f", container], { stdio: "ignore" }); + await rm(dir, { recursive: true, force: true }); + } + }, + ); + + test.skipIf(!dockerAvailable)( + "preserves function CORS headers and exposes JWT errors through Kong", + { timeout: SERVE_OFFLINE_TEST_TIMEOUT_MS }, + async () => { + const dir = await mkdtemp(join(tmpdir(), "supabase-serve-kong-e2e-")); + const network = `supabase-serve-kong-e2e-${process.pid.toString()}`; + const runtimeContainer = `${network}-runtime`; + const kongContainer = `${network}-kong`; + try { + await writeFile(join(dir, "index.ts"), await bundleServeMainTemplate()); + await mkdir(join(dir, "functions", "custom"), { recursive: true }); + await writeFile(join(dir, "functions", "custom", "index.ts"), CUSTOM_FUNCTION); + await writeKongConfig(dir, runtimeContainer); + + const createNetwork = spawnSync("docker", ["network", "create", network], { + encoding: "utf8", + }); + expect(createNetwork.status, createNetwork.stderr).toBe(0); + + const runRuntime = spawnSync( + "docker", + [ + "run", + "-d", + "--name", + runtimeContainer, + "--network", + network, + "-e", + "SUPABASE_INTERNAL_HOST_PORT=8081", + "-e", + "SUPABASE_INTERNAL_JWT_SECRET=auth-e2e", + "-e", + `SUPABASE_URL=http://${kongContainer}:8000`, + "-e", + `SUPABASE_INTERNAL_FUNCTIONS_CONFIG=${KONG_FUNCTIONS_CONFIG}`, + "-e", + "SUPABASE_INTERNAL_WALLCLOCK_LIMIT_SEC=400", + "-e", + 'SUPABASE_JWKS={"keys":[]}', + "-v", + `${dir}:/app:ro`, + "--entrypoint", + "edge-runtime", + LEGACY_EDGE_RUNTIME_IMAGE, + "start", + "--main-service=/app", + "--port=8081", + ], + { encoding: "utf8" }, + ); + expect(runRuntime.status, runRuntime.stderr).toBe(0); + + const runKong = spawnSync( + "docker", + [ + "run", + "-d", + "--name", + kongContainer, + "--network", + network, + "-p", + "127.0.0.1::8000", + "-e", + "KONG_DATABASE=off", + "-e", + "KONG_DECLARATIVE_CONFIG=/home/kong/kong.yml", + "-e", + "KONG_PLUGINS=request-transformer,cors", + "-e", + "KONG_NGINX_WORKER_PROCESSES=1", + "-v", + `${join(dir, "kong.yml")}:/home/kong/kong.yml:ro`, + LEGACY_KONG_IMAGE, + "kong", + "docker-start", + ], + { encoding: "utf8" }, + ); + expect(runKong.status, runKong.stderr).toBe(0); + + const portResult = spawnSync("docker", ["port", kongContainer, "8000/tcp"], { + encoding: "utf8", + }); + expect(portResult.status, portResult.stderr).toBe(0); + const port = Number(portResult.stdout.trim().split(":").at(-1)); + expect(port).toBeGreaterThan(0); + const functionsUrl = `http://127.0.0.1:${port}/functions/v1`; + const authUrl = `${functionsUrl}/test`; + + const deadline = Date.now() + SERVE_OFFLINE_STARTUP_TIMEOUT_MS; + let ready = false; + while (Date.now() < deadline) { + try { + const response = await fetch(authUrl); + if (response.status === 401) { + ready = true; + break; + } + } catch {} + await new Promise((resolve) => setTimeout(resolve, 250)); + } + expect(ready, `${containerLogs(kongContainer)}\n${containerLogs(runtimeContainer)}`).toBe( + true, + ); + + const customResponse = await fetch(`${functionsUrl}/custom`, { + headers: { Origin: "http://localhost:3000" }, + }); + expect(customResponse.status).toBe(200); + expect(customResponse.headers.get("x-custom-id")).toBe("abc123"); + expect(customResponse.headers.get("access-control-expose-headers")?.toLowerCase()).toBe( + "x-custom-id", + ); + + const authResponse = await fetch(authUrl, { + headers: { Origin: "http://localhost:3000" }, + }); + expect(authResponse.status).toBe(401); + expect(authResponse.headers.get("sb-error-code")).toBe("UNAUTHORIZED_NO_AUTH_HEADER"); + expect(authResponse.headers.get("access-control-expose-headers")).toBe("sb-error-code"); + expect(await authResponse.json()).toEqual({ + code: "UNAUTHORIZED_NO_AUTH_HEADER", + message: "Missing authorization header", + msg: "Missing authorization header", + }); + } finally { + spawnSync("docker", ["rm", "-f", kongContainer, runtimeContainer], { + stdio: "ignore", + }); + spawnSync("docker", ["network", "rm", network], { stdio: "ignore" }); + await rm(dir, { recursive: true, force: true }); + } + }, + ); }); diff --git a/apps/cli/src/shared/functions/serve.main.ts b/apps/cli/src/shared/functions/serve.main.ts index e86b82ebda..986632d4ec 100644 --- a/apps/cli/src/shared/functions/serve.main.ts +++ b/apps/cli/src/shared/functions/serve.main.ts @@ -46,6 +46,41 @@ const DENO_SB_ERROR_MAP = new Map([ [Deno.errors.WorkerRequestCancelled, SB_SPECIFIC_ERROR_CODE.WorkerLimit], ]); const GENERIC_FUNCTION_SERVE_MESSAGE = `Serving functions on http://127.0.0.1:${HOST_PORT}/functions/v1/`; +const AUTH_ERROR_CODE = { + MissingAuthHeader: "UNAUTHORIZED_NO_AUTH_HEADER", + InvalidJwtFormat: "UNAUTHORIZED_INVALID_JWT_FORMAT", + LegacyJwt: "UNAUTHORIZED_LEGACY_JWT", + AsymmetricJwt: "UNAUTHORIZED_ASYMMETRIC_JWT", + UnsupportedTokenAlgorithm: "UNAUTHORIZED_UNSUPPORTED_TOKEN_ALGORITHM", +}; + +interface AuthFailure { + code: string; + message: string; +} + +const AUTH_FAILURE = { + MissingAuthHeader: { + code: AUTH_ERROR_CODE.MissingAuthHeader, + message: "Missing authorization header", + }, + InvalidJwtFormat: { + code: AUTH_ERROR_CODE.InvalidJwtFormat, + message: "Invalid JWT format", + }, + LegacyJwt: { + code: AUTH_ERROR_CODE.LegacyJwt, + message: "Invalid JWT", + }, + AsymmetricJwt: { + code: AUTH_ERROR_CODE.AsymmetricJwt, + message: "Invalid JWT", + }, + UnsupportedTokenAlgorithm: (algorithm: string) => ({ + code: AUTH_ERROR_CODE.UnsupportedTokenAlgorithm, + message: `Unsupported JWT algorithm ${algorithm}`, + }), +}; interface FunctionConfig { entrypointPath: string; @@ -74,6 +109,13 @@ function getResponse(payload: any, status: number, customHeaders = {}) { return new Response(body, { status, headers }); } +function getAuthErrorResponse({ code, message }: AuthFailure) { + return getResponse({ code, message, msg: message }, STATUS_CODE.Unauthorized, { + "sb-error-code": code, + "Access-Control-Expose-Headers": "sb-error-code", + }); +} + const functionsConfig: Record = (() => { try { const functionsConfig = JSON.parse(FUNCTIONS_CONFIG_STRING); @@ -99,7 +141,7 @@ export function extractBearerToken(rawToken: string) { return token; } -function getAuthToken(req: Request) { +function getAuthToken(req: Request): string | AuthFailure { const authHeader = req.headers.get("authorization"); const sbApiKeyCompatibilityToken = req.headers.get("sb-api-key"); @@ -107,7 +149,7 @@ function getAuthToken(req: Request) { const cleanSbApiKeyCompatibilityToken = sbApiKeyCompatibilityToken?.replace("Bearer", "")?.trim(); if (!authHeader && !cleanSbApiKeyCompatibilityToken) { - throw new Error("Missing authorization header"); + return AUTH_FAILURE.MissingAuthHeader; } // NOTE:(kallebysantos) Compatibility mode is triggered when all conditions match: @@ -118,22 +160,22 @@ function getAuthToken(req: Request) { !bearerToken || bearerToken.startsWith("sb_") ? cleanSbApiKeyCompatibilityToken : bearerToken; if (!token) { - throw new Error(`Auth header is not 'Bearer {token}'`); + return AUTH_FAILURE.InvalidJwtFormat; } return token; } -async function isValidLegacyJWT(jwtSecret: string, jwt: string): Promise { +async function isValidLegacyJWT(jwtSecret: string, jwt: string): Promise { const encoder = new TextEncoder(); const secretKey = encoder.encode(jwtSecret); try { await jose.jwtVerify(jwt, secretKey); } catch (e) { console.error("Symmetric Legacy JWT verification error", e); - return false; + return AUTH_FAILURE.LegacyJwt; } - return true; + return null; } // Lazy-loading JWKs @@ -146,7 +188,7 @@ let jwks = (() => { } })(); -async function isValidJWT(jwksUrl: URL, jwt: string): Promise { +async function isValidJWT(jwksUrl: URL, jwt: string): Promise { try { if (!jwks) { // Loading from remote-url on fly @@ -155,9 +197,9 @@ async function isValidJWT(jwksUrl: URL, jwt: string): Promise { await jose.jwtVerify(jwt, jwks); } catch (e) { console.error("Asymmetric JWT verification error", e); - return false; + return AUTH_FAILURE.AsymmetricJwt; } - return true; + return null; } /** @@ -168,8 +210,18 @@ export async function verifyHybridJWT( jwtSecret: string, jwksUrl: URL, jwt: string, -): Promise { - const { alg: jwtAlgorithm } = jose.decodeProtectedHeader(jwt); +): Promise { + let jwtAlgorithm: string | undefined; + try { + jwtAlgorithm = jose.decodeProtectedHeader(jwt).alg; + } catch (e) { + console.error("JWT format error", e); + return AUTH_FAILURE.InvalidJwtFormat; + } + + if (!jwtAlgorithm) { + return AUTH_FAILURE.InvalidJwtFormat; + } if (jwtAlgorithm === "HS256") { console.log(`Legacy token type detected, attempting ${jwtAlgorithm} verification.`); @@ -181,7 +233,7 @@ export async function verifyHybridJWT( return await isValidJWT(jwksUrl, jwt); } - return false; + return AUTH_FAILURE.UnsupportedTokenAlgorithm(jwtAlgorithm); } // Ref: https://docs.deno.com/examples/checking_file_existence/ @@ -242,14 +294,19 @@ Deno.serve({ if (req.method !== "OPTIONS" && functionsConfig[functionName].verifyJWT) { try { const token = getAuthToken(req); - const isValidJWT = await verifyHybridJWT(JWT_SECRET, JWKS_ENDPOINT, token); - - if (!isValidJWT) { - return getResponse({ msg: "Invalid JWT" }, STATUS_CODE.Unauthorized); + if (typeof token !== "string") { + return getAuthErrorResponse(token); + } + const authFailure = await verifyHybridJWT(JWT_SECRET, JWKS_ENDPOINT, token); + if (authFailure) { + return getAuthErrorResponse(authFailure); } } catch (e) { console.error(e); - return getResponse({ msg: e.toString() }, STATUS_CODE.Unauthorized); + return getAuthErrorResponse({ + code: AUTH_ERROR_CODE.InvalidJwtFormat, + message: "Invalid JWT format", + }); } } diff --git a/packages/stack/src/ApiProxy.ts b/packages/stack/src/ApiProxy.ts index 12f258235e..b158c974b6 100644 --- a/packages/stack/src/ApiProxy.ts +++ b/packages/stack/src/ApiProxy.ts @@ -92,7 +92,7 @@ const CORS_HEADERS: ReadonlyArray = [ ["access-control-allow-origin", "*"], ["access-control-allow-methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS"], ["access-control-allow-headers", "Authorization, Content-Type, apikey, X-Client-Info"], - ["access-control-expose-headers", "Content-Range, Range"], + ["access-control-expose-headers", "Content-Range, Range, sb-error-code"], ["access-control-max-age", "86400"], ]; diff --git a/packages/stack/src/ApiProxy.unit.test.ts b/packages/stack/src/ApiProxy.unit.test.ts index d2b3a00bbc..506c6d31e4 100644 --- a/packages/stack/src/ApiProxy.unit.test.ts +++ b/packages/stack/src/ApiProxy.unit.test.ts @@ -197,6 +197,7 @@ describe("ApiProxy", () => { expect(res.headers.get("access-control-allow-methods")).toContain("GET"); expect(res.headers.get("access-control-allow-headers")).toContain("apikey"); expect(res.headers.get("access-control-expose-headers")).toContain("Content-Range"); + expect(res.headers.get("access-control-expose-headers")).toContain("sb-error-code"); expect(res.headers.get("access-control-max-age")).toBe("86400"); }); diff --git a/packages/stack/src/functions.unit.test.ts b/packages/stack/src/functions.unit.test.ts index a744b173ba..56ead117fb 100644 --- a/packages/stack/src/functions.unit.test.ts +++ b/packages/stack/src/functions.unit.test.ts @@ -6,11 +6,13 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { Effect } from "effect"; import { resolveConfig } from "./createStack.ts"; +import { defaultJwtSecret, generateJwt } from "./JwtGenerator.ts"; import { configureFunctionsRuntime, functionsRuntimeConfigPath, resolveFunctionsRuntimeConfig, } from "./functions.ts"; +import { verifyRequest } from "./services/edge-runtime-main.ts"; function makeTempProject(): string { return mkdtempSync(join(tmpdir(), "supabase-stack-functions-")); @@ -54,6 +56,50 @@ async function writeProject(cwd: string) { ); } +function jwtWithInvalidSignature(algorithm?: string): string { + const header = Buffer.from(JSON.stringify({ alg: algorithm, typ: "JWT" })).toString("base64url"); + const payload = Buffer.from(JSON.stringify({ sub: "test-user" })).toString("base64url"); + return `${header}.${payload}.invalid`; +} + +const authFailureCases = [ + { + name: "returns the missing authorization error", + code: "UNAUTHORIZED_NO_AUTH_HEADER", + message: "Missing authorization header", + }, + { + name: "returns the invalid JWT format error", + authorization: "Bearer not-a-jwt", + code: "UNAUTHORIZED_INVALID_JWT_FORMAT", + message: "Invalid JWT format", + }, + { + name: "returns the invalid JWT format error when the algorithm is missing", + authorization: `Bearer ${jwtWithInvalidSignature()}`, + code: "UNAUTHORIZED_INVALID_JWT_FORMAT", + message: "Invalid JWT format", + }, + { + name: "returns the legacy JWT error", + authorization: `Bearer ${jwtWithInvalidSignature("HS256")}`, + code: "UNAUTHORIZED_LEGACY_JWT", + message: "Invalid JWT", + }, + { + name: "returns the asymmetric JWT error", + authorization: `Bearer ${jwtWithInvalidSignature("ES256")}`, + code: "UNAUTHORIZED_ASYMMETRIC_JWT", + message: "Invalid JWT", + }, + { + name: "returns the unsupported algorithm error", + authorization: `Bearer ${jwtWithInvalidSignature("none")}`, + code: "UNAUTHORIZED_UNSUPPORTED_TOKEN_ALGORITHM", + message: "Unsupported JWT algorithm none", + }, +]; + describe("stack Functions runtime config", () => { it.live("auto-detects enabled functions from projectDir", () => { const cwd = makeTempProject(); @@ -150,3 +196,52 @@ describe("stack Functions runtime config", () => { ); }); }); + +describe("stack Functions runtime auth", () => { + for (const { name, authorization, code, message } of authFailureCases) { + it(name, async () => { + const response = await verifyRequest( + new Request("http://127.0.0.1/functions/v1/test", { + headers: authorization === undefined ? undefined : { authorization }, + }), + { jwtSecret: defaultJwtSecret }, + { verifyJWT: true }, + ); + + expect(response).not.toBeNull(); + if (response === null) return; + + expect(response.status).toBe(401); + expect(response.headers.get("content-type")).toContain("application/json"); + expect(response.headers.get("sb-error-code")).toBe(code); + expect(response.headers.get("access-control-expose-headers")).toBe("sb-error-code"); + expect(await response.json()).toEqual({ code, message, msg: message }); + }); + } + + it("accepts a valid legacy JWT", async () => { + const token = generateJwt(defaultJwtSecret, "anon"); + const response = await verifyRequest( + new Request("http://127.0.0.1/functions/v1/test", { + headers: { authorization: `Bearer ${token}` }, + }), + { jwtSecret: defaultJwtSecret }, + { verifyJWT: true }, + ); + + expect(response).toBeNull(); + }); + + it("accepts a lowercase bearer scheme", async () => { + const token = generateJwt(defaultJwtSecret, "anon"); + const response = await verifyRequest( + new Request("http://127.0.0.1/functions/v1/test", { + headers: { authorization: `bearer ${token}` }, + }), + { jwtSecret: defaultJwtSecret }, + { verifyJWT: true }, + ); + + expect(response).toBeNull(); + }); +}); diff --git a/packages/stack/src/services/edge-runtime-main.ts b/packages/stack/src/services/edge-runtime-main.ts index 1db10e1243..9793333a88 100644 --- a/packages/stack/src/services/edge-runtime-main.ts +++ b/packages/stack/src/services/edge-runtime-main.ts @@ -6,6 +6,42 @@ const placeholder = { message: "Edge Functions are not configured for this local stack yet.", }; +const AUTH_ERROR_CODE = { + MissingAuthHeader: "UNAUTHORIZED_NO_AUTH_HEADER", + InvalidJwtFormat: "UNAUTHORIZED_INVALID_JWT_FORMAT", + LegacyJwt: "UNAUTHORIZED_LEGACY_JWT", + AsymmetricJwt: "UNAUTHORIZED_ASYMMETRIC_JWT", + UnsupportedTokenAlgorithm: "UNAUTHORIZED_UNSUPPORTED_TOKEN_ALGORITHM", +}; + +interface AuthFailure { + code: string; + message: string; +} + +const AUTH_FAILURE = { + MissingAuthHeader: { + code: AUTH_ERROR_CODE.MissingAuthHeader, + message: "Missing authorization header", + }, + InvalidJwtFormat: { + code: AUTH_ERROR_CODE.InvalidJwtFormat, + message: "Invalid JWT format", + }, + LegacyJwt: { + code: AUTH_ERROR_CODE.LegacyJwt, + message: "Invalid JWT", + }, + AsymmetricJwt: { + code: AUTH_ERROR_CODE.AsymmetricJwt, + message: "Invalid JWT", + }, + UnsupportedTokenAlgorithm: (algorithm: string) => ({ + code: AUTH_ERROR_CODE.UnsupportedTokenAlgorithm, + message: `Unsupported JWT algorithm ${algorithm}`, + }), +}; + const configPath = typeof Deno === "undefined" ? new URL("./functions-runtime-config.json", import.meta.url) @@ -36,6 +72,28 @@ function bytesEqual(left: Uint8Array, right: Uint8Array) { return result === 0; } +function getAuthErrorResponse({ code, message }: AuthFailure) { + return Response.json( + { code, message, msg: message }, + { + status: 401, + headers: { + "sb-error-code": code, + "Access-Control-Expose-Headers": "sb-error-code", + }, + }, + ); +} + +function decodeJwtAlgorithm(jwt: string): string | undefined { + const parts = jwt.split("."); + if (parts.length !== 3) { + throw new Error("Invalid JWT format"); + } + const decodedHeader = JSON.parse(new TextDecoder().decode(base64UrlToBytes(parts[0]!))); + return typeof decodedHeader.alg === "string" ? decodedHeader.alg : undefined; +} + async function isValidLocalJwt(secret: string, jwt: string) { const parts = jwt.split("."); if (parts.length !== 3) return false; @@ -60,13 +118,13 @@ async function isValidLocalJwt(secret: string, jwt: string) { return bytesEqual(new Uint8Array(signed), base64UrlToBytes(signature!)); } -async function verifyRequest(req: Request, config: any, functionConfig: any) { +export async function verifyRequest(req: Request, config: any, functionConfig: any) { if (!functionConfig.verifyJWT || req.method === "OPTIONS") return null; const bearerToken = req.headers.get("authorization")?.slice("Bearer ".length); const sbApiKeyCompatibilityToken = req.headers.get("sb-api-key")?.replace("Bearer", "")?.trim(); if (!bearerToken && !sbApiKeyCompatibilityToken) { - return Response.json({ msg: "Missing authorization header" }, { status: 401 }); + return getAuthErrorResponse(AUTH_FAILURE.MissingAuthHeader); } // NOTE:(kallebysantos) Compatibility mode is triggered when all conditions match: @@ -76,15 +134,35 @@ async function verifyRequest(req: Request, config: any, functionConfig: any) { !bearerToken || bearerToken.startsWith("sb_") ? sbApiKeyCompatibilityToken : bearerToken; if (!token) { - return Response.json({ msg: "Auth header is not 'Bearer {token}'" }, { status: 401 }); + return getAuthErrorResponse(AUTH_FAILURE.InvalidJwtFormat); } + let algorithm: string | undefined; try { - if (await isValidLocalJwt(config.jwtSecret, token)) return null; + algorithm = decodeJwtAlgorithm(token); } catch (error) { - console.error("JWT verification failed", error); + console.error("JWT format error", error); + return getAuthErrorResponse(AUTH_FAILURE.InvalidJwtFormat); + } + + if (!algorithm) { + return getAuthErrorResponse(AUTH_FAILURE.InvalidJwtFormat); } - return Response.json({ msg: "Invalid JWT" }, { status: 401 }); + + if (algorithm === "HS256") { + try { + if (await isValidLocalJwt(config.jwtSecret, token)) return null; + } catch (error) { + console.error("JWT verification failed", error); + } + return getAuthErrorResponse(AUTH_FAILURE.LegacyJwt); + } + + if (algorithm === "ES256" || algorithm === "RS256") { + return getAuthErrorResponse(AUTH_FAILURE.AsymmetricJwt); + } + + return getAuthErrorResponse(AUTH_FAILURE.UnsupportedTokenAlgorithm(algorithm)); } function dirname(path: string) {