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..79ff317891 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},j={[m.OK]:"OK",[m.Unauthorized]:"Unauthorized",[m.NotFound]:"Not Found",[m.InternalServerError]:"Internal Server Error",[m.ServiceUnavailable]:"Service Unavailable"};function ze(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===""?".":ze(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 Ze(e){return e.replace(/\s/g,t=>`%${t.charCodeAt(0).toString(16).padStart(2,"0").toUpperCase()}`)}function ye(e){if(!e.startsWith("/"))throw new TypeError(`Path must be absolute: received "${e}"`);let t=new URL("file:///");return t.pathname=Ze(e.replace(/%/g,"%25").replace(/\\/g,"%5C")),t}var L=new TextEncoder,A=new TextDecoder,Ht=2**32;function Se(...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 F(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 Ee(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 je(e){return parseInt(e.name.slice(4),10)}function te(e,t){if(je(e.hash)!==t)throw K(`SHA-${t}`,"algorithm.hash")}function Qe(e){switch(e){case"ES256":return"P-256";case"ES384":return"P-384";case"ES512":return"P-521";default:throw new Error("unreachable")}}function et(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");te(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");te(e.algorithm,parseInt(t.slice(2),10));break}case"PS256":case"PS384":case"PS512":{if(!I(e.algorithm,"RSA-PSS"))throw K("RSA-PSS");te(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=Qe(t);if(e.algorithm.namedCurve!==o)throw K(o,"algorithm.namedCurve");break}default:throw new TypeError("CryptoKey does not support this operation")}et(e,r)}function Ae(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 we=(e,...t)=>Ae("Key must be ",e,...t),re=(e,t,...r)=>Ae(`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)}},g=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}},H=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}},k=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"},x=class extends h{static code="ERR_JWT_INVALID";code="ERR_JWT_INVALID"};var M=class extends h{static code="ERR_JWKS_INVALID";code="ERR_JWKS_INVALID"},W=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)}},$=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)}},V=class extends h{static code="ERR_JWKS_TIMEOUT";code="ERR_JWKS_TIMEOUT";constructor(t="request timed out",r){super(t,r)}},G=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 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 w(e)}catch{throw new r(`Failed to base64url decode the ${t}`)}}var tt=e=>typeof e=="object"&&e!==null;function y(e){if(!tt(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 be(...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",Te=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,Ke=e=>e.kty==="oct"&&typeof e.k=="string";function ot(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 nt(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 it(e,t,r){if(t instanceof Uint8Array){if(!e.startsWith("HS"))throw new TypeError(we(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 _e(e,t,r,o){let n=await it(e,t,"verify");ot(e,n);let i=nt(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 st(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 v(e){if(!e.alg)throw new TypeError('"alg" argument is required when "jwk.alg" is not present');let{algorithm:t,keyUsages:r}=st(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",J,Pe=async(e,t,r,o=!1)=>{J||=new WeakMap;let n=J.get(e);if(n?.[r])return n[r];let i=await v({...t,alg:r});return o&&Object.freeze(e),n?n[r]=i:J.set(e,{[r]:i}),i},at=(e,t)=>{J||=new WeakMap;let r=J.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:J.set(e,{[t]:i}),i};async function Ce(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 at(e,t)}catch(o){if(o instanceof TypeError)throw o}let r=e.export({format:"jwk"});return Pe(e,r,t)}if(B(e))return e.k?w(e.k):Pe(e,e,t,!0);throw new Error("unreachable")}async function Ie(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 w(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 v({...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 v({...e,ext:o})}case"EC":case"OKP":return v({...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 N=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},ct=(e,t,r)=>{if(!(t instanceof Uint8Array)){if(B(t)){if(Ke(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(`${N(t)} instances for symmetric algorithms must be of type "secret"`)}},ft=(e,t,r)=>{if(B(t))switch(r){case"decrypt":case"sign":if(Te(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(`${N(t)} instances for asymmetric algorithms must not be of type "secret"`);if(t.type==="public")switch(r){case"sign":throw new TypeError(`${N(t)} instances for asymmetric algorithm signing must be of type "private"`);case"decrypt":throw new TypeError(`${N(t)} instances for asymmetric algorithm decryption must be of type "private"`)}if(t.type==="private")switch(r){case"verify":throw new TypeError(`${N(t)} instances for asymmetric algorithm verifying must be of type "public"`);case"encrypt":throw new TypeError(`${N(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":ct(e,t,r);break;default:ft(e,t,r)}}async function Oe(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 z=w(e.protected);o=JSON.parse(A.decode(z))}catch{throw new u("JWS Protected Header is invalid")}if(!be(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 d=r&&We("algorithms",r.algorithms);if(d&&!d.has(f))throw new k('"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=Se(e.protected!==void 0?F(e.protected):new Uint8Array,F("."),typeof e.payload=="string"?s?F(e.payload):L.encode(e.payload):e.payload),S=se(e.signature,"signature",u),P=await Ce(t,f);if(!await _e(f,P,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:P}:R}async function Je(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 Oe({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 ut=e=>Math.floor(e.getTime()/1e3),Ue=60,Le=Ue*60,ce=Le*24,dt=ce*7,pt=ce*365.25,lt=/^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i;function Ne(e){let t=lt.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*Ue);break;case"hour":case"hours":case"hr":case"hrs":case"h":n=Math.round(r*Le);break;case"day":case"days":case"d":n=Math.round(r*ce);break;case"week":case"weeks":case"w":n=Math.round(r*dt);break;default:n=Math.round(r*pt);break}return t[1]==="-"||t[4]==="ago"?-n:n}var De=e=>e.includes("/")?e.toLowerCase():`application/${e.toLowerCase()}`,ht=(e,t)=>typeof e=="string"?t.includes(e):Array.isArray(e)?t.some(Set.prototype.has.bind(new Set(e))):!1;function He(e,t,r={}){let o;try{o=JSON.parse(A.decode(t))}catch{}if(!y(o))throw new x("JWT Claims Set must be a top-level JSON object");let{typ:n}=r;if(n&&(typeof e.typ!="string"||De(e.typ)!==De(n)))throw new g('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 g(`missing required "${E}" claim`,o,E,"missing");if(s&&!(Array.isArray(s)?s:[s]).includes(o.iss))throw new g('unexpected "iss" claim value',o,"iss","check_failed");if(f&&o.sub!==f)throw new g('unexpected "sub" claim value',o,"sub","check_failed");if(d&&!ht(o.aud,typeof d=="string"?[d]:d))throw new g('unexpected "aud" claim value',o,"aud","check_failed");let S;switch(typeof r.clockTolerance){case"string":S=Ne(r.clockTolerance);break;case"number":S=r.clockTolerance;break;case"undefined":S=0;break;default:throw new TypeError("Invalid clockTolerance option type")}let{currentDate:P}=r,C=ut(P||new Date);if((o.iat!==void 0||a)&&typeof o.iat!="number")throw new g('"iat" claim must be a number',o,"iat","invalid");if(o.nbf!==void 0){if(typeof o.nbf!="number")throw new g('"nbf" claim must be a number',o,"nbf","invalid");if(o.nbf>C+S)throw new g('"nbf" claim timestamp check failed',o,"nbf","check_failed")}if(o.exp!==void 0){if(typeof o.exp!="number")throw new g('"exp" claim must be a number',o,"exp","invalid");if(o.exp<=C-S)throw new H('"exp" claim timestamp check failed',o,"exp","check_failed")}if(a){let E=C-o.iat,R=typeof a=="number"?a:Ne(a);if(E-S>R)throw new H('"iat" claim timestamp check failed (too far in the past)',o,"iat","check_failed");if(E<0-S)throw new g('"iat" claim timestamp check failed (it should be in the past)',o,"iat","check_failed")}return o}async function Y(e,t,r){let o=await Je(e,t,r);if(o.protectedHeader.crit?.includes("b64")&&o.protectedHeader.b64===!1)throw new x("JWTs MUST NOT use unencoded payload");let i={payload:He(o.protectedHeader,o.payload,r),protectedHeader:o.protectedHeader};return typeof t=="function"?{...i,key:o.key}:i}function mt(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 yt(e){return e&&typeof e=="object"&&Array.isArray(e.keys)&&e.keys.every(St)}function St(e){return y(e)}var fe=class{#r;#s=new WeakMap;constructor(t){if(!yt(t))throw new M("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=mt(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 W;if(d!==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 Ie({...t,ext:!0},r);if(n instanceof Uint8Array||n.type!=="public")throw new M("JSON Web Key Set members must be public keys");o[r]=n}return o[r]}function D(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 Et(){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 Be=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 V: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 q=Symbol();function At(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 de=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?.[Be],r?.[q]!==void 0&&(this.#i=r?.[q],At(r?.[q],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 pe(e,t){let r=new de(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(A.decode(w(t)));if(!y(r))throw new Error;return r}catch{throw new TypeError("Invalid Token or Protected Header formatting")}}var T={BootError:m.ServiceUnavailable,InvalidWorkerResponse:m.InternalServerError,WorkerLimit:546},bt={[T.BootError]:"BOOT_ERROR",[T.InvalidWorkerResponse]:"WORKER_ERROR",[T.WorkerLimit]:"WORKER_LIMIT"},Tt={[T.BootError]:"Worker failed to boot (please check logs)",[T.InvalidWorkerResponse]:"Function exited due to an error (please check logs)",[T.WorkerLimit]:"Worker failed to respond due to a resource limit (please check logs)"},Rt=["HOME","HOSTNAME","PATH","PWD"],Ge=Deno.env.get("SUPABASE_INTERNAL_HOST_PORT"),Kt=Deno.env.get("SUPABASE_INTERNAL_JWT_SECRET"),_t=new URL("/auth/v1/.well-known/jwks.json",Deno.env.get("SUPABASE_URL")),Pt=Deno.env.get("SUPABASE_INTERNAL_DEBUG")==="true",Ct=Deno.env.get("SUPABASE_INTERNAL_FUNCTIONS_CONFIG"),Fe=Deno.env.get("SUPABASE_INTERNAL_PUBLISHABLE_KEY"),ke=Deno.env.get("SUPABASE_INTERNAL_SECRET_KEY"),$e=parseInt(Deno.env.get("SUPABASE_INTERNAL_WALLCLOCK_LIMIT_SEC")),It=new Map([[Deno.errors.InvalidWorkerCreation,T.BootError],[Deno.errors.InvalidWorkerResponse,T.InvalidWorkerResponse],[Deno.errors.WorkerRequestCancelled,T.WorkerLimit]]),Ve=`Serving functions on http://127.0.0.1:${Ge}/functions/v1/`,xt=(i=>(i.MissingAuthHeader="UNAUTHORIZED_NO_AUTH_HEADER",i.InvalidLegacyJWT="UNAUTHORIZED_LEGACY_JWT",i.InvalidAsymmetricJWT="UNAUTHORIZED_ASYMMETRIC_JWT",i.InvalidTokenFormat="UNAUTHORIZED_INVALID_JWT_FORMAT",i.UnsupportedTokenAlgorithm="UNAUTHORIZED_UNSUPPORTED_TOKEN_ALGORITHM",i))(xt||{});function U(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 he({code:e,message:t="Invalid JWT"}){return U({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(Ct);return Pt&&console.log("Functions config:",JSON.stringify(e,null,2)),e}catch(e){throw new Error("Failed to parse functions config",{cause:e})}})();function Wt(e){let t=e.split(" "),[r,o]=t;return r!=="Bearer"||t.length!==2?null:o}function vt(e){let t=e.headers.get("authorization"),o=e.headers.get("sb-api-key")?.replace("Bearer","")?.trim();if(!t&&!o)return{code:"UNAUTHORIZED_NO_AUTH_HEADER",message:"Missing authorization header"};let n=Wt(t??""),i=!n||n.startsWith("sb_")?o:n;return i||{code:"UNAUTHORIZED_INVALID_JWT_FORMAT",message:"Invalid JWT format"}}async function Ot(e,t){let o=new TextEncoder().encode(e);try{await Y(t,o)}catch(n){return console.error("Symmetric Legacy JWT verification error",n),{code:"UNAUTHORIZED_LEGACY_JWT"}}return null}var me=(()=>{try{return D(JSON.parse(Deno.env.get("SUPABASE_JWKS")))}catch{return null}})();async function Jt(e,t){try{me||(me=pe(new URL(e))),await Y(t,me)}catch(r){return console.error("Asymmetric JWT verification error",r),{code:"UNAUTHORIZED_ASYMMETRIC_JWT"}}return null}async function Nt(e,t,r){let o;try{o=le(r).alg}catch(n){return console.error("JWT format error",n),{code:"UNAUTHORIZED_INVALID_JWT_FORMAT",message:"Invalid JWT format"}}return o?o==="HS256"?(console.log(`Legacy token type detected, attempting ${o} verification.`),await Ot(e,r)):o==="ES256"||o==="RS256"?await Jt(t,r):{code:"UNAUTHORIZED_UNSUPPORTED_TOKEN_ALGORITHM",message:`Unsupported JWT algorithm ${o}`}:{code:"UNAUTHORIZED_INVALID_JWT_FORMAT",message:"Invalid JWT format"}}async function Dt({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 Ut(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 U({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 U("Function not found",m.NotFound);if(e.method!=="OPTIONS"&&_[n].verifyJWT)try{let p=vt(e);if(typeof p!="string")return he(p);let b=await Nt(Kt,_t,p);if(b)return he(b)}catch(p){return console.error(p),he({code:"UNAUTHORIZED_INVALID_JWT_FORMAT",message:"Invalid JWT format"})}let i=ee(_[n].entrypointPath);console.error(`serving the request with ${i}`);let s=256,f=isFinite($e)?$e*1e3:400*1e3,d=!1,a={...Deno.env.toObject(),...Object.fromEntries(Object.entries(_[n].env??{}).filter(([p,b])=>!p.startsWith("SUPABASE_")))};Fe&&(a.SUPABASE_PUBLISHABLE_KEYS=JSON.stringify({default:Fe})),ke&&(a.SUPABASE_SECRET_KEYS=JSON.stringify({default:ke}));let c=Object.entries(a).filter(([p,b])=>!Rt.includes(p)&&!p.startsWith("SUPABASE_INTERNAL_")),S=!1,P="",C=1e3,E=2e3,R="tc39",z=Q(Deno.cwd(),_[n].entrypointPath),Xe=ye(z).href,Ye=await Dt(_[n]),qe=_[n].staticFiles;try{let p=await EdgeRuntime.userWorkers.create({servicePath:i,memoryLimitMb:s,workerTimeoutMs:f,noModuleCache:d,noNpm:!Ye,importMapPath:_[n].importMapPath,envVars:c,forceCreate:S,customModuleRoot:P,cpuTimeSoftLimitMs:C,cpuTimeHardLimitMs:E,decoratorType:R,maybeEntrypoint:Xe,context:{useReadSyncFileAPI:!0},staticPatterns:qe}),b=Ut(e);return await p.fetch(b)}catch(p){console.error(p);for(let[b,Z]of It.entries())if(b!==void 0&&p instanceof b)return U({code:bt[Z],message:Tt[Z]},Z);return U({code:j[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:${Ge}/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(`${Ve}${s} +Using ${Deno.version.deno}`)}}catch{console.log(`${Ve} +Using ${Deno.version.deno}`)}},onError:e=>U({code:j[m.InternalServerError],message:"Request failed due to an internal server error",trace:JSON.stringify(e.stack)},m.InternalServerError)});export{xt as RequestErrors,Wt as extractBearerToken,Ut as prepareUserRequest,Nt 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..3366498eac 100644 --- a/apps/cli/src/shared/functions/serve.main.ts +++ b/apps/cli/src/shared/functions/serve.main.ts @@ -46,6 +46,18 @@ 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/`; +export enum RequestErrors { + MissingAuthHeader = "UNAUTHORIZED_NO_AUTH_HEADER", + InvalidLegacyJWT = "UNAUTHORIZED_LEGACY_JWT", + InvalidAsymmetricJWT = "UNAUTHORIZED_ASYMMETRIC_JWT", + InvalidTokenFormat = "UNAUTHORIZED_INVALID_JWT_FORMAT", + UnsupportedTokenAlgorithm = "UNAUTHORIZED_UNSUPPORTED_TOKEN_ALGORITHM", +} + +interface AuthFailure { + code: RequestErrors; + message?: string; +} interface FunctionConfig { entrypointPath: string; @@ -74,6 +86,22 @@ function getResponse(payload: any, status: number, customHeaders = {}) { return new Response(body, { status, headers }); } +function getAuthErrorResponse({ code, message = "Invalid JWT" }: AuthFailure) { + return getResponse( + { + code, + message, + // DEPRECATED: Retained for backward compatibility. + 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 +127,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 +135,10 @@ function getAuthToken(req: Request) { const cleanSbApiKeyCompatibilityToken = sbApiKeyCompatibilityToken?.replace("Bearer", "")?.trim(); if (!authHeader && !cleanSbApiKeyCompatibilityToken) { - throw new Error("Missing authorization header"); + return { + code: RequestErrors.MissingAuthHeader, + message: "Missing authorization header", + }; } // NOTE:(kallebysantos) Compatibility mode is triggered when all conditions match: @@ -118,22 +149,25 @@ function getAuthToken(req: Request) { !bearerToken || bearerToken.startsWith("sb_") ? cleanSbApiKeyCompatibilityToken : bearerToken; if (!token) { - throw new Error(`Auth header is not 'Bearer {token}'`); + return { + code: RequestErrors.InvalidTokenFormat, + message: "Invalid JWT format", + }; } 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 { code: RequestErrors.InvalidLegacyJWT }; } - return true; + return null; } // Lazy-loading JWKs @@ -146,7 +180,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 +189,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 { code: RequestErrors.InvalidAsymmetricJWT }; } - return true; + return null; } /** @@ -168,8 +202,24 @@ 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 { + code: RequestErrors.InvalidTokenFormat, + message: "Invalid JWT format", + }; + } + + if (!jwtAlgorithm) { + return { + code: RequestErrors.InvalidTokenFormat, + message: "Invalid JWT format", + }; + } if (jwtAlgorithm === "HS256") { console.log(`Legacy token type detected, attempting ${jwtAlgorithm} verification.`); @@ -181,7 +231,10 @@ export async function verifyHybridJWT( return await isValidJWT(jwksUrl, jwt); } - return false; + return { + code: RequestErrors.UnsupportedTokenAlgorithm, + message: `Unsupported JWT algorithm ${jwtAlgorithm}`, + }; } // Ref: https://docs.deno.com/examples/checking_file_existence/ @@ -242,14 +295,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: RequestErrors.InvalidTokenFormat, + message: "Invalid JWT format", + }); } } diff --git a/packages/stack/src/ApiProxy.ts b/packages/stack/src/ApiProxy.ts index 116de838f2..2f24a075bb 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..cda66721c5 100644 --- a/packages/stack/src/services/edge-runtime-main.ts +++ b/packages/stack/src/services/edge-runtime-main.ts @@ -6,6 +6,19 @@ const placeholder = { message: "Edge Functions are not configured for this local stack yet.", }; +export enum RequestErrors { + MissingAuthHeader = "UNAUTHORIZED_NO_AUTH_HEADER", + InvalidLegacyJWT = "UNAUTHORIZED_LEGACY_JWT", + InvalidAsymmetricJWT = "UNAUTHORIZED_ASYMMETRIC_JWT", + InvalidTokenFormat = "UNAUTHORIZED_INVALID_JWT_FORMAT", + UnsupportedTokenAlgorithm = "UNAUTHORIZED_UNSUPPORTED_TOKEN_ALGORITHM", +} + +interface AuthFailure { + code: RequestErrors; + message?: string; +} + const configPath = typeof Deno === "undefined" ? new URL("./functions-runtime-config.json", import.meta.url) @@ -36,6 +49,33 @@ function bytesEqual(left: Uint8Array, right: Uint8Array) { return result === 0; } +function getAuthErrorResponse({ code, message = "Invalid JWT" }: AuthFailure) { + return Response.json( + { + code, + message, + // DEPRECATED: Retained for backward compatibility. + 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 +100,16 @@ 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({ + code: RequestErrors.MissingAuthHeader, + message: "Missing authorization header", + }); } // NOTE:(kallebysantos) Compatibility mode is triggered when all conditions match: @@ -76,15 +119,47 @@ 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({ + code: RequestErrors.InvalidTokenFormat, + message: "Invalid JWT format", + }); } + 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({ + code: RequestErrors.InvalidTokenFormat, + message: "Invalid JWT format", + }); + } + + if (!algorithm) { + return getAuthErrorResponse({ + code: RequestErrors.InvalidTokenFormat, + message: "Invalid JWT format", + }); } - 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({ code: RequestErrors.InvalidLegacyJWT }); + } + + if (algorithm === "ES256" || algorithm === "RS256") { + return getAuthErrorResponse({ code: RequestErrors.InvalidAsymmetricJWT }); + } + + return getAuthErrorResponse({ + code: RequestErrors.UnsupportedTokenAlgorithm, + message: `Unsupported JWT algorithm ${algorithm}`, + }); } function dirname(path: string) {