dns-worker 1.1.1 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +3 -3
  2. package/dist/serverfull.mjs +73 -69
  3. package/dist/serverfull.mjs.map +4 -4
  4. package/package.json +3 -1
  5. package/static/assets/AccountView-p5jSjMAE.js +4 -0
  6. package/static/assets/{AnalyticsView-C_g_jz14.js → AnalyticsView-BywwDzah.js} +2 -2
  7. package/static/assets/AuthView-qoUKd5PS.js +2 -0
  8. package/static/assets/{DestinationMap-jSW7gimP.js → DestinationMap-9Yc54Mdj.js} +1 -1
  9. package/static/assets/FilteringView-Bs3__NpV.js +1 -0
  10. package/static/assets/LogsView-B-U9oaxB.js +5 -0
  11. package/static/assets/{QRCodeCanvas-Cu_-aNyM.js → QRCodeCanvas-DQ-xNuwF.js} +2 -2
  12. package/static/assets/{RulesView-CfVeQv0-.js → RulesView-B2kL1QhI.js} +1 -1
  13. package/static/assets/SettingsView-DTGI6eSd.js +1 -0
  14. package/static/assets/SetupView-DE9MM-32.js +1 -0
  15. package/static/assets/{SwipeableDrawer-BrmEzhuP.js → SwipeableDrawer-B81ANpsc.js} +1 -1
  16. package/static/assets/{TrendChart-Dc5yJndv.js → TrendChart-CCR1W3fC.js} +3 -3
  17. package/static/assets/browser-Dc5iKjY4.js +1 -0
  18. package/static/assets/date-CpvuBM37.js +1 -0
  19. package/static/assets/{de-DE-CA3VPcoz.js → de-DE-kDnumQOF.js} +1 -1
  20. package/static/assets/{es-ES-CHvRWwd-.js → es-ES-CqKS7vHl.js} +1 -1
  21. package/static/assets/{fr-FR-CqGOuepx.js → fr-FR-BRcdpT35.js} +1 -1
  22. package/static/assets/getFlagEmoji-DRubsb7D.js +1 -0
  23. package/static/assets/index-Bheo8y3N.css +2 -0
  24. package/static/assets/index-dXN_pYn1.js +16 -0
  25. package/static/assets/{ja-JP-BJSbUSmh.js → ja-JP-C5jk6SuH.js} +1 -1
  26. package/static/assets/{ko-KR-Chzg6jwO.js → ko-KR-z38NtMFa.js} +1 -1
  27. package/static/assets/{ru-RU-CSyCGGPn.js → ru-RU-Bicx52lz.js} +1 -1
  28. package/static/assets/services-BVnEJBDq.js +1 -0
  29. package/static/assets/vendor-i18next-BKUzkAKP.js +1 -0
  30. package/static/assets/vendor-react-BmoHsW1x.js +11 -0
  31. package/static/assets/{vendor-ui-core-sfZn2C08.js → vendor-ui-core-CY_WyMIf.js} +1 -1
  32. package/static/assets/{vendor-utils-CnB7BG7m.js → vendor-utils-BWSB0jGn.js} +1 -1
  33. package/static/assets/{vi-VN-D7rcA1IX.js → vi-VN-CvS_mTAu.js} +1 -1
  34. package/static/assets/{zh-CN-CSPdaOkF.js → zh-CN-B0nRgJTD.js} +1 -1
  35. package/static/assets/{zh-TW-DETA1X3X.js → zh-TW-lc_SSoVI.js} +1 -1
  36. package/static/index.html +6 -6
  37. package/static/sw.js +1 -1
  38. package/static/assets/AccountView-CGRwz6ae.js +0 -4
  39. package/static/assets/AuthView-BQzmEyvO.js +0 -2
  40. package/static/assets/FilteringView-CQ7sX3Rp.js +0 -1
  41. package/static/assets/LogsView-eLfZMRVo.js +0 -5
  42. package/static/assets/SettingsView-agJiYEt5.js +0 -1
  43. package/static/assets/SetupView-CTgCUAgk.js +0 -1
  44. package/static/assets/browser-DPi2BX_1.js +0 -1
  45. package/static/assets/date-IKj2stuv.js +0 -1
  46. package/static/assets/getFlagEmoji-_Wxhq0lT.js +0 -1
  47. package/static/assets/index-919BqnYI.css +0 -2
  48. package/static/assets/index-CbTjGMTZ.js +0 -16
  49. package/static/assets/services-Cwvmit1q.js +0 -1
  50. package/static/assets/vendor-i18next-cO7FDf_e.js +0 -1
  51. package/static/assets/vendor-react-CHk5ngkq.js +0 -11
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env node
2
- var kl=Object.defineProperty;var Ge=(t,e,n)=>()=>{if(n)throw n[0];try{return t&&(e=t(t=0)),e}catch(r){throw n=[r],r}};var _o=(t,e)=>{for(var n in e)kl(t,n,{get:e[n],enumerable:!0})};var P,ge=Ge(()=>{"use strict";P={generateCacheUrl(t){return`https://obex.local/cache/${encodeURIComponent(t)}`},async get(t,e){if(!t)return null;let n=this.generateCacheUrl(e),r=await t.match(n);return r?r.json():null},async set(t,e,n,r,s=[]){if(!t)return;let o=this.generateCacheUrl(e),i={"Content-Type":"application/json","Cache-Control":`public, max-age=${r}`};s&&s.length>0&&(i["Cache-Tag"]=s.join(","));let c=new Response(JSON.stringify(n),{headers:i});return t.put(o,c)},async delete(t,e){if(!t)return!1;let n=this.generateCacheUrl(e);return t.delete(n)},async isRateLimited(t,e,n,r){if(!t)return!1;let s=`ratelimit:${e}`,o=await this.get(t,s),i=Math.floor(Date.now()/1e3);return!o||i>o.reset?(await this.set(t,s,{count:1,reset:i+r},r),!1):o.count>=n?!0:(await this.set(t,s,{count:o.count+1,reset:o.reset},Math.max(1,o.reset-i)),!1)}}});function mn(t){let e=t.cf;if(e&&e.latitude&&e.longitude){let s=parseFloat(e.latitude),o=parseFloat(e.longitude);if(!isNaN(s)&&!isNaN(o))return{latitude:s,longitude:o}}let n=t.headers.get("CF-IPLatitude"),r=t.headers.get("CF-IPLongitude");if(n&&r){let s=parseFloat(n),o=parseFloat(r);if(!isNaN(s)&&!isNaN(o))return{latitude:s,longitude:o}}return{latitude:null,longitude:null}}function rs(t,e,n,r){let o=(n-t)*Math.PI/180,i=(r-e)*Math.PI/180,c=Math.sin(o/2)*Math.sin(o/2)+Math.cos(t*Math.PI/180)*Math.cos(n*Math.PI/180)*Math.sin(i/2)*Math.sin(i/2);return 6371*(2*Math.atan2(Math.sqrt(c),Math.sqrt(1-c)))}var Uo=Ge(()=>{"use strict"});async function ss(t,e,n,r=256){let o=new TextEncoder().encode(t),i=await crypto.subtle.importKey("raw",o,"PBKDF2",!1,["deriveBits"]),c=await crypto.subtle.deriveBits({name:"PBKDF2",salt:e,iterations:n,hash:"SHA-256"},i,r);return new Uint8Array(c)}async function Yl(t,e,n=1e5,r=256){let s=e??crypto.getRandomValues(new Uint8Array(16)),o=await ss(t,s,n,r);return Array.from(o).map(i=>i.toString(16).padStart(2,"0")).join("")}async function et(t,e=1){let n=crypto.getRandomValues(new Uint8Array(16)),s=await ss(t,n,1e5,256),o=new Uint8Array(n.length+s.length);return o.set(n),o.set(s,n.length),btoa(String.fromCharCode(...o))}async function mt(t,e,n=1){let r=new Uint8Array(atob(e).split("").map(l=>l.charCodeAt(0))),s=r.slice(0,16),o=r.slice(16),c=await ss(t,s,1e5,256);if(c.length!==o.length)return!1;let a=0;for(let l=0;l<c.length;l++)a|=c[l]^o[l];return a===0}function Mt(t=5){let e=new Uint8Array(t);crypto.getRandomValues(e);let n="";for(let r=0;r<t;r++)n+=Mo[e[r]&31];return n}function j(t){let e=Math.ceil(t/2),n=new Uint8Array(e);return crypto.getRandomValues(n),Array.from(n).map(r=>r.toString(16).padStart(2,"0")).join("").slice(0,t)}function os(t){let n=new Uint8Array(atob(t).split("").map(r=>r.charCodeAt(0))).slice(0,16);return Array.from(n).map(r=>r.toString(16).padStart(2,"0")).join("")}async function is(t,e){let n=new TextEncoder,r=typeof t=="string"?n.encode(t):t,s=typeof e=="string"?n.encode(e):e,o=await crypto.subtle.importKey("raw",r,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),i=await crypto.subtle.sign("HMAC",o,s);return Array.from(new Uint8Array(i)).map(c=>c.toString(16).padStart(2,"0")).join("")}async function re(t,e){let n=new TextEncoder().encode(e);return Yl(t,n,100,256)}async function Ji(t,e){let n=new TextEncoder().encode(e.toLowerCase()),r=await ss(t,n,1e4,256);return Array.from(r).map(s=>s.toString(16).padStart(2,"0")).join("")}var Mo,Re=Ge(()=>{"use strict";Mo="ybndrfg8ejkmcpqxot1uwisza345h769"});function ht(t,e,n){let r;return n?r=(Number(e.OPTIONAL_SESSION_EXPIRATION_DAYS)||7)*24*60*60:r=(Number(e.DEFAULT_SESSION_EXPIRATION_MINUTES)||1440)*60,`${sr}=${t}; HttpOnly; SameSite=Lax; Path=/; Max-Age=${r}; Secure`}function Ye(){return`${sr}=; HttpOnly; SameSite=Lax; Path=/; Max-Age=0; Secure`}function De(t){if(!t)return null;let e=t.match(new RegExp(`(?:^|;\\s*)${sr}=([^;]*)`));return e?e[1]:null}function tt(t,e,n){let r;return n&&e?r=(Number(e.OPTIONAL_SESSION_EXPIRATION_DAYS)||7)*24*60*60:r=(Number(e?.DEFAULT_SESSION_EXPIRATION_MINUTES)||1440)*60,`csrf_token=${t}; SameSite=Lax; Path=/; Max-Age=${r}; Secure`}function hn(t){if(!t)return null;let e=t.match(/(?:^|;\s*)csrf_token=([^;]*)/);return e?e[1]:null}function as(t,e){let n=Number(e.PREAUTH_TTL_SECONDS)||300;return`${or}=${t}; HttpOnly; SameSite=Lax; Path=/; Max-Age=${n}; Secure`}function cs(){return`${or}=; HttpOnly; SameSite=Lax; Path=/; Max-Age=0; Secure`}function ls(t){if(!t)return null;let e=t.match(new RegExp(`(?:^|;\\s*)${or}=([^;]*)`));return e?e[1]:null}var sr,or,Gi=Ge(()=>{"use strict";sr="auth_refresh",or="preauth_session"});var ir={};_o(ir,{SessionModel:()=>le});var le,Ie=Ge(()=>{"use strict";le=class{constructor(e){this.db=e}db;async getSessionUserId(e){let n=await this.db.prepare("SELECT user_id, expires_at FROM sessions WHERE id = ?").bind(e).first();return n?n.expires_at<=Math.floor(Date.now()/1e3)?(await this.deleteSession(e),null):n.user_id:null}async getSession(e){let n=await this.db.prepare("SELECT * FROM sessions WHERE id = ?").bind(e).first();return n?n.expires_at<=Math.floor(Date.now()/1e3)?(await this.deleteSession(e),null):n:null}async getSessionWithUser(e){let n=await this.db.prepare(`
2
+ var Hl=Object.defineProperty;var ze=(n,e,t)=>()=>{if(t)throw t[0];try{return n&&(e=n(n=0)),e}catch(r){throw t=[r],r}};var vo=(n,e)=>{for(var t in e)Hl(n,t,{get:e[t],enumerable:!0})};var P,ge=ze(()=>{"use strict";P={generateCacheUrl(n){return`https://obex.local/cache/${encodeURIComponent(n)}`},async get(n,e){if(!n)return null;let t=this.generateCacheUrl(e),r=await n.match(t);return r?r.json():null},async set(n,e,t,r,s=[]){if(!n)return;let o=this.generateCacheUrl(e),i={"Content-Type":"application/json","Cache-Control":`public, max-age=${r}`};s&&s.length>0&&(i["Cache-Tag"]=s.join(","));let c=new Response(JSON.stringify(t),{headers:i});return n.put(o,c)},async delete(n,e){if(!n)return!1;let t=this.generateCacheUrl(e);return n.delete(t)},async isRateLimited(n,e,t,r){if(!n)return!1;let s=`ratelimit:${e}`,o=await this.get(n,s),i=Math.floor(Date.now()/1e3);return!o||i>o.reset?(await this.set(n,s,{count:1,reset:i+r},r),!1):o.count>=t?!0:(await this.set(n,s,{count:o.count+1,reset:o.reset},Math.max(1,o.reset-i)),!1)}}});function En(n){let e=n.cf;if(e&&e.latitude&&e.longitude){let s=parseFloat(e.latitude),o=parseFloat(e.longitude);if(!isNaN(s)&&!isNaN(o))return{latitude:s,longitude:o}}let t=n.headers.get("CF-IPLatitude"),r=n.headers.get("CF-IPLongitude");if(t&&r){let s=parseFloat(t),o=parseFloat(r);if(!isNaN(s)&&!isNaN(o))return{latitude:s,longitude:o}}return{latitude:null,longitude:null}}function us(n,e,t,r){let o=(t-n)*Math.PI/180,i=(r-e)*Math.PI/180,c=Math.sin(o/2)*Math.sin(o/2)+Math.cos(n*Math.PI/180)*Math.cos(t*Math.PI/180)*Math.sin(i/2)*Math.sin(i/2);return 6371*(2*Math.atan2(Math.sqrt(c),Math.sqrt(1-c)))}var Ko=ze(()=>{"use strict"});async function ps(n,e,t,r=256){let o=new TextEncoder().encode(n),i=await crypto.subtle.importKey("raw",o,"PBKDF2",!1,["deriveBits"]),c=await crypto.subtle.deriveBits({name:"PBKDF2",salt:e,iterations:t,hash:"SHA-256"},i,r);return new Uint8Array(c)}async function rd(n,e,t=1e5,r=256){let s=e??crypto.getRandomValues(new Uint8Array(16)),o=await ps(n,s,t,r);return Array.from(o).map(i=>i.toString(16).padStart(2,"0")).join("")}async function ot(n,e=1){let t=crypto.getRandomValues(new Uint8Array(16)),s=await ps(n,t,1e5,256),o=new Uint8Array(t.length+s.length);return o.set(t),o.set(s,t.length),btoa(String.fromCharCode(...o))}async function yt(n,e,t=1){let r=new Uint8Array(atob(e).split("").map(l=>l.charCodeAt(0))),s=r.slice(0,16),o=r.slice(16),c=await ps(n,s,1e5,256);if(c.length!==o.length)return!1;let a=0;for(let l=0;l<c.length;l++)a|=c[l]^o[l];return a===0}function $t(n=5){let e=new Uint8Array(n);crypto.getRandomValues(e);let t="";for(let r=0;r<n;r++)t+=Wo[e[r]&31];return t}function j(n){let e=Math.ceil(n/2),t=new Uint8Array(e);return crypto.getRandomValues(t),Array.from(t).map(r=>r.toString(16).padStart(2,"0")).join("").slice(0,n)}function fs(n){let t=new Uint8Array(atob(n).split("").map(r=>r.charCodeAt(0))).slice(0,16);return Array.from(t).map(r=>r.toString(16).padStart(2,"0")).join("")}async function ms(n,e){let t=new TextEncoder,r=typeof n=="string"?t.encode(n):n,s=typeof e=="string"?t.encode(e):e,o=await crypto.subtle.importKey("raw",r,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),i=await crypto.subtle.sign("HMAC",o,s);return Array.from(new Uint8Array(i)).map(c=>c.toString(16).padStart(2,"0")).join("")}async function re(n,e){let t=new TextEncoder().encode(e);return rd(n,t,100,256)}async function Zi(n,e){let t=new TextEncoder().encode(e.toLowerCase()),r=await ps(n,t,1e4,256);return Array.from(r).map(s=>s.toString(16).padStart(2,"0")).join("")}var Wo,Te=ze(()=>{"use strict";Wo="ybndrfg8ejkmcpqxot1uwisza345h769"});function wt(n,e,t){let r;return t?r=(Number(e.OPTIONAL_SESSION_EXPIRATION_DAYS)||7)*24*60*60:r=(Number(e.DEFAULT_SESSION_EXPIRATION_MINUTES)||1440)*60,`${dr}=${n}; HttpOnly; SameSite=Lax; Path=/; Max-Age=${r}; Secure`}function Qe(){return`${dr}=; HttpOnly; SameSite=Lax; Path=/; Max-Age=0; Secure`}function Le(n){if(!n)return null;let e=n.match(new RegExp(`(?:^|;\\s*)${dr}=([^;]*)`));return e?e[1]:null}function it(n,e,t){let r;return t&&e?r=(Number(e.OPTIONAL_SESSION_EXPIRATION_DAYS)||7)*24*60*60:r=(Number(e?.DEFAULT_SESSION_EXPIRATION_MINUTES)||1440)*60,`csrf_token=${n}; SameSite=Lax; Path=/; Max-Age=${r}; Secure`}function _n(n){if(!n)return null;let e=n.match(/(?:^|;\s*)csrf_token=([^;]*)/);return e?e[1]:null}function hs(n,e){let t=Number(e.PREAUTH_TTL_SECONDS)||300;return`${ur}=${n}; HttpOnly; SameSite=Lax; Path=/; Max-Age=${t}; Secure`}function gs(){return`${ur}=; HttpOnly; SameSite=Lax; Path=/; Max-Age=0; Secure`}function ys(n){if(!n)return null;let e=n.match(new RegExp(`(?:^|;\\s*)${ur}=([^;]*)`));return e?e[1]:null}var dr,ur,qi=ze(()=>{"use strict";dr="auth_refresh",ur="preauth_session"});var pr={};vo(pr,{SessionModel:()=>le});var le,Be=ze(()=>{"use strict";le=class{constructor(e){this.db=e}db;async getSessionUserId(e){let t=await this.db.prepare("SELECT user_id, expires_at FROM sessions WHERE id = ?").bind(e).first();return t?t.expires_at<=Math.floor(Date.now()/1e3)?(await this.deleteSession(e),null):t.user_id:null}async getSession(e){let t=await this.db.prepare("SELECT * FROM sessions WHERE id = ?").bind(e).first();return t?t.expires_at<=Math.floor(Date.now()/1e3)?(await this.deleteSession(e),null):t:null}async getSessionWithUser(e){let t=await this.db.prepare(`
3
3
  SELECT sessions.id as id, sessions.id as session_id, sessions.user_id, sessions.created_at, sessions.expires_at, sessions.ip_address, sessions.user_agent, sessions.latitude, sessions.longitude, sessions.rotation_counter, sessions.last_active_at, sessions.is_paused,
4
4
  users.id as u_id, users.username, users.role, users.pin_hash, users.session_lock_timeout
5
5
  FROM sessions
6
6
  INNER JOIN users ON sessions.user_id = users.id
7
7
  WHERE sessions.id = ?
8
- `).bind(e).first();return n?n.expires_at<=Math.floor(Date.now()/1e3)?(await this.deleteSession(e),null):n:null}async createSession(e,n,r,s,o=null,i=null,c=null,a=null,l=null){return(await this.db.prepare("INSERT INTO sessions (id, user_id, created_at, expires_at, ip_address, user_agent, latitude, longitude, rotation_counter, last_active_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0, ?)").bind(e,n,r,s,o,i,c,a,l||r).run()).success}async updateLastActive(e,n){return(await this.db.prepare("UPDATE sessions SET last_active_at = ? WHERE id = ?").bind(n,e).run()).success}async pauseSession(e){return(await this.db.prepare("UPDATE sessions SET is_paused = 1 WHERE id = ?").bind(e).run()).success}async resumeSession(e,n){return(await this.db.prepare("UPDATE sessions SET is_paused = 0, last_active_at = ? WHERE id = ?").bind(n,e).run()).success}async getSessionsByUser(e,n=Math.floor(Date.now()/1e3)){await this.db.prepare("DELETE FROM sessions WHERE user_id = ? AND expires_at <= ?").bind(e,n).run();let{results:r}=await this.db.prepare(`
8
+ `).bind(e).first();return t?t.expires_at<=Math.floor(Date.now()/1e3)?(await this.deleteSession(e),null):t:null}async createSession(e,t,r,s,o=null,i=null,c=null,a=null,l=null){return(await this.db.prepare("INSERT INTO sessions (id, user_id, created_at, expires_at, ip_address, user_agent, latitude, longitude, rotation_counter, last_active_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0, ?)").bind(e,t,r,s,o,i,c,a,l||r).run()).success}async updateLastActive(e,t){return(await this.db.prepare("UPDATE sessions SET last_active_at = ? WHERE id = ?").bind(t,e).run()).success}async pauseSession(e){return(await this.db.prepare("UPDATE sessions SET is_paused = 1 WHERE id = ?").bind(e).run()).success}async resumeSession(e,t){return(await this.db.prepare("UPDATE sessions SET is_paused = 0, last_active_at = ? WHERE id = ?").bind(t,e).run()).success}async getSessionsByUser(e,t=Math.floor(Date.now()/1e3)){await this.db.prepare("DELETE FROM sessions WHERE user_id = ? AND expires_at <= ?").bind(e,t).run();let{results:r}=await this.db.prepare(`
9
9
  SELECT id, ip_address, user_agent, created_at, expires_at, latitude, longitude
10
10
  FROM sessions
11
11
  WHERE user_id = ? AND expires_at > ?
12
12
  ORDER BY expires_at DESC
13
- `).bind(e,n).all();return r}async deleteExpiredSessions(e=Math.floor(Date.now()/1e3)){let n=await this.db.prepare("DELETE FROM sessions WHERE expires_at <= ?").bind(e).run(),r=await this.db.prepare("DELETE FROM pending_totp_sessions WHERE expires_at <= ?").bind(e).run();return{deletedSessions:n.meta?.changes||0,deletedPending:r.meta?.changes||0}}async extendSession(e,n){return(await this.db.prepare("UPDATE sessions SET expires_at = ? WHERE id = ?").bind(n,e).run()).success}async incrementRotationCounter(e){return(await this.db.prepare("UPDATE sessions SET rotation_counter = rotation_counter + 1 WHERE id = ?").bind(e).run()).success}async deleteSession(e){return(await this.db.prepare("DELETE FROM sessions WHERE id = ?").bind(e).run()).success}async deleteAllByUserId(e){return(await this.db.prepare("DELETE FROM sessions WHERE user_id = ?").bind(e).run()).success}async createPendingTotpSession(e,n,r){return(await this.db.prepare("INSERT INTO pending_totp_sessions (id, user_id, expires_at) VALUES (?, ?, ?)").bind(e,n,r).run()).success}async getPendingTotpSession(e){let n=await this.db.prepare("SELECT * FROM pending_totp_sessions WHERE id = ?").bind(e).first();return n?n.expires_at<=Math.floor(Date.now()/1e3)?(await this.deletePendingTotpSession(e),null):n:null}async deletePendingTotpSession(e){return(await this.db.prepare("DELETE FROM pending_totp_sessions WHERE id = ?").bind(e).run()).success}}});function ar(t){let e="";if(typeof t=="string")e=t;else{let n=new Uint8Array(t);for(let r=0;r<n.byteLength;r++)e+=String.fromCharCode(n[r])}return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function ds(t){let e=t.replace(/-/g,"+").replace(/_/g,"/");for(;e.length%4;)e+="=";let n=atob(e),r=new Uint8Array(n.length);for(let s=0;s<n.length;s++)r[s]=n.charCodeAt(s);return r}function Yi(t){return new TextEncoder().encode(t)}function Fo(t){return typeof t!="string"?!0:t.trim().length===0}function Ho(t){return typeof t!="string"?!1:Xl.has(t.trim())}function gn(t){return Fo(t)?"missing":Ho(t)?"preset":"valid"}function ke(t){return gn(t)==="valid"}function gt(t){return ke(t)?t.trim().length>=Bo:!1}async function Le(t){let e=new TextEncoder().encode(`${t}:${zl}`),n=await crypto.subtle.digest("SHA-256",e);return crypto.subtle.importKey("raw",n,{name:"HMAC",hash:"SHA-512"},!1,["sign","verify"])}async function yn(t,e){let r=ar(JSON.stringify({alg:"HS512",typ:"JWT"})),s=ar(JSON.stringify(t)),o=`${r}.${s}`,i=await crypto.subtle.sign("HMAC",e,Yi(o)),c=ar(i);return`${o}.${c}`}async function wn(t,e){let n=t.split(".");if(n.length!==3)return null;let[r,s,o]=n,i=`${r}.${s}`,c=ds(o);if(!await crypto.subtle.verify("HMAC",e,c,Yi(i)))return null;try{let l=ds(s),d=new TextDecoder().decode(l),u=JSON.parse(d);return u.exp&&Math.floor(Date.now()/1e3)>u.exp?null:u}catch{return null}}var Bo,Xl,zl,Ue=Ge(()=>{"use strict";Bo=32,Xl=new Set(["your_secure_random_string_here","\u60A8\u7684\u968F\u673A\u5B89\u5168JWT\u5BC6\u94A5","\u60A8\u7684\u96A8\u6A5F\u5B89\u5168JWT\u91D1\u9470","replace_with_a_secure_random_jwt_secret_string_32chars_min"]);zl="DNS_WORKER_JWT_KEY_SALT_v1"});function cr(t,e){let n={sid:t,v:e,ts:Date.now()};return ar(JSON.stringify(n))}function Ae(t){try{let e=new TextDecoder().decode(ds(t));return JSON.parse(e)}catch{return null}}async function bn(t,e,n=null,r=null,s=null,o=null,i){let a=(i?"k_":"s_")+j(lr-2),l=Math.floor(Date.now()/1e3),d;if(i){let m=Number(t.OPTIONAL_SESSION_EXPIRATION_DAYS)||7;d=l+m*24*60*60}else{let m=Number(t.DEFAULT_SESSION_EXPIRATION_MINUTES)||1440;d=l+m*60}let u={id:a,user_id:e,created_at:l,expires_at:d,ip_address:n,user_agent:r,latitude:s,longitude:o,last_active_at:l};await new le(t.DB).createSession(u.id,u.user_id,u.created_at,u.expires_at,u.ip_address,u.user_agent,u.latitude,u.longitude,u.last_active_at);let p=cr(u.id,0);return{session:u,refreshToken:p}}async function us(t,e,n=null,r=null){let s=Ae(e);if(!s)return{session:null,user:null,newRefreshToken:null,reason:"invalid_token"};let o=new le(t.DB),i=await o.getSessionWithUser(s.sid);if(!i)return{session:null,user:null,newRefreshToken:null,reason:"session_not_found"};let c={id:i.session_id,user_id:i.user_id,created_at:i.created_at,expires_at:i.expires_at,ip_address:i.ip_address,user_agent:i.user_agent,latitude:i.latitude,longitude:i.longitude,rotation_counter:i.rotation_counter,last_active_at:i.last_active_at,is_paused:i.is_paused},a={id:i.u_id,username:i.username,role:i.role,pin_hash:i.pin_hash,session_lock_timeout:i.session_lock_timeout},l=Math.floor(Date.now()/1e3);if(l>=c.expires_at)return await yt(t,c.id),{session:null,user:a,newRefreshToken:null,reason:"expired"};let d=c.rotation_counter===s.v,u=c.rotation_counter!==void 0&&s.v===c.rotation_counter-1,f=c.last_active_at||c.created_at,p=15;if(!d){if(u&&l-f<=p){let S=cr(c.id,c.rotation_counter||1);return{session:c,user:a,newRefreshToken:S}}return await yt(t,c.id),{session:null,user:a,newRefreshToken:null,reason:"token_reuse"}}let m=t.SERVERFULL_DEFAULT_PROFILE_KEY!==void 0||t.SERVERFULL_HOST!==void 0||t.SERVERFULL_DOT_DOMAIN!==void 0||t.SERVERFULL_HTTP_PORT!==void 0||t.SERVERFULL_HTTPS_PORT!==void 0,h=c.latitude===0&&c.longitude===0||n===0&&r===0;if(!m&&!h){if(c.latitude===null||c.latitude===void 0||c.longitude===null||c.longitude===void 0||n===null||r===null)return await yt(t,c.id),{session:null,user:a,newRefreshToken:null,reason:"geolocation_missing"};let S=rs(c.latitude,c.longitude,n,r),x=Number(t.SESSION_GEO_DISTANCE_KM)||50;if(S>x)return await yt(t,c.id),{session:null,user:a,newRefreshToken:null,reason:"geolocation_mismatch"}}if(a.pin_hash&&!c.is_paused){let S=(a.session_lock_timeout||15)*60;l-f>S&&(await o.pauseSession(c.id),c.is_paused=1)}let g=c.expires_at-Math.floor(Date.now()/1e3),b=c.id.startsWith("k_")?(Number(t.OPTIONAL_SESSION_EXPIRATION_DAYS)||7)*24*60*60:(Number(t.DEFAULT_SESSION_EXPIRATION_MINUTES)||1440)*60,y=Math.floor(b/2);g<y&&(c.expires_at=Math.floor(Date.now()/1e3)+b,await o.extendSession(c.id,c.expires_at)),await o.incrementRotationCounter(c.id),c.is_paused||await o.updateLastActive(c.id,l);let E=(c.rotation_counter||0)+1,_=cr(c.id,E);return{session:c,user:a,newRefreshToken:_}}async function yt(t,e){await new le(t.DB).deleteSession(e)}var lr,$o=Ge(()=>{"use strict";Ie();Re();Ue();Uo();lr=80});async function ps(t,e){let n=j(lr),r=Number(t.PREAUTH_TTL_SECONDS)||300,s=Math.floor(Date.now()/1e3)+r;return await new le(t.DB).createPendingTotpSession(n,e,s),n}async function fs(t,e){let n=new le(t.DB),r=await n.getPendingTotpSession(e);return r?Math.floor(Date.now()/1e3)>=r.expires_at?(await n.deletePendingTotpSession(e),null):r.user_id:null}async function dr(t,e){await new le(t.DB).deletePendingTotpSession(e)}async function Xe(t,e,n){let r=`preauth_state:${e}`,s=await P.get(t,r);if(!s)return 0;let o=(s.failedAttempts||0)+1;if(o>=3)return await new le(n.DB).deletePendingTotpSession(e),await P.delete(t,r),0;let i=Number(n.PREAUTH_TTL_SECONDS)||300;return await P.set(t,r,{...s,failedAttempts:o},i),3-o}var Xi=Ge(()=>{"use strict";Ie();Re();$o();ge()});var ur={};_o(ur,{MIN_JWT_SECRET_LENGTH:()=>Bo,PREAUTH_COOKIE_NAME:()=>or,REFRESH_TOKEN_COOKIE_NAME:()=>sr,SESSION_ID_LENGTH:()=>lr,ZBASE32_ALPHABET:()=>Mo,calculateDistanceInKm:()=>rs,clearPreauthCookie:()=>cs,createBlankRefreshTokenCookie:()=>Ye,createCsrfCookie:()=>tt,createPreauthCookie:()=>as,createPreauthSession:()=>ps,createRefreshTokenCookie:()=>ht,createRefreshTokenString:()=>cr,createSession:()=>bn,extractSaltHex:()=>os,generateId:()=>j,generateSessionHash:()=>re,generateZBase32Token:()=>Mt,getJwtSecretStatus:()=>gn,getOrCreateJwtSecret:()=>Me,getRequestCoordinates:()=>mn,hmacSha256:()=>is,invalidatePreauthSession:()=>dr,invalidateSession:()=>yt,isMissingJwtSecret:()=>Fo,isPresetJwtSecret:()=>Ho,isStrongJwtSecret:()=>gt,isUsableJwtSecret:()=>ke,parseRefreshTokenString:()=>Ae,readCsrfCookie:()=>hn,readPreauthCookie:()=>ls,readRefreshTokenCookie:()=>De,recordFailedPreauthAttempt:()=>Xe,rotateSession:()=>us,validatePreauthSession:()=>fs});async function Me(t){let e=gn(t.JWT_SECRET);if(e==="missing")throw new Error("jwt_secret_missing");if(e==="preset")throw new Error("jwt_secret_preset");return t.JWT_SECRET}var pe=Ge(()=>{"use strict";Uo();Re();Gi();$o();Xi();Ue()});var Nc={};_o(Nc,{applySecurityHeaders:()=>xi,getCurrentUser:()=>Ai,invalidateAuthUserCache:()=>Fn,validateCsrf:()=>vi});function xi(t,e){let n=new Headers(t.headers);return n.set("X-Content-Type-Options","nosniff"),n.set("X-Frame-Options","DENY"),n.set("X-XSS-Protection","1; mode=block"),n.set("Strict-Transport-Security","max-age=31536000; includeSubDomains; preload"),n.set("Cross-Origin-Opener-Policy","same-origin"),n.set("Cross-Origin-Embedder-Policy","credentialless"),n.has("Content-Security-Policy")||n.set("Content-Security-Policy",`default-src 'self'; script-src 'self' 'nonce-${e}' https://challenges.cloudflare.com https://static.cloudflareinsights.com 'wasm-unsafe-eval'; worker-src 'self' blob:; script-src-attr 'unsafe-inline'; frame-src 'self' https://challenges.cloudflare.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://icons.duckduckgo.com; connect-src 'self' https://challenges.cloudflare.com https://cloudflare-dns.com https://1.1.1.1;`),n.has("Alt-Svc")||n.set("Alt-Svc",'h3=":443"; ma=86400, h3-29=":443"; ma=86400'),new Response(t.body,{status:t.status,statusText:t.statusText,headers:n})}function Fn(t){en.delete(t),Dt.delete(t)}async function Ai(t,e,n){let r=t.headers.get("Authorization")||"",s="";if(r.startsWith("Bearer "))s=r.slice(7);else if(t.headers.get("Upgrade")?.toLowerCase().includes("websocket")||new URL(t.url).pathname.endsWith("/ws")){let o=new URL(t.url);s=o.searchParams.get("token")||o.searchParams.get("access_token")||""}if(!s)return null;try{let o=await Me(e),i=await Le(o),c=await wn(s,i);if(c){let a=en.get(c.sessionId);if(a&&a.expiresAt>Date.now()){let _=Dt.get(c.sessionId);return _&&(_.lastObserved=Math.floor(Date.now()/1e3)),a.user}let l=new le(e.DB),d=await l.getSessionWithUser(c.sessionId);if(!d)return en.delete(c.sessionId),Dt.delete(c.sessionId),null;let u=d.id||d.session_id||c.sessionId,f=Math.floor(Date.now()/1e3),p=d.last_active_at||d.created_at,m=Dt.get(c.sessionId),h=Math.max(p,m?.lastObserved??0);if(d.pin_hash&&!d.is_paused){let _=(d.session_lock_timeout||15)*60;if(f-h>_){try{await l.pauseSession(u)}catch(S){console.error("[Auth] Failed to update pauseSession in D1:",S)}d.is_paused=1}}if(d.is_paused)return{id:c.userId,username:d.username||"",role:d.role||c.role,isPaused:!0,sessionId:c.sessionId};let g=m?.lastWriteAttempt??p,w=parseInt(String(e.SESSION_LAST_ACTIVE_UPDATE_INTERVAL||"60"),10)||60,b=g;if(f-g>w){b=f;let _=l.updateLastActive(u,f).catch(S=>console.error("[Auth] session last-active write failed:",S));n&&typeof n.waitUntil=="function"&&n.waitUntil(_)}if(Dt.size>1e3){let _=Dt.keys().next().value;_&&Dt.delete(_)}Dt.set(c.sessionId,{lastObserved:f,lastWriteAttempt:b});let y={id:c.userId,username:d.username||"",role:d.role||c.role,sessionId:c.sessionId},E=parseInt(String(e.AUTH_CACHE_TTL_SEC||"30"),10)||30;if(en.size>100){let _=en.keys().next().value;_&&en.delete(_)}return en.set(c.sessionId,{user:y,expiresAt:Date.now()+E*1e3}),y}}catch{}return null}function vi(t){let e=t.headers.get("Cookie")||"",n=hn(e),r=t.headers.get("X-CSRF-Token");return!!n&&!!r&&n===r}var en,Dt,Lr=Ge(()=>{"use strict";pe();Ue();Ie();en=new Map,Dt=new Map});import Yu from"node:path";import{parseArgs as Xu}from"node:util";var Br=class{store=new Map;async match(e){let n=typeof e=="string"?e:e.url,r=this.store.get(n);if(r){if(Date.now()>r.expires){this.store.delete(n);return}return new Response(r.body,{status:r.status,statusText:r.statusText,headers:new Headers(r.headers)})}}async put(e,n){let r=typeof e=="string"?e:e.url,o=(n.headers.get("Cache-Control")||"").match(/max-age=(\d+)/i),i=o?parseInt(o[1],10):3600,c=await n.clone().arrayBuffer();this.store.set(r,{body:new Uint8Array(c),headers:new Headers(n.headers),status:n.status,statusText:n.statusText,expires:Date.now()+i*1e3})}async delete(e){let n=typeof e=="string"?e:e.url;return this.store.delete(n)}};function Ui(){if(typeof globalThis.caches>"u"){let t=new Br;globalThis.caches={default:t,open:async()=>new Br}}typeof globalThis.HTMLRewriter>"u"&&(globalThis.HTMLRewriter=class{handlers=[];on(t,e){return e.element&&this.handlers.push({selector:t,fn:e.element}),this}transform(t){let e=this.handlers,n=t.text(),r=new ReadableStream({async start(o){let i=await n;for(let c of e)c.selector==="head"&&c.fn({prepend(a){i=i.replace(/<head[^>]*>/i,`$&${a}`)},append(a){i=i.replace(/<\/head>/i,`${a}$&`)}});o.enqueue(new TextEncoder().encode(i)),o.close()}}),s=new Headers(t.headers);return s.delete("content-length"),new Response(r,{status:t.status,statusText:t.statusText,headers:s})}})}import ne from"node:fs";import G from"node:path";import Nl from"node:crypto";import{execSync as Bi}from"node:child_process";import{fileURLToPath as Il}from"node:url";var Fr=[{label:"settings.presetCloudflareSecurity",url:"https://security.cloudflare-dns.com/dns-query"},{label:"settings.presetCloudflareFamilies",url:"https://family.cloudflare-dns.com/dns-query"},{label:"Cloudflare",url:"https://cloudflare-dns.com/dns-query"},{label:"settings.presetQuad9",url:"https://dns.quad9.net/dns-query"},{label:"settings.presetQuad9Ecs",url:"https://dns11.quad9.net/dns-query"},{label:"settings.presetControlDFree",url:"https://freedns.controld.com/no-ads-malware-typo"},{label:"settings.presetControlDUncensored",url:"https://freedns.controld.com/uncensored"},{label:"settings.presetAdGuard",url:"https://dns.adguard-dns.com/dns-query"},{label:"settings.presetAdGuardFamily",url:"https://family.adguard-dns.com/dns-query"},{label:"Cloudflare Security (1.1.1.2)",url:"tcp://1.1.1.2:53"},{label:"Cloudflare (1.1.1.1)",url:"tcp://1.1.1.1:53"},{label:"Quad9 ECS (9.9.9.11)",url:"tcp://9.9.9.11:9953"},{label:"Google (8.8.8.8)",url:"tcp://8.8.8.8:53"}],Hr=[{label:"filtering.presetOisdBig",url:"https://big.oisd.nl"},{label:"filtering.presetOisdNsfw",url:"https://nsfw.oisd.nl"},{label:"filtering.presetAdGuard",url:"https://adguardteam.github.io/AdguardFilters/BaseFilter/sections/adservers.txt"},{label:"filtering.presetStevenBlack",url:"https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts"}],$r=[{ip:"198.41.222.102",area:"SG"},{ip:"173.245.59.246",area:"SG"},{ip:"104.18.47.174",area:"HK"},{ip:"104.19.50.3",area:"HK"}],Yn="www.okx.com",Mi="https://freedns.controld.com/no-ads-malware-typo";import Kr from"node:fs";import Ll from"node:path";import{execSync as Ol}from"node:child_process";var So=`# ==============================================================================
13
+ `).bind(e,t).all();return r}async deleteExpiredSessions(e=Math.floor(Date.now()/1e3)){let t=await this.db.prepare("DELETE FROM sessions WHERE expires_at <= ?").bind(e).run(),r=await this.db.prepare("DELETE FROM pending_totp_sessions WHERE expires_at <= ?").bind(e).run();return{deletedSessions:t.meta?.changes||0,deletedPending:r.meta?.changes||0}}async extendSession(e,t){return(await this.db.prepare("UPDATE sessions SET expires_at = ? WHERE id = ?").bind(t,e).run()).success}async incrementRotationCounter(e){return(await this.db.prepare("UPDATE sessions SET rotation_counter = rotation_counter + 1 WHERE id = ?").bind(e).run()).success}async deleteSession(e){return(await this.db.prepare("DELETE FROM sessions WHERE id = ?").bind(e).run()).success}async deleteAllByUserId(e){return(await this.db.prepare("DELETE FROM sessions WHERE user_id = ?").bind(e).run()).success}async createPendingTotpSession(e,t,r){return(await this.db.prepare("INSERT INTO pending_totp_sessions (id, user_id, expires_at) VALUES (?, ?, ?)").bind(e,t,r).run()).success}async getPendingTotpSession(e){let t=await this.db.prepare("SELECT * FROM pending_totp_sessions WHERE id = ?").bind(e).first();return t?t.expires_at<=Math.floor(Date.now()/1e3)?(await this.deletePendingTotpSession(e),null):t:null}async deletePendingTotpSession(e){return(await this.db.prepare("DELETE FROM pending_totp_sessions WHERE id = ?").bind(e).run()).success}}});function fr(n){let e="";if(typeof n=="string")e=n;else{let t=new Uint8Array(n);for(let r=0;r<t.byteLength;r++)e+=String.fromCharCode(t[r])}return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function ws(n){let e=n.replace(/-/g,"+").replace(/_/g,"/");for(;e.length%4;)e+="=";let t=atob(e),r=new Uint8Array(t.length);for(let s=0;s<t.length;s++)r[s]=t.charCodeAt(s);return r}function ea(n){return new TextEncoder().encode(n)}function Vo(n){return typeof n!="string"?!0:n.trim().length===0}function Go(n){return typeof n!="string"?!1:sd.has(n.trim())}function Sn(n){return Vo(n)?"missing":Go(n)?"preset":"valid"}function Oe(n){return Sn(n)==="valid"}function bt(n){return Oe(n)?n.trim().length>=jo:!1}async function Ne(n){let e=new TextEncoder().encode(`${n}:${od}`),t=await crypto.subtle.digest("SHA-256",e);return crypto.subtle.importKey("raw",t,{name:"HMAC",hash:"SHA-512"},!1,["sign","verify"])}async function Rn(n,e){let r=fr(JSON.stringify({alg:"HS512",typ:"JWT"})),s=fr(JSON.stringify(n)),o=`${r}.${s}`,i=await crypto.subtle.sign("HMAC",e,ea(o)),c=fr(i);return`${o}.${c}`}async function Tn(n,e){let t=n.split(".");if(t.length!==3)return null;let[r,s,o]=t,i=`${r}.${s}`,c=ws(o);if(!await crypto.subtle.verify("HMAC",e,c,ea(i)))return null;try{let l=ws(s),d=new TextDecoder().decode(l),u=JSON.parse(d);return u.exp&&Math.floor(Date.now()/1e3)>u.exp?null:u}catch{return null}}var jo,sd,od,Fe=ze(()=>{"use strict";jo=32,sd=new Set(["your_secure_random_string_here","\u60A8\u7684\u968F\u673A\u5B89\u5168JWT\u5BC6\u94A5","\u60A8\u7684\u96A8\u6A5F\u5B89\u5168JWT\u91D1\u9470","replace_with_a_secure_random_jwt_secret_string_32chars_min"]);od="DNS_WORKER_JWT_KEY_SALT_v1"});function mr(n,e){let t={sid:n,v:e,ts:Date.now()};return fr(JSON.stringify(t))}function ve(n){try{let e=new TextDecoder().decode(ws(n));return JSON.parse(e)}catch{return null}}async function xn(n,e,t=null,r=null,s=null,o=null,i){let a=(i?"k_":"s_")+j(hr-2),l=Math.floor(Date.now()/1e3),d;if(i){let m=Number(n.OPTIONAL_SESSION_EXPIRATION_DAYS)||7;d=l+m*24*60*60}else{let m=Number(n.DEFAULT_SESSION_EXPIRATION_MINUTES)||1440;d=l+m*60}let u={id:a,user_id:e,created_at:l,expires_at:d,ip_address:t,user_agent:r,latitude:s,longitude:o,last_active_at:l};await new le(n.DB).createSession(u.id,u.user_id,u.created_at,u.expires_at,u.ip_address,u.user_agent,u.latitude,u.longitude,u.last_active_at);let p=mr(u.id,0);return{session:u,refreshToken:p}}async function bs(n,e,t=null,r=null){let s=ve(e);if(!s)return{session:null,user:null,newRefreshToken:null,reason:"invalid_token"};let o=new le(n.DB),i=await o.getSessionWithUser(s.sid);if(!i)return{session:null,user:null,newRefreshToken:null,reason:"session_not_found"};let c={id:i.session_id,user_id:i.user_id,created_at:i.created_at,expires_at:i.expires_at,ip_address:i.ip_address,user_agent:i.user_agent,latitude:i.latitude,longitude:i.longitude,rotation_counter:i.rotation_counter,last_active_at:i.last_active_at,is_paused:i.is_paused},a={id:i.u_id,username:i.username,role:i.role,pin_hash:i.pin_hash,session_lock_timeout:i.session_lock_timeout},l=Math.floor(Date.now()/1e3);if(l>=c.expires_at)return await Et(n,c.id),{session:null,user:a,newRefreshToken:null,reason:"expired"};let d=c.rotation_counter===s.v,u=c.rotation_counter!==void 0&&s.v===c.rotation_counter-1,f=c.last_active_at||c.created_at,p=15;if(!d){if(u&&l-f<=p){let S=mr(c.id,c.rotation_counter||1);return{session:c,user:a,newRefreshToken:S}}return await Et(n,c.id),{session:null,user:a,newRefreshToken:null,reason:"token_reuse"}}let m=n.SERVERFULL_DEFAULT_PROFILE_KEY!==void 0||n.SERVERFULL_HOST!==void 0||n.SERVERFULL_DOT_DOMAIN!==void 0||n.SERVERFULL_HTTP_PORT!==void 0||n.SERVERFULL_HTTPS_PORT!==void 0,h=c.latitude===0&&c.longitude===0||t===0&&r===0;if(!m&&!h){if(c.latitude===null||c.latitude===void 0||c.longitude===null||c.longitude===void 0||t===null||r===null)return await Et(n,c.id),{session:null,user:a,newRefreshToken:null,reason:"geolocation_missing"};let S=us(c.latitude,c.longitude,t,r),x=Number(n.SESSION_GEO_DISTANCE_KM)||50;if(S>x)return await Et(n,c.id),{session:null,user:a,newRefreshToken:null,reason:"geolocation_mismatch"}}if(a.pin_hash&&!c.is_paused){let S=(a.session_lock_timeout||15)*60;l-f>S&&(await o.pauseSession(c.id),c.is_paused=1)}let g=c.expires_at-Math.floor(Date.now()/1e3),w=c.id.startsWith("k_")?(Number(n.OPTIONAL_SESSION_EXPIRATION_DAYS)||7)*24*60*60:(Number(n.DEFAULT_SESSION_EXPIRATION_MINUTES)||1440)*60,y=Math.floor(w/2);g<y&&(c.expires_at=Math.floor(Date.now()/1e3)+w,await o.extendSession(c.id,c.expires_at)),await o.incrementRotationCounter(c.id),c.is_paused||await o.updateLastActive(c.id,l);let E=(c.rotation_counter||0)+1,_=mr(c.id,E);return{session:c,user:a,newRefreshToken:_}}async function Et(n,e){await new le(n.DB).deleteSession(e)}var hr,Jo=ze(()=>{"use strict";Be();Te();Fe();Ko();hr=80});async function Es(n,e){let t=j(hr),r=Number(n.PREAUTH_TTL_SECONDS)||300,s=Math.floor(Date.now()/1e3)+r;return await new le(n.DB).createPendingTotpSession(t,e,s),t}async function _s(n,e){let t=new le(n.DB),r=await t.getPendingTotpSession(e);return r?Math.floor(Date.now()/1e3)>=r.expires_at?(await t.deletePendingTotpSession(e),null):r.user_id:null}async function gr(n,e){await new le(n.DB).deletePendingTotpSession(e)}async function Ze(n,e,t){let r=`preauth_state:${e}`,s=await P.get(n,r);if(!s)return 0;let o=(s.failedAttempts||0)+1;if(o>=3)return await new le(t.DB).deletePendingTotpSession(e),await P.delete(n,r),0;let i=Number(t.PREAUTH_TTL_SECONDS)||300;return await P.set(n,r,{...s,failedAttempts:o},i),3-o}var ta=ze(()=>{"use strict";Be();Te();Jo();ge()});var yr={};vo(yr,{MIN_JWT_SECRET_LENGTH:()=>jo,PREAUTH_COOKIE_NAME:()=>ur,REFRESH_TOKEN_COOKIE_NAME:()=>dr,SESSION_ID_LENGTH:()=>hr,ZBASE32_ALPHABET:()=>Wo,calculateDistanceInKm:()=>us,clearPreauthCookie:()=>gs,createBlankRefreshTokenCookie:()=>Qe,createCsrfCookie:()=>it,createPreauthCookie:()=>hs,createPreauthSession:()=>Es,createRefreshTokenCookie:()=>wt,createRefreshTokenString:()=>mr,createSession:()=>xn,extractSaltHex:()=>fs,generateId:()=>j,generateSessionHash:()=>re,generateZBase32Token:()=>$t,getJwtSecretStatus:()=>Sn,getOrCreateJwtSecret:()=>He,getRequestCoordinates:()=>En,hmacSha256:()=>ms,invalidatePreauthSession:()=>gr,invalidateSession:()=>Et,isMissingJwtSecret:()=>Vo,isPresetJwtSecret:()=>Go,isStrongJwtSecret:()=>bt,isUsableJwtSecret:()=>Oe,parseRefreshTokenString:()=>ve,readCsrfCookie:()=>_n,readPreauthCookie:()=>ys,readRefreshTokenCookie:()=>Le,recordFailedPreauthAttempt:()=>Ze,rotateSession:()=>bs,validatePreauthSession:()=>_s});async function He(n){let e=Sn(n.JWT_SECRET);if(e==="missing")throw new Error("jwt_secret_missing");if(e==="preset")throw new Error("jwt_secret_preset");return n.JWT_SECRET}var pe=ze(()=>{"use strict";Ko();Te();qi();Jo();ta();Fe()});var Hc={};vo(Hc,{applySecurityHeaders:()=>ki,getCurrentUser:()=>Li,invalidateAuthUserCache:()=>Vn,validateCsrf:()=>Oi});function ki(n,e){let t=new Headers(n.headers);return t.set("X-Content-Type-Options","nosniff"),t.set("X-Frame-Options","DENY"),t.set("X-XSS-Protection","1; mode=block"),t.set("Strict-Transport-Security","max-age=31536000; includeSubDomains; preload"),t.set("Cross-Origin-Opener-Policy","same-origin"),t.set("Cross-Origin-Embedder-Policy","credentialless"),t.has("Content-Security-Policy")||t.set("Content-Security-Policy",`default-src 'self'; script-src 'self' 'nonce-${e}' https://challenges.cloudflare.com https://static.cloudflareinsights.com 'wasm-unsafe-eval'; worker-src 'self' blob:; script-src-attr 'unsafe-inline'; frame-src 'self' https://challenges.cloudflare.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://icons.duckduckgo.com; connect-src 'self' https://challenges.cloudflare.com https://cloudflare-dns.com https://1.1.1.1;`),t.has("Alt-Svc")||t.set("Alt-Svc",'h3=":443"; ma=86400, h3-29=":443"; ma=86400'),new Response(n.body,{status:n.status,statusText:n.statusText,headers:t})}function Vn(n){on.delete(n),Lt.delete(n)}async function Li(n,e,t){let r=n.headers.get("Authorization")||"",s="";if(r.startsWith("Bearer "))s=r.slice(7);else if(n.headers.get("Upgrade")?.toLowerCase().includes("websocket")||new URL(n.url).pathname.endsWith("/ws")){let o=new URL(n.url);s=o.searchParams.get("token")||o.searchParams.get("access_token")||""}if(!s)return null;try{let o=await He(e),i=await Ne(o),c=await Tn(s,i);if(c){let a=on.get(c.sessionId);if(a&&a.expiresAt>Date.now()){let _=Lt.get(c.sessionId);return _&&(_.lastObserved=Math.floor(Date.now()/1e3)),a.user}let l=new le(e.DB),d=await l.getSessionWithUser(c.sessionId);if(!d)return on.delete(c.sessionId),Lt.delete(c.sessionId),null;let u=d.id||d.session_id||c.sessionId,f=Math.floor(Date.now()/1e3),p=d.last_active_at||d.created_at,m=Lt.get(c.sessionId),h=Math.max(p,m?.lastObserved??0);if(d.pin_hash&&!d.is_paused){let _=(d.session_lock_timeout||15)*60;if(f-h>_){try{await l.pauseSession(u)}catch(S){console.error("[Auth] Failed to update pauseSession in D1:",S)}d.is_paused=1}}if(d.is_paused)return{id:c.userId,username:d.username||"",role:d.role||c.role,isPaused:!0,sessionId:c.sessionId};let g=m?.lastWriteAttempt??p,b=parseInt(String(e.SESSION_LAST_ACTIVE_UPDATE_INTERVAL||"60"),10)||60,w=g;if(f-g>b){w=f;let _=l.updateLastActive(u,f).catch(S=>console.error("[Auth] session last-active write failed:",S));t&&typeof t.waitUntil=="function"&&t.waitUntil(_)}if(Lt.size>1e3){let _=Lt.keys().next().value;_&&Lt.delete(_)}Lt.set(c.sessionId,{lastObserved:f,lastWriteAttempt:w});let y={id:c.userId,username:d.username||"",role:d.role||c.role,sessionId:c.sessionId},E=parseInt(String(e.AUTH_CACHE_TTL_SEC||"30"),10)||30;if(on.size>100){let _=on.keys().next().value;_&&on.delete(_)}return on.set(c.sessionId,{user:y,expiresAt:Date.now()+E*1e3}),y}}catch{}return null}function Oi(n){let e=n.headers.get("Cookie")||"",t=_n(e),r=n.headers.get("X-CSRF-Token");return!!t&&!!r&&t===r}var on,Lt,Hr=ze(()=>{"use strict";pe();Fe();Be();on=new Map,Lt=new Map});import cp from"node:path";import{parseArgs as lp}from"node:util";var Jr=class{store=new Map;async match(e){let t=typeof e=="string"?e:e.url,r=this.store.get(t);if(r){if(Date.now()>r.expires){this.store.delete(t);return}return new Response(r.body,{status:r.status,statusText:r.statusText,headers:new Headers(r.headers)})}}async put(e,t){let r=typeof e=="string"?e:e.url,o=(t.headers.get("Cache-Control")||"").match(/max-age=(\d+)/i),i=o?parseInt(o[1],10):3600,c=await t.clone().arrayBuffer();this.store.set(r,{body:new Uint8Array(c),headers:new Headers(t.headers),status:t.status,statusText:t.statusText,expires:Date.now()+i*1e3})}async delete(e){let t=typeof e=="string"?e:e.url;return this.store.delete(t)}};function Wi(){if(typeof globalThis.caches>"u"){let n=new Jr;globalThis.caches={default:n,open:async()=>new Jr}}typeof globalThis.HTMLRewriter>"u"&&(globalThis.HTMLRewriter=class{handlers=[];on(n,e){return e.element&&this.handlers.push({selector:n,fn:e.element}),this}transform(n){let e=this.handlers,t=n.text(),r=new ReadableStream({async start(o){let i=await t;for(let c of e)c.selector==="head"&&c.fn({prepend(a){i=i.replace(/<head[^>]*>/i,`$&${a}`)},append(a){i=i.replace(/<\/head>/i,`${a}$&`)}});o.enqueue(new TextEncoder().encode(i)),o.close()}}),s=new Headers(n.headers);return s.delete("content-length"),new Response(r,{status:n.status,statusText:n.statusText,headers:s})}})}import ne from"node:fs";import J from"node:path";import Wl from"node:crypto";import{execSync as Vi}from"node:child_process";import{fileURLToPath as jl}from"node:url";var Yr=[{label:"settings.presetCloudflareSecurity",url:"https://security.cloudflare-dns.com/dns-query"},{label:"settings.presetCloudflareFamilies",url:"https://family.cloudflare-dns.com/dns-query"},{label:"Cloudflare",url:"https://cloudflare-dns.com/dns-query"},{label:"settings.presetQuad9",url:"https://dns.quad9.net/dns-query"},{label:"settings.presetQuad9Ecs",url:"https://dns11.quad9.net/dns-query"},{label:"settings.presetControlDFree",url:"https://freedns.controld.com/no-ads-malware-typo"},{label:"settings.presetControlDUncensored",url:"https://freedns.controld.com/uncensored"},{label:"settings.presetAdGuard",url:"https://dns.adguard-dns.com/dns-query"},{label:"settings.presetAdGuardFamily",url:"https://family.adguard-dns.com/dns-query"},{label:"Cloudflare Security (1.1.1.2)",url:"tcp://1.1.1.2:53"},{label:"Cloudflare (1.1.1.1)",url:"tcp://1.1.1.1:53"},{label:"Quad9 ECS (9.9.9.11)",url:"tcp://9.9.9.11:9953"},{label:"Google (8.8.8.8)",url:"tcp://8.8.8.8:53"}],zr=[{label:"filtering.presetOisdBig",url:"https://big.oisd.nl"},{label:"filtering.presetOisdNsfw",url:"https://nsfw.oisd.nl"},{label:"filtering.presetAdGuard",url:"https://adguardteam.github.io/AdguardFilters/BaseFilter/sections/adservers.txt"},{label:"filtering.presetStevenBlack",url:"https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts"}],Xr=[{ip:"198.41.222.102",area:"SG"},{ip:"173.245.59.246",area:"SG"},{ip:"104.18.47.174",area:"HK"},{ip:"104.19.50.3",area:"HK"}],tr="www.okx.com",ji="https://freedns.controld.com/no-ads-malware-typo";import Qr from"node:fs";import $l from"node:path";import{execSync as Kl}from"node:child_process";var Po=`# ==============================================================================
14
14
  # DNS Worker - Serverfull Mode Environment Configuration (.env.serverfull)
15
15
  # ==============================================================================
16
16
  # You can edit this file directly, or copy it to .env:
@@ -201,29 +201,29 @@ PRESET_ECH_FRONTING_DOMAINS='["cloudflare-ech.com","crypto.cloudflare.com","one.
201
201
 
202
202
  # Substitute Region IPs mapping (JSON string) / \u8F85\u52A9\u57DF\u540D\u5404\u533A\u57DF\u89E3\u6790 IP \u6620\u5C04 (JSON \u5B57\u7B26\u4E32)
203
203
  IP_REGION_CN='[{"ip":"198.41.222.102","area":"SG"},{"ip":"173.245.59.246","area":"SG"},{"ip":"104.18.47.174","area":"HK"},{"ip":"104.19.50.3","area":"HK"}]'
204
- `;function lt(t,e=!1){let n=Ll.dirname(t);if(Kr.existsSync(n)||Kr.mkdirSync(n,{recursive:!0,mode:493}),Kr.existsSync(t)&&!e)return{created:!1,path:t};if(Kr.writeFileSync(t,So,{encoding:"utf-8",mode:420}),process.platform==="linux"&&process.env.SUDO_USER&&process.env.SUDO_USER!=="root"){let r=process.env.SUDO_USER.trim();if(/^[a-zA-Z0-9._-]+$/.test(r))try{Ol(`chown ${r} "${t}"`)}catch{}}return{created:!0,path:t}}function Nt(){try{let t=G.dirname(Il(import.meta.url));if(ne.existsSync(G.join(t,"migrations"))&&ne.existsSync(G.join(t,"static")))return t;let e=G.resolve(t,"..");if(ne.existsSync(G.join(e,"migrations"))&&ne.existsSync(G.join(e,"static")))return e;let n=G.resolve(t,"../..");if(ne.existsSync(G.join(n,"migrations"))&&ne.existsSync(G.join(n,"static")))return n}catch{}return process.cwd()}function jr(){try{let t=G.join(Nt(),"package.json");if(ne.existsSync(t)){let e=JSON.parse(ne.readFileSync(t,"utf-8"));if(e.version)return e.version}}catch{}return"1.0.0"}function dt(){if(process.platform==="win32"){let t=process.env.ProgramData||G.join(process.env.SystemDrive||"C:","ProgramData");return G.join(t,"DNS-Worker")}if(process.platform==="linux"){let t="/var/lib/dns-worker";if(typeof process.getuid=="function"&&process.getuid()===0)return t;if(ne.existsSync(t))try{return ne.accessSync(t,ne.constants.W_OK),t}catch{}let e=process.env.HOME||"/tmp",n=process.env.XDG_DATA_HOME||G.join(e,".local","share");return G.join(n,"dns-worker")}if(process.platform==="darwin"){let t=process.env.HOME||"/tmp";return G.join(t,"Library","Application Support","DNS-Worker")}return G.join(process.cwd(),"data")}function Vr(){return G.join(dt(),"dns_worker.sqlite")}function cn(){if(process.platform==="win32"){let t=process.env.ProgramData||G.join(process.env.SystemDrive||"C:","ProgramData");return G.join(t,"DNS-Worker")}if(process.platform==="linux"){let t="/etc/dns-worker";if(typeof process.getuid=="function"&&process.getuid()===0)return t;if(ne.existsSync(t))try{return ne.accessSync(t,ne.constants.W_OK),t}catch{}let e=process.env.HOME||"/tmp",n=process.env.XDG_CONFIG_HOME||G.join(e,".config");return G.join(n,"dns-worker")}if(process.platform==="darwin"){let t=process.env.HOME||"/tmp";return G.join(t,"Library","Application Support","DNS-Worker")}return G.join(process.cwd(),"config")}function ut(){return G.join(cn(),".env")}function Jr(t=!0){let e=dt(),n=cn(),r=ut();try{ne.existsSync(e)||ne.mkdirSync(e,{recursive:!0,mode:493})}catch{}try{ne.existsSync(n)||ne.mkdirSync(n,{recursive:!0,mode:493})}catch{}if(t)try{lt(r,!1)}catch{}if(process.platform==="linux"&&process.env.SUDO_USER&&process.env.SUDO_USER!=="root"){let s=process.env.SUDO_USER.trim();if(/^[a-zA-Z0-9._-]+$/.test(s)){try{Bi(`chown -R ${s} "${e}"`)}catch{}try{Bi(`chown -R ${s} "${n}"`)}catch{}}}return{dataDir:e,configDir:n,configFile:r}}var Wr=[];function Gr(){return Wr}function Ul(t){try{if(ne.existsSync(t)){let n=ne.readFileSync(t,"utf-8").split(`
205
- `);for(let r of n){let s=r.trim();if(!s||s.startsWith("#"))continue;let o=s.indexOf("=");if(o!==-1){let i=s.slice(0,o).trim(),c=s.slice(o+1).trim();(c.startsWith('"')&&c.endsWith('"')||c.startsWith("'")&&c.endsWith("'"))&&(c=c.slice(1,-1)),i in process.env||(process.env[i]=c)}}return!0}}catch(e){console.warn(`[Config] Failed to read ${t}:`,e)}return!1}function Ro(t=process.cwd()){Jr(!0),Wr.length=0;let e=[G.join(t,".dev.vars"),G.join(t,".env"),G.join(t,".env.serverfull"),ut(),process.platform==="linux"?"/etc/dns-worker/.env":null,process.platform==="linux"?"/etc/default/dns-worker":null,process.platform==="linux"?G.join(dt(),".env"):null,G.join(Nt(),".env.serverfull")].filter(r=>!!r),n=Array.from(new Set(e));for(let r of n)Ul(r)&&Wr.push(r);return Wr}function Ml(t=dt()){if(process.env.JWT_SECRET&&process.env.JWT_SECRET.trim().length>0)return process.env.JWT_SECRET.trim();let e=G.join(t,".jwt_secret");try{if(ne.existsSync(e)){let r=ne.readFileSync(e,"utf-8").trim();if(r.length>=16)return r}}catch{}let n=Buffer.from(Nl.randomBytes(32)).toString("hex");try{ne.existsSync(t)||ne.mkdirSync(t,{recursive:!0}),ne.writeFileSync(e,n,{encoding:"utf-8",mode:384})}catch{}return n}function Yr(t){Jr(),Ro();let e=Nt(),n=(process.env.SERVERFULL_TLS_KEY_PATH||process.env.SERFULL_TLS_KEY_PATH||process.env.TLS_KEY_PATH||process.env.SSL_KEY_PATH||process.env.SERVERFULL_TLS_KEY||process.env.TLS_KEY||process.env.SSL_KEY||process.env.KEY_PATH||process.env.KEY_FILE||"").trim(),r=(process.env.SERVERFULL_TLS_CERT_PATH||process.env.SERVERFULL_TLS_PUB_PATH||process.env.SERVERFULL_TLS_PUBLIC_KEY_PATH||process.env.SERFULL_TLS_CERT_PATH||process.env.SERFULL_TLS_PUB_PATH||process.env.TLS_CERT_PATH||process.env.SSL_CERT_PATH||process.env.SERVERFULL_TLS_CERT||process.env.TLS_CERT||process.env.SSL_CERT||process.env.CERT_PATH||process.env.CERT_FILE||"").trim(),s=parseInt(t?.["dns-port"]||process.env.SERVERFULL_UDP_PORT||process.env.DNS_PORT||"53",10),o=parseInt(t?.["dot-port"]||process.env.SERVERFULL_DOT_PORT||process.env.DOT_PORT||"853",10),i=(t?.["dot-domain"]||process.env.SERVERFULL_DOT_DOMAIN||process.env.DOT_DOMAIN||"").trim(),c=parseInt(t?.["http-port"]||t?.port||process.env.SERVERFULL_HTTP_PORT||process.env.HTTP_PORT||process.env.PORT||"10080",10),a=parseInt(t?.["https-port"]||process.env.SERVERFULL_HTTPS_PORT||process.env.HTTPS_PORT||"10443",10),l=t?.host||process.env.SERVERFULL_HOST||process.env.SERVERFULL_BIND_ADDRESS||"0.0.0.0",d=Vr(),u=t?.db||process.env.SERVERFULL_DB_PATH||process.env.DB_PATH||d,f=t?.["default-profile"]||process.env.SERVERFULL_DEFAULT_PROFILE_KEY||process.env.DEFAULT_PROFILE_KEY||"",p=!!(t?.["disable-udp"]||process.env.SERVERFULL_DISABLE_UDP==="true"),m=!!(t?.["disable-dot"]||process.env.SERVERFULL_DISABLE_DOT==="true"),h=!!(t?.["disable-https"]||process.env.SERVERFULL_DISABLE_HTTPS==="true"),g=t?.["ech-enabled"]!==void 0?!!t["ech-enabled"]:process.env.SERVERFULL_ECH_ENABLED===void 0||process.env.SERVERFULL_ECH_ENABLED==="true"||process.env.SERVERFULL_ECH_ENABLED==="1",w=(t?.["ech-config"]||process.env.SERVERFULL_ECH_CONFIG||"").trim(),b=(t?.["ech-fronting-domain"]||process.env.SERVERFULL_ECH_FRONTING_DOMAIN||"cloudflare-ech.com").trim(),y={tlsKeyPath:n,tlsCertPath:r,udpPort:s,dotPort:o,dotDomain:i,httpPort:c,httpsPort:a,host:l,dbPath:u,defaultProfileKey:f,disableUdp:p,disableDot:m,disableHttps:h,echEnabled:g,echConfig:w,echFrontingDomain:b,packageRoot:e},E={DB:null,ASSETS:null,JWT_SECRET:Ml(),FAIL_OPEN_UPSTREAM:process.env.FAIL_OPEN_UPSTREAM||Mi,SUBSTITUTE_DOMAIN:process.env.SUBSTITUTE_DOMAIN||Yn,PRESET_UPSTREAMS:process.env.PRESET_UPSTREAMS||JSON.stringify(Fr),PRESET_EXTERNAL_FILTERS:process.env.PRESET_EXTERNAL_FILTERS||JSON.stringify(Hr),IP_REGION_CN:process.env.IP_REGION_CN||JSON.stringify($r),MAX_ACCESS_POINTS_PER_PROFILE:process.env.MAX_ACCESS_POINTS_PER_PROFILE||100,MAX_PROFILES_PER_USER:process.env.MAX_PROFILES_PER_USER||10,DEFAULT_SESSION_EXPIRATION_MINUTES:process.env.DEFAULT_SESSION_EXPIRATION_MINUTES||1440,OPTIONAL_SESSION_EXPIRATION_DAYS:process.env.OPTIONAL_SESSION_EXPIRATION_DAYS||7,ACCESS_TOKEN_EXPIRATION_MINUTES:Number(process.env.ACCESS_TOKEN_EXPIRATION_MINUTES)||10,SESSION_GEO_DISTANCE_KM:process.env.SESSION_GEO_DISTANCE_KM||50,PREAUTH_TTL_SECONDS:process.env.PREAUTH_TTL_SECONDS||300,BLOOM_MEM_TTL:process.env.BLOOM_MEM_TTL||6e5,SYNC_TIMEOUT_MS:process.env.SYNC_TIMEOUT_MS||3e4,INACTIVITY_THRESHOLD_DAYS:process.env.INACTIVITY_THRESHOLD_DAYS||180,THROTTLE_ACTIVE_SEC:process.env.THROTTLE_ACTIVE_SEC||3600,SYNC_PROFILE_INTERVAL_SEC:process.env.SYNC_PROFILE_INTERVAL_SEC||86400,BLOOM_FALSE_POSITIVE_RATE:process.env.BLOOM_FALSE_POSITIVE_RATE||1e-4,MAX_SYNC_DOMAINS:process.env.MAX_SYNC_DOMAINS||1e6,MAX_LIST_DOMAINS:process.env.MAX_LIST_DOMAINS||5e5,MAX_LOG_RETENTION_DAYS:process.env.MAX_LOG_RETENTION_DAYS||30,DEFAULT_LOG_RETENTION_DAYS:process.env.DEFAULT_LOG_RETENTION_DAYS||7,NORMAL_USER_MAX_LOG_RETENTION_DAYS:process.env.NORMAL_USER_MAX_LOG_RETENTION_DAYS||7,NORMAL_USER_DEFAULT_LOG_RETENTION_DAYS:process.env.NORMAL_USER_DEFAULT_LOG_RETENTION_DAYS||1,MAX_LOGS_PER_PROFILE:process.env.MAX_LOGS_PER_PROFILE||5e5,SERVERFULL_DEFAULT_PROFILE_KEY:f,SERVERFULL_DOT_DOMAIN:i,DOT_DOMAIN:i,SERVERFULL_HTTPS_PORT:a,SERVERFULL_DOT_PORT:o,SERVERFULL_HTTP_PORT:c,SERVERFULL_ECH_ENABLED:g?"true":"false",SERVERFULL_ECH_CONFIG:w,SERVERFULL_ECH_FRONTING_DOMAIN:b,...process.env};return{config:y,env:E}}import pt from"node:fs";import ln from"node:path";import{DatabaseSync as Bl}from"node:sqlite";var To=class{constructor(e,n){this.db=e;this.sql=n}db;sql;params=[];bind(...e){return this.params=e.map(n=>typeof n=="boolean"?n?1:0:n),this}async first(e){try{let r=this.db.prepare(this.sql).get(...this.params);return r?e?r[e]??null:r:null}catch(n){throw console.warn(`[SQLite D1] Query error in first(): ${n.message}
206
- SQL: ${this.sql}`),n}}async all(){try{let n=this.db.prepare(this.sql).all(...this.params);return{results:n,success:!0,meta:{duration:0,size_after:0,rows_read:n.length,rows_written:0,last_row_id:0,changed_db:!1,changes:0}}}catch(e){throw console.warn(`[SQLite D1] Query error in all(): ${e.message}
207
- SQL: ${this.sql}`),e}}async run(){try{let n=this.db.prepare(this.sql).run(...this.params),r=Number(n.changes),s=Number(n.lastInsertRowid);return{results:[],success:!0,meta:{duration:0,size_after:0,rows_read:0,rows_written:r,last_row_id:s,changed_db:r>0,changes:r}}}catch(e){throw console.warn(`[SQLite D1] Query error in run(): ${e.message}
208
- SQL: ${this.sql}`),e}}async raw(e){try{let r=this.db.prepare(this.sql).all(...this.params),s=r.map(o=>Object.values(o));return e?.columnNames&&r.length>0?[Object.keys(r[0]),...s]:s}catch(n){throw console.warn(`[SQLite D1] Query error in raw(): ${n.message}
209
- SQL: ${this.sql}`),n}}},xo=class{constructor(e){this.rawDb=e}rawDb;prepare(e){return new To(this.rawDb,e)}async batch(e){this.rawDb.exec("BEGIN IMMEDIATE");try{let n=[];for(let r of e){let s=await r.run();n.push(s)}return this.rawDb.exec("COMMIT"),n}catch(n){throw this.rawDb.exec("ROLLBACK"),n}}async exec(e){return this.rawDb.exec(e),{count:0,duration:0}}async dump(){throw new Error("dump() is not supported in NodeD1Database")}withSession(e){return Object.assign(this,{getBookmark:()=>null})}};function Fl(t,e){if(t.exec(`
204
+ `;function Me(n,e=!1){let t=$l.dirname(n);if(Qr.existsSync(t)||Qr.mkdirSync(t,{recursive:!0,mode:493}),Qr.existsSync(n)&&!e)return{created:!1,path:n};if(Qr.writeFileSync(n,Po,{encoding:"utf-8",mode:420}),process.platform==="linux"&&process.env.SUDO_USER&&process.env.SUDO_USER!=="root"){let r=process.env.SUDO_USER.trim();if(/^[a-zA-Z0-9._-]+$/.test(r))try{Kl(`chown ${r} "${n}"`)}catch{}}return{created:!0,path:n}}function Mt(){try{let n=J.dirname(jl(import.meta.url));if(ne.existsSync(J.join(n,"migrations"))&&ne.existsSync(J.join(n,"static")))return n;let e=J.resolve(n,"..");if(ne.existsSync(J.join(e,"migrations"))&&ne.existsSync(J.join(e,"static")))return e;let t=J.resolve(n,"../..");if(ne.existsSync(J.join(t,"migrations"))&&ne.existsSync(J.join(t,"static")))return t}catch{}return process.cwd()}function qr(){try{let n=J.join(Mt(),"package.json");if(ne.existsSync(n)){let e=JSON.parse(ne.readFileSync(n,"utf-8"));if(e.version)return e.version}}catch{}return"1.0.0"}function ht(){if(process.platform==="win32"){let n=process.env.ProgramData||J.join(process.env.SystemDrive||"C:","ProgramData");return J.join(n,"DNS-Worker")}if(process.platform==="linux"){let n="/var/lib/dns-worker";if(typeof process.getuid=="function"&&process.getuid()===0)return n;if(ne.existsSync(n))try{return ne.accessSync(n,ne.constants.W_OK),n}catch{}let e=process.env.HOME||"/tmp",t=process.env.XDG_DATA_HOME||J.join(e,".local","share");return J.join(t,"dns-worker")}if(process.platform==="darwin"){let n=process.env.HOME||"/tmp";return J.join(n,"Library","Application Support","DNS-Worker")}return J.join(process.cwd(),"data")}function fn(){return J.join(ht(),"dns_worker.sqlite")}function mn(){if(process.platform==="win32"){let n=process.env.ProgramData||J.join(process.env.SystemDrive||"C:","ProgramData");return J.join(n,"DNS-Worker")}if(process.platform==="linux"){let n="/etc/dns-worker";if(typeof process.getuid=="function"&&process.getuid()===0)return n;if(ne.existsSync(n))try{return ne.accessSync(n,ne.constants.W_OK),n}catch{}let e=process.env.HOME||"/tmp",t=process.env.XDG_CONFIG_HOME||J.join(e,".config");return J.join(t,"dns-worker")}if(process.platform==="darwin"){let n=process.env.HOME||"/tmp";return J.join(n,"Library","Application Support","DNS-Worker")}return J.join(process.cwd(),"config")}function Xe(){return J.join(mn(),".env")}function es(n=!0){let e=ht(),t=mn(),r=Xe();try{ne.existsSync(e)||ne.mkdirSync(e,{recursive:!0,mode:493})}catch{}try{ne.existsSync(t)||ne.mkdirSync(t,{recursive:!0,mode:493})}catch{}if(n)try{Me(r,!1)}catch{}if(process.platform==="linux"&&process.env.SUDO_USER&&process.env.SUDO_USER!=="root"){let s=process.env.SUDO_USER.trim();if(/^[a-zA-Z0-9._-]+$/.test(s)){try{Vi(`chown -R ${s} "${e}"`)}catch{}try{Vi(`chown -R ${s} "${t}"`)}catch{}}}return{dataDir:e,configDir:t,configFile:r}}var Zr=[];function ts(){return Zr}function Vl(n){try{if(ne.existsSync(n)){let t=ne.readFileSync(n,"utf-8").split(`
205
+ `);for(let r of t){let s=r.trim();if(!s||s.startsWith("#"))continue;let o=s.indexOf("=");if(o!==-1){let i=s.slice(0,o).trim(),c=s.slice(o+1).trim();(c.startsWith('"')&&c.endsWith('"')||c.startsWith("'")&&c.endsWith("'"))&&(c=c.slice(1,-1)),i in process.env||(process.env[i]=c)}}return!0}}catch(e){console.warn(`[Config] Failed to read ${n}:`,e)}return!1}function Co(n=process.cwd()){es(!0),Zr.length=0;let e=[J.join(n,".dev.vars"),J.join(n,".env"),J.join(n,".env.serverfull"),Xe(),process.platform==="linux"?"/etc/dns-worker/.env":null,process.platform==="linux"?"/etc/default/dns-worker":null,process.platform==="linux"?J.join(ht(),".env"):null,J.join(Mt(),".env.serverfull")].filter(r=>!!r),t=Array.from(new Set(e));for(let r of t)Vl(r)&&Zr.push(r);return Zr}function Gl(n=ht()){if(process.env.JWT_SECRET&&process.env.JWT_SECRET.trim().length>0)return process.env.JWT_SECRET.trim();let e=J.join(n,".jwt_secret");try{if(ne.existsSync(e)){let r=ne.readFileSync(e,"utf-8").trim();if(r.length>=16)return r}}catch{}let t=Buffer.from(Wl.randomBytes(32)).toString("hex");try{ne.existsSync(n)||ne.mkdirSync(n,{recursive:!0}),ne.writeFileSync(e,t,{encoding:"utf-8",mode:384})}catch{}return t}function ns(n){es(),Co();let e=Mt(),t=(process.env.SERVERFULL_TLS_KEY_PATH||process.env.SERFULL_TLS_KEY_PATH||process.env.TLS_KEY_PATH||process.env.SSL_KEY_PATH||process.env.SERVERFULL_TLS_KEY||process.env.TLS_KEY||process.env.SSL_KEY||process.env.KEY_PATH||process.env.KEY_FILE||"").trim(),r=(process.env.SERVERFULL_TLS_CERT_PATH||process.env.SERVERFULL_TLS_PUB_PATH||process.env.SERVERFULL_TLS_PUBLIC_KEY_PATH||process.env.SERFULL_TLS_CERT_PATH||process.env.SERFULL_TLS_PUB_PATH||process.env.TLS_CERT_PATH||process.env.SSL_CERT_PATH||process.env.SERVERFULL_TLS_CERT||process.env.TLS_CERT||process.env.SSL_CERT||process.env.CERT_PATH||process.env.CERT_FILE||"").trim(),s=parseInt(n?.["dns-port"]||process.env.SERVERFULL_UDP_PORT||process.env.DNS_PORT||"53",10),o=parseInt(n?.["dot-port"]||process.env.SERVERFULL_DOT_PORT||process.env.DOT_PORT||"853",10),i=(n?.["dot-domain"]||process.env.SERVERFULL_DOT_DOMAIN||process.env.DOT_DOMAIN||"").trim(),c=parseInt(n?.["http-port"]||n?.port||process.env.SERVERFULL_HTTP_PORT||process.env.HTTP_PORT||process.env.PORT||"10080",10),a=parseInt(n?.["https-port"]||process.env.SERVERFULL_HTTPS_PORT||process.env.HTTPS_PORT||"10443",10),l=n?.host||process.env.SERVERFULL_HOST||process.env.SERVERFULL_BIND_ADDRESS||"0.0.0.0",d=fn(),u=n?.db||process.env.SERVERFULL_DB_PATH||process.env.DB_PATH||d,f=n?.["default-profile"]||process.env.SERVERFULL_DEFAULT_PROFILE_KEY||process.env.DEFAULT_PROFILE_KEY||"",p=!!(n?.["disable-udp"]||process.env.SERVERFULL_DISABLE_UDP==="true"),m=!!(n?.["disable-dot"]||process.env.SERVERFULL_DISABLE_DOT==="true"),h=!!(n?.["disable-https"]||process.env.SERVERFULL_DISABLE_HTTPS==="true"),g=n?.["ech-enabled"]!==void 0?!!n["ech-enabled"]:process.env.SERVERFULL_ECH_ENABLED===void 0||process.env.SERVERFULL_ECH_ENABLED==="true"||process.env.SERVERFULL_ECH_ENABLED==="1",b=(n?.["ech-config"]||process.env.SERVERFULL_ECH_CONFIG||"").trim(),w=(n?.["ech-fronting-domain"]||process.env.SERVERFULL_ECH_FRONTING_DOMAIN||"cloudflare-ech.com").trim(),y={tlsKeyPath:t,tlsCertPath:r,udpPort:s,dotPort:o,dotDomain:i,httpPort:c,httpsPort:a,host:l,dbPath:u,defaultProfileKey:f,disableUdp:p,disableDot:m,disableHttps:h,echEnabled:g,echConfig:b,echFrontingDomain:w,packageRoot:e},E={DB:null,ASSETS:null,JWT_SECRET:Gl(),FAIL_OPEN_UPSTREAM:process.env.FAIL_OPEN_UPSTREAM||ji,SUBSTITUTE_DOMAIN:process.env.SUBSTITUTE_DOMAIN||tr,PRESET_UPSTREAMS:process.env.PRESET_UPSTREAMS||JSON.stringify(Yr),PRESET_EXTERNAL_FILTERS:process.env.PRESET_EXTERNAL_FILTERS||JSON.stringify(zr),IP_REGION_CN:process.env.IP_REGION_CN||JSON.stringify(Xr),MAX_ACCESS_POINTS_PER_PROFILE:process.env.MAX_ACCESS_POINTS_PER_PROFILE||100,MAX_PROFILES_PER_USER:process.env.MAX_PROFILES_PER_USER||10,DEFAULT_SESSION_EXPIRATION_MINUTES:process.env.DEFAULT_SESSION_EXPIRATION_MINUTES||1440,OPTIONAL_SESSION_EXPIRATION_DAYS:process.env.OPTIONAL_SESSION_EXPIRATION_DAYS||7,ACCESS_TOKEN_EXPIRATION_MINUTES:Number(process.env.ACCESS_TOKEN_EXPIRATION_MINUTES)||10,SESSION_GEO_DISTANCE_KM:process.env.SESSION_GEO_DISTANCE_KM||50,PREAUTH_TTL_SECONDS:process.env.PREAUTH_TTL_SECONDS||300,BLOOM_MEM_TTL:process.env.BLOOM_MEM_TTL||6e5,SYNC_TIMEOUT_MS:process.env.SYNC_TIMEOUT_MS||3e4,INACTIVITY_THRESHOLD_DAYS:process.env.INACTIVITY_THRESHOLD_DAYS||180,THROTTLE_ACTIVE_SEC:process.env.THROTTLE_ACTIVE_SEC||3600,SYNC_PROFILE_INTERVAL_SEC:process.env.SYNC_PROFILE_INTERVAL_SEC||86400,BLOOM_FALSE_POSITIVE_RATE:process.env.BLOOM_FALSE_POSITIVE_RATE||1e-4,MAX_SYNC_DOMAINS:process.env.MAX_SYNC_DOMAINS||1e6,MAX_LIST_DOMAINS:process.env.MAX_LIST_DOMAINS||5e5,MAX_LOG_RETENTION_DAYS:process.env.MAX_LOG_RETENTION_DAYS||30,DEFAULT_LOG_RETENTION_DAYS:process.env.DEFAULT_LOG_RETENTION_DAYS||7,NORMAL_USER_MAX_LOG_RETENTION_DAYS:process.env.NORMAL_USER_MAX_LOG_RETENTION_DAYS||7,NORMAL_USER_DEFAULT_LOG_RETENTION_DAYS:process.env.NORMAL_USER_DEFAULT_LOG_RETENTION_DAYS||1,MAX_LOGS_PER_PROFILE:process.env.MAX_LOGS_PER_PROFILE||5e5,SERVERFULL_DEFAULT_PROFILE_KEY:f,SERVERFULL_DB_PATH:u,SERVERFULL_DOT_DOMAIN:i,DOT_DOMAIN:i,SERVERFULL_HTTPS_PORT:a,SERVERFULL_DOT_PORT:o,SERVERFULL_HTTP_PORT:c,SERVERFULL_ECH_ENABLED:g?"true":"false",SERVERFULL_ECH_CONFIG:b,SERVERFULL_ECH_FRONTING_DOMAIN:w,...process.env};return{config:y,env:E}}import Re from"node:fs";import hn from"node:path";import{DatabaseSync as Jl}from"node:sqlite";var Do=class{constructor(e,t){this.db=e;this.sql=t}db;sql;params=[];bind(...e){return this.params=e.map(t=>typeof t=="boolean"?t?1:0:t),this}async first(e){try{let r=this.db.prepare(this.sql).get(...this.params);return r?e?r[e]??null:r:null}catch(t){throw console.warn(`[SQLite D1] Query error in first(): ${t.message}
206
+ SQL: ${this.sql}`),t}}async all(){try{let t=this.db.prepare(this.sql).all(...this.params);return{results:t,success:!0,meta:{duration:0,size_after:0,rows_read:t.length,rows_written:0,last_row_id:0,changed_db:!1,changes:0}}}catch(e){throw console.warn(`[SQLite D1] Query error in all(): ${e.message}
207
+ SQL: ${this.sql}`),e}}async run(){try{let t=this.db.prepare(this.sql).run(...this.params),r=Number(t.changes),s=Number(t.lastInsertRowid);return{results:[],success:!0,meta:{duration:0,size_after:0,rows_read:0,rows_written:r,last_row_id:s,changed_db:r>0,changes:r}}}catch(e){throw console.warn(`[SQLite D1] Query error in run(): ${e.message}
208
+ SQL: ${this.sql}`),e}}async raw(e){try{let r=this.db.prepare(this.sql).all(...this.params),s=r.map(o=>Object.values(o));return e?.columnNames&&r.length>0?[Object.keys(r[0]),...s]:s}catch(t){throw console.warn(`[SQLite D1] Query error in raw(): ${t.message}
209
+ SQL: ${this.sql}`),t}}},ko=class{constructor(e,t){this.rawDb=e;this.dbPath=t}rawDb;dbPath;getDatabaseSize(){let e=0;if(this.dbPath&&this.dbPath!==":memory:")try{Re.existsSync(this.dbPath)&&(e+=Re.statSync(this.dbPath).size);let t=`${this.dbPath}-wal`;Re.existsSync(t)&&(e+=Re.statSync(t).size);let r=`${this.dbPath}-shm`;Re.existsSync(r)&&(e+=Re.statSync(r).size)}catch{}if(e===0)try{let t=this.rawDb.prepare("PRAGMA page_count").get()?.page_count??0,r=this.rawDb.prepare("PRAGMA freelist_count").get()?.freelist_count??0,s=this.rawDb.prepare("PRAGMA page_size").get()?.page_size??4096;e=Math.max(0,(Number(t)-Number(r))*Number(s))}catch{}return e}vacuum(){try{this.rawDb.exec("VACUUM;"),this.rawDb.exec("PRAGMA wal_checkpoint(TRUNCATE);")}catch(e){console.warn("[SQLite D1] VACUUM / checkpoint warning:",e)}}prepare(e){return new Do(this.rawDb,e)}async batch(e){this.rawDb.exec("BEGIN IMMEDIATE");try{let t=[];for(let r of e){let s=await r.run();t.push(s)}return this.rawDb.exec("COMMIT"),t}catch(t){throw this.rawDb.exec("ROLLBACK"),t}}async exec(e){return this.rawDb.exec(e),{count:0,duration:0}}async dump(){throw new Error("dump() is not supported in NodeD1Database")}close(){try{this.rawDb.close()}catch{}}withSession(e){return Object.assign(this,{getBookmark:()=>null})}};function Yl(n,e){if(n.exec(`
210
210
  CREATE TABLE IF NOT EXISTS _cf_d1_migrations (
211
211
  id INTEGER PRIMARY KEY AUTOINCREMENT,
212
212
  name TEXT UNIQUE NOT NULL,
213
213
  applied_at INTEGER NOT NULL
214
214
  );
215
- `),!pt.existsSync(e)){console.warn(`[Migrations] Directory not found: ${e}`);return}let n=pt.readdirSync(e).filter(i=>i.endsWith(".sql")).sort(),r=t.prepare("SELECT name FROM _cf_d1_migrations WHERE name = ?"),s=t.prepare("INSERT INTO _cf_d1_migrations (name, applied_at) VALUES (?, ?)"),o=0;for(let i of n){if(r.get(i))continue;let a=ln.join(e,i),l=pt.readFileSync(a,"utf-8");console.log(`[Migrations] Applying ${i}...`),t.exec("BEGIN IMMEDIATE");try{t.exec(l),s.run(i,Math.floor(Date.now()/1e3)),t.exec("COMMIT"),o++}catch(d){throw t.exec("ROLLBACK"),console.error(`[Migrations] Failed to apply ${i}:`,d.message||d),d}}o>0?console.log(`[Migrations] Successfully applied ${o} migration(s).`):console.log("[Migrations] Database schema is up-to-date.")}function Fi(t,e=Nt()){let n=ln.dirname(t);if(pt.existsSync(n)||pt.mkdirSync(n,{recursive:!0}),!pt.existsSync(t)){let o=ln.join(process.cwd(),"data","dns_worker.sqlite");if(pt.existsSync(o)&&ln.resolve(o)!==ln.resolve(t))try{pt.copyFileSync(o,t),console.log(`[SQLite D1] Seamlessly migrated existing database from ${o} to ${t}`)}catch{}}console.log(`[SQLite D1] Connecting to database at: ${t}`);let r=new Bl(t);r.exec("PRAGMA journal_mode = WAL;"),r.exec("PRAGMA synchronous = NORMAL;"),r.exec("PRAGMA foreign_keys = ON;"),r.exec("PRAGMA temp_store = MEMORY;"),r.exec("PRAGMA cache_size = -64000;"),r.exec("PRAGMA mmap_size = 268435456;");let s=ln.join(e,"migrations");return Fl(r,s),new xo(r)}import Ru from"node:dgram";var Xr={1:"A",2:"NS",5:"CNAME",6:"SOA",12:"PTR",13:"HINFO",15:"MX",16:"TXT",17:"RP",24:"SIG",25:"KEY",28:"AAAA",29:"LOC",33:"SRV",35:"NAPTR",36:"KX",37:"CERT",39:"DNAME",41:"OPT",43:"DS",44:"SSHFP",45:"IPSECKEY",46:"RRSIG",47:"NSEC",48:"DNSKEY",49:"DHCID",50:"NSEC3",51:"NSEC3PARAM",52:"TLSA",53:"SMIMEA",59:"CDS",64:"SVCB",65:"HTTPS",99:"SPF",255:"ANY",256:"URI",257:"CAA",32769:"DLV"},Xn=Object.fromEntries(Object.entries(Xr).map(([t,e])=>[e,Number(t)]));function qe(t,e){let n="",r=e,s=!1,o=0,i=0,c=!1;for(;i<128&&!(r>=t.length);){let a=t[r];if(a===0){s||o++,c=!0;break}if((a&192)===192){if(r+1>=t.length)break;let l=(a&63)<<8|t[r+1];s||(o+=2,s=!0),r=l,i++;continue}if((a&192)!==0||(n.length>0&&(n+="."),r+1+a>t.length))break;for(let l=0;l<a;l++)n+=String.fromCharCode(t[r+1+l]);s||(o+=a+1),r+=a+1,i++}return c?{name:n,read:o}:{name:"",read:0}}function Ao(t){return Xr[t]||`TYPE${t}`}function dn(t){try{if(t.length<16)return null;let{name:e,read:n}=qe(t,12);if(n===0)return null;let r=12+n;if(r+4>t.length)return null;let s=t[r]<<8|t[r+1];return{name:e,type:Ao(s),raw:t}}catch(e){return console.error("DNS Parse Error:",e),null}}async function vo(t){try{let e;if(t.method==="GET"){let r=new URL(t.url).searchParams.get("dns");if(!r)return null;let s=r.replace(/-/g,"+").replace(/_/g,"/");for(;s.length%4;)s+="=";let o=atob(s);e=new Uint8Array(o.length);for(let i=0;i<o.length;i++)e[i]=o.charCodeAt(i)}else if(t.method==="POST"){let n=await t.arrayBuffer();e=new Uint8Array(n)}else return null;return dn(e)}catch(e){return console.error("DNS Parse Error:",e),null}}function Ce(t){if(t.length<12)return[];let e=t[6]<<8|t[7];if(e===0)return[];let n=[],r=12,s=t[4]<<8|t[5];for(let o=0;o<s;o++){if(r>=t.length)return[];let{read:i}=qe(t,r);if(i===0)return[];if(r+=i+4,r>t.length)return[]}for(let o=0;o<e&&!(r>=t.length);o++){let{name:i,read:c}=qe(t,r);if(c===0||(r+=c,r+10>t.length))break;let a=t[r]<<8|t[r+1],l=t[r+4]<<24|t[r+5]<<16|t[r+6]<<8|t[r+7],d=t[r+8]<<8|t[r+9];if(r+=10,r+d>t.length)break;let u=Ao(a),f="";if(u==="A"&&d===4)f=`${t[r]}.${t[r+1]}.${t[r+2]}.${t[r+3]}`;else if(u==="AAAA"&&d===16){let p=[];for(let b=0;b<16;b+=2)p.push((t[r+b]<<8|t[r+b+1]).toString(16));let m=-1,h=0,g=-1,w=0;for(let b=0;b<p.length;b++)p[b]==="0"?(g===-1&&(g=b),w++):(w>h&&(m=g,h=w),g=-1,w=0);if(w>h&&(m=g,h=w),h>1){let b=m===0||m+h===p.length?":":"";p.splice(m,h,b)}f=p.join(":").replace(":::","::")}else if(u==="CNAME"||u==="NS"||u==="PTR")f=qe(t,r).name;else if(u==="TXT"){let p=r,m=[],h=r+d;for(;p<h;){let g=t[p];if(p+1+g>h)break;m.push(String.fromCharCode(...t.slice(p+1,p+1+g))),p+=g+1}f=m.join("")}else if(u==="HTTPS"||u==="SVCB")if(d>=2){let p=t[r]<<8|t[r+1],{name:m,read:h}=qe(t,r+2),g=r+2+h,w=r+d,b=[];for(;g+4<=w;){let y=t[g]<<8|t[g+1],E=t[g+2]<<8|t[g+3];if(g+=4,g+E>w)break;if(y===1){let _=g,S=g+E,x=[];for(;_<S;){let T=t[_];if(_+1+T>S)break;let v="";for(let C=0;C<T;C++)v+=String.fromCharCode(t[_+1+C]);x.push(v),_+=T+1}b.push(`alpn=${x.join(",")}`)}else if(y===4){let _=[];for(let S=0;S+4<=E;S+=4)_.push(`${t[g+S]}.${t[g+S+1]}.${t[g+S+2]}.${t[g+S+3]}`);b.push(`ipv4hint=${_.join(",")}`)}else if(y===5){let _="";for(let S=0;S<E;S++)_+=String.fromCharCode(t[g+S]);b.push(`ech=${btoa(_)}`)}else if(y===6){let _=[];for(let S=0;S+16<=E;S+=16){let x=[];for(let T=0;T<16;T+=2)x.push((t[g+S+T]<<8|t[g+S+T+1]).toString(16));_.push(x.join(":"))}b.push(`ipv6hint=${_.join(",")}`)}else b.push(`key${y}=[${E}B]`);g+=E}f=`${p} ${m||"."}${b.length>0?" "+b.join(" "):""}`.trim()}else f=`[Raw: ${d} bytes]`;else f=`[Raw: ${d} bytes]`;n.push({name:i,type:u,data:f,ttl:l}),r+=d}return n}var Hl=["cloudflare-ech.com","crypto.cloudflare.com","one.one.one.one","www.cloudflare.com","encryptedsni.com","cdnjs.com"];var It="cloudflare-ech.com",Hi="AEX+DQBBawAgACAUjjcEHSf2wlThCqPLx//d+m3qlWUe3nwuQaUVaVwQBgAEAAEAAQASY2xvdWRmbGFyZS1lY2guY29tAAA=";function $i(t){if(t?.PRESET_ECH_FRONTING_DOMAINS)try{let e=JSON.parse(t.PRESET_ECH_FRONTING_DOMAINS);if(Array.isArray(e)&&e.length>0)return e.map(n=>typeof n=="string"?n:n?.domain||"").filter(Boolean)}catch(e){console.warn("[ECH] Failed to parse PRESET_ECH_FRONTING_DOMAINS from env:",e)}return[...Hl]}function $l(t,e=It){try{let n=atob(t),r=new Uint8Array(n.length);for(let T=0;T<n.length;T++)r[T]=n.charCodeAt(T);if(r.length<16||(r[2]<<8|r[3])!==65037)return t;let o=r[6],i=r[7]<<8|r[8],c=r[9]<<8|r[10],a=11,l=a+c;if(l+4>r.length)return t;let d=r.slice(a,l),u=l,f=r[u]<<8|r[u+1];if(u+=2,u+f+2>r.length)return t;let p=r.slice(u,u+f);u+=f;let m=r[u++],h=r[u++];if(u+h+2>r.length)return t;u+=h;let g=r[u]<<8|r[u+1];if(u+=2,u+g>r.length)return t;let w=r.slice(u,u+g),b=(e||It).trim().toLowerCase(),y=new Uint8Array(b.length);for(let T=0;T<b.length;T++)y[T]=b.charCodeAt(T);let E=[o,i>>8&255,i&255,c>>8&255,c&255,...Array.from(d),f>>8&255,f&255,...Array.from(p),m,y.length,...Array.from(y),g>>8&255,g&255,...Array.from(w)],_=[254,13,E.length>>8&255,E.length&255,...E],S=[_.length>>8&255,_.length&255,..._],x="";for(let T=0;T<S.length;T++)x+=String.fromCharCode(S[T]);return btoa(x)}catch(n){return console.error("Failed to rebuild ECH with fronting domain:",n),t}}function zn(t=It,e){return $l(e||Hi,t)}function Kl(t){let e=new Uint8Array(16);if(t.includes("::")){let[n,r]=t.split("::"),s=n?n.split(":").filter(Boolean):[],o=r?r.split(":").filter(Boolean):[],i=0;for(let c of s){let a=parseInt(c,16);e[i++]=a>>8&255,e[i++]=a&255}i=16-o.length*2;for(let c of o){let a=parseInt(c,16);e[i++]=a>>8&255,e[i++]=a&255}}else{let n=t.split(":"),r=0;for(let s of n){let o=parseInt(s,16);e[r++]=o>>8&255,e[r++]=o&255}}return Array.from(e)}function Wl(t){let{priority:e=1,target:n=".",alpn:r=["h3","h2"],ipv4hints:s=[],ipv6hints:o=[],echBase64:i=null}=t,c=[];if(c.push(e>>8&255,e&255),!n||n===".")c.push(0);else{let a=n.split(".");for(let l of a){c.push(l.length);for(let d=0;d<l.length;d++)c.push(l.charCodeAt(d))}c.push(0)}if(r&&r.length>0){let a=[];for(let l of r){a.push(l.length);for(let d=0;d<l.length;d++)a.push(l.charCodeAt(d))}c.push(0,1),c.push(a.length>>8&255,a.length&255),c.push(...a)}if(s&&s.length>0){let a=[];for(let l of s){let d=l.split(".").map(Number);d.length===4&&d.every(u=>!isNaN(u)&&u>=0&&u<=255)&&a.push(...d)}a.length>0&&(c.push(0,4),c.push(a.length>>8&255,a.length&255),c.push(...a))}if(i)try{let a=atob(i),l=[];for(let d=0;d<a.length;d++)l.push(a.charCodeAt(d));c.push(0,5),c.push(l.length>>8&255,l.length&255),c.push(...l)}catch(a){console.error("Failed to decode base64 ech config:",a)}if(o&&o.length>0){let a=[];for(let l of o){let d=Kl(l);d&&d.length===16&&a.push(...d)}a.length>0&&(c.push(0,6),c.push(a.length>>8&255,a.length&255),c.push(...a))}return c}function Ki(t){let e=t.trim().split(/\s+/),n=parseInt(e[0],10)||1,r=e[1]||".",s,o,i,c;for(let a=2;a<e.length;a++){let l=e[a],d=l.indexOf("=");if(d===-1)continue;let u=l.substring(0,d),f=l.substring(d+1);u==="alpn"?s=f.split(","):u==="ipv4hint"?o=f.split(","):u==="ech"?i=f:u==="ipv6hint"&&(c=f.split(","))}return Wl({priority:n,target:r,alpn:s,ipv4hints:o,ipv6hints:c,echBase64:i})}function zr(t){let e=t.split(".");if(e.length!==4)return null;let n=!1,r=e.reduce((s,o)=>{let i=Number(o);return(o===""||isNaN(i)||i<0||i>255||String(i)!==o)&&(n=!0),(s<<8)+i},0)>>>0;return n?null:r}function Qn(t){let e=t.trim().toLowerCase();e.startsWith("[")&&e.endsWith("]")&&(e=e.slice(1,-1));let n="";if(e.includes(".")){let c=e.lastIndexOf(":");if(c===-1)return null;n=e.substring(c+1),e=e.substring(0,c)+":0:0"}let r=e.split("::");if(r.length>2)return null;let s=e;if(r.length===2){let c=r[0]?r[0].split(":"):[],a=r[1]?r[1].split(":"):[];if(c.includes("")||a.includes(""))return null;let l=8-(c.length+a.length);if(l<0)return null;let d=new Array(l).fill("0").join(":");s=[...c,d,...a].filter(Boolean).join(":")}let o=s.split(":");if(o.length!==8)return null;if(n){let c=zr(n);if(c===null)return null;o[6]=(c>>>16).toString(16),o[7]=(c&65535).toString(16)}let i="";for(let c of o){if(c===""||c.length>4)return null;let a=parseInt(c,16);if(isNaN(a)||a<0||a>65535||c.toLowerCase()!==a.toString(16).padStart(c.length,"0"))return null;i+=c.padStart(4,"0")}try{return BigInt("0x"+i)}catch{return null}}function Zn(t){return zr(t)!==null}function Qr(t){return Qn(t)!==null}function Po(t){if(!t||typeof t!="string")return null;let e=t.lastIndexOf("/");if(e===-1)return null;let n=t.slice(0,e).trim(),r=t.slice(e+1).trim(),s=parseInt(r,10);if(isNaN(s)||s<0)return null;if(n.includes(":")){if(s>128)return null;let o=Qn(n);if(o===null)return null;let i=s===0?0n:~0n<<BigInt(128-s)&(1n<<128n)-1n;return{version:6,net:o&i,mask:i}}else{if(s>32)return null;let o=zr(n);if(o===null)return null;let i=s===0?0:-1<<32-s>>>0;return{version:4,net:(o&i)>>>0,mask:i}}}function Zr(t){let e=[],n=[];for(let r of t){let s=Po(r);s&&(s.version===4?e.push(s):n.push(s))}return r=>{if(!r)return!1;if(r.includes(":")){let s=Qn(r);return s===null?!1:n.some(o=>(s&o.mask)===o.net)}else{let s=zr(r);return s===null?!1:e.some(o=>(s&o.mask)>>>0===o.net)}}}var Co=[],Do=null;function ko(t){t&&t.length>0&&(Co=t,Do=Zr(Co))}function qr(){return Co}function es(t){return Do?Do(t):!1}var ft=new Map,qn=300*1e3,he=class{constructor(e){this.db=e}db;static clearMemoryCache(e){e?ft.delete(e):ft.clear()}async ensureTable(){try{await this.db.prepare("CREATE TABLE IF NOT EXISTS system_settings (key TEXT PRIMARY KEY, value TEXT NOT NULL, updated_at INTEGER NOT NULL)").run()}catch(e){console.warn("[SystemSettingsModel] Failed to ensure system_settings table:",e)}}async getAll(){try{let{results:e}=await this.db.prepare("SELECT key, value FROM system_settings").all(),n={},r=Date.now()+qn;for(let s of e)n[s.key]=s.value,ft.set(s.key,{value:s.value,expiresAt:r});return n}catch(e){if((e instanceof Error?e.message:String(e)).includes("no such table"))return await this.ensureTable(),{};throw e}}async get(e){let n=ft.get(e);if(n&&n.expiresAt>Date.now())return n.value;try{let r=await this.db.prepare("SELECT value FROM system_settings WHERE key = ?").bind(e).first(),s=r?r.value:null;return ft.set(e,{value:s,expiresAt:Date.now()+qn}),s}catch(r){if((r instanceof Error?r.message:String(r)).includes("no such table"))return await this.ensureTable(),null;throw r}}async set(e,n){let r=Math.floor(Date.now()/1e3);try{let s=await this.db.prepare("INSERT INTO system_settings (key, value, updated_at) VALUES (?, ?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value, updated_at=excluded.updated_at").bind(e,n,r).run();return s.success&&ft.set(e,{value:n,expiresAt:Date.now()+qn}),s.success}catch(s){if((s instanceof Error?s.message:String(s)).includes("no such table")){await this.ensureTable();let i=await this.db.prepare("INSERT INTO system_settings (key, value, updated_at) VALUES (?, ?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value, updated_at=excluded.updated_at").bind(e,n,r).run();return i.success&&ft.set(e,{value:n,expiresAt:Date.now()+qn}),i.success}throw s}}async setMany(e){let n=Math.floor(Date.now()/1e3),r=Object.entries(e).map(([o,i])=>this.db.prepare("INSERT INTO system_settings (key, value, updated_at) VALUES (?, ?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value, updated_at=excluded.updated_at").bind(o,String(i),n));try{r.length>0&&await this.db.batch(r)}catch(o){if((o instanceof Error?o.message:String(o)).includes("no such table"))await this.ensureTable(),r.length>0&&await this.db.batch(r);else throw o}let s=Date.now()+qn;for(let[o,i]of Object.entries(e))ft.set(o,{value:String(i),expiresAt:s});return!0}};var Wi=null,er=null;async function ji(t){qr().length>0||(!er&&t&&(er=(async()=>{try{let n=new he(t),[r,s]=await Promise.all([n.get("cf_proxy_cidrs"),n.get("cf_active_ech_config")]);if(s&&(Wi=s),r){let o=JSON.parse(r);if(Array.isArray(o)&&o.length>0){ko(o);return}}await Lo(t,!0)}catch(n){console.warn("[ECH] Could not load Cloudflare IP ranges from DB:",n)}finally{er=null}})()),er&&await er)}async function Lo(t,e=!1){let n=new he(t),r=Math.floor(Date.now()/1e3);if(!e){let s=await n.get("cf_proxy_cidrs_updated_at");if(s){let o=parseInt(s,10);if(!isNaN(o)&&r-o<86400)return{success:!0,updated:!1,count:qr().length}}}try{let[s,o,i]=await Promise.all([fetch("https://www.cloudflare.com/ips-v4",{headers:{"User-Agent":"Obex-DNS/1.0"},signal:AbortSignal.timeout(5e3)}),fetch("https://www.cloudflare.com/ips-v6",{headers:{"User-Agent":"Obex-DNS/1.0"},signal:AbortSignal.timeout(5e3)}),fetch("https://cloudflare-dns.com/dns-query?name=cloudflare-ech.com&type=HTTPS",{headers:{Accept:"application/dns-json"},signal:AbortSignal.timeout(5e3)}).catch(()=>null)]);if(!s.ok||!o.ok)throw new Error(`Failed to fetch Cloudflare IPs: v4 HTTP ${s.status}, v6 HTTP ${o.status}`);let c=await s.text(),a=await o.text(),d=[...c.split(`
215
+ `),!Re.existsSync(e)){console.warn(`[Migrations] Directory not found: ${e}`);return}let t=Re.readdirSync(e).filter(i=>i.endsWith(".sql")).sort(),r=n.prepare("SELECT name FROM _cf_d1_migrations WHERE name = ?"),s=n.prepare("INSERT INTO _cf_d1_migrations (name, applied_at) VALUES (?, ?)"),o=0;for(let i of t){if(r.get(i))continue;let a=hn.join(e,i),l=Re.readFileSync(a,"utf-8");console.log(`[Migrations] Applying ${i}...`),n.exec("BEGIN IMMEDIATE");try{n.exec(l),s.run(i,Math.floor(Date.now()/1e3)),n.exec("COMMIT"),o++}catch(d){throw n.exec("ROLLBACK"),console.error(`[Migrations] Failed to apply ${i}:`,d.message||d),d}}o>0?console.log(`[Migrations] Successfully applied ${o} migration(s).`):console.log("[Migrations] Database schema is up-to-date.")}function rs(n,e=Mt()){let t=hn.dirname(n);if(Re.existsSync(t)||Re.mkdirSync(t,{recursive:!0}),!Re.existsSync(n)){let o=hn.join(process.cwd(),"data","dns_worker.sqlite");if(Re.existsSync(o)&&hn.resolve(o)!==hn.resolve(n))try{Re.copyFileSync(o,n),console.log(`[SQLite D1] Seamlessly migrated existing database from ${o} to ${n}`)}catch{}}console.log(`[SQLite D1] Connecting to database at: ${n}`);let r=new Jl(n);r.exec("PRAGMA journal_mode = WAL;"),r.exec("PRAGMA synchronous = NORMAL;"),r.exec("PRAGMA foreign_keys = ON;"),r.exec("PRAGMA temp_store = MEMORY;"),r.exec("PRAGMA cache_size = -64000;"),r.exec("PRAGMA mmap_size = 268435456;");let s=hn.join(e,"migrations");return Yl(r,s),new ko(r,n)}import Lu from"node:dgram";var ss={1:"A",2:"NS",5:"CNAME",6:"SOA",12:"PTR",13:"HINFO",15:"MX",16:"TXT",17:"RP",24:"SIG",25:"KEY",28:"AAAA",29:"LOC",33:"SRV",35:"NAPTR",36:"KX",37:"CERT",39:"DNAME",41:"OPT",43:"DS",44:"SSHFP",45:"IPSECKEY",46:"RRSIG",47:"NSEC",48:"DNSKEY",49:"DHCID",50:"NSEC3",51:"NSEC3PARAM",52:"TLSA",53:"SMIMEA",59:"CDS",64:"SVCB",65:"HTTPS",99:"SPF",255:"ANY",256:"URI",257:"CAA",32769:"DLV"},nr=Object.fromEntries(Object.entries(ss).map(([n,e])=>[e,Number(n)]));function rt(n,e){let t="",r=e,s=!1,o=0,i=0,c=!1;for(;i<128&&!(r>=n.length);){let a=n[r];if(a===0){s||o++,c=!0;break}if((a&192)===192){if(r+1>=n.length)break;let l=(a&63)<<8|n[r+1];s||(o+=2,s=!0),r=l,i++;continue}if((a&192)!==0||(t.length>0&&(t+="."),r+1+a>n.length))break;for(let l=0;l<a;l++)t+=String.fromCharCode(n[r+1+l]);s||(o+=a+1),r+=a+1,i++}return c?{name:t,read:o}:{name:"",read:0}}function Lo(n){return ss[n]||`TYPE${n}`}function gn(n){try{if(n.length<16)return null;let{name:e,read:t}=rt(n,12);if(t===0)return null;let r=12+t;if(r+4>n.length)return null;let s=n[r]<<8|n[r+1];return{name:e,type:Lo(s),raw:n}}catch(e){return console.error("DNS Parse Error:",e),null}}async function Oo(n){try{let e;if(n.method==="GET"){let r=new URL(n.url).searchParams.get("dns");if(!r)return null;let s=r.replace(/-/g,"+").replace(/_/g,"/");for(;s.length%4;)s+="=";let o=atob(s);e=new Uint8Array(o.length);for(let i=0;i<o.length;i++)e[i]=o.charCodeAt(i)}else if(n.method==="POST"){let t=await n.arrayBuffer();e=new Uint8Array(t)}else return null;return gn(e)}catch(e){return console.error("DNS Parse Error:",e),null}}function ke(n){if(n.length<12)return[];let e=n[6]<<8|n[7];if(e===0)return[];let t=[],r=12,s=n[4]<<8|n[5];for(let o=0;o<s;o++){if(r>=n.length)return[];let{read:i}=rt(n,r);if(i===0)return[];if(r+=i+4,r>n.length)return[]}for(let o=0;o<e&&!(r>=n.length);o++){let{name:i,read:c}=rt(n,r);if(c===0||(r+=c,r+10>n.length))break;let a=n[r]<<8|n[r+1],l=n[r+4]<<24|n[r+5]<<16|n[r+6]<<8|n[r+7],d=n[r+8]<<8|n[r+9];if(r+=10,r+d>n.length)break;let u=Lo(a),f="";if(u==="A"&&d===4)f=`${n[r]}.${n[r+1]}.${n[r+2]}.${n[r+3]}`;else if(u==="AAAA"&&d===16){let p=[];for(let w=0;w<16;w+=2)p.push((n[r+w]<<8|n[r+w+1]).toString(16));let m=-1,h=0,g=-1,b=0;for(let w=0;w<p.length;w++)p[w]==="0"?(g===-1&&(g=w),b++):(b>h&&(m=g,h=b),g=-1,b=0);if(b>h&&(m=g,h=b),h>1){let w=m===0||m+h===p.length?":":"";p.splice(m,h,w)}f=p.join(":").replace(":::","::")}else if(u==="CNAME"||u==="NS"||u==="PTR")f=rt(n,r).name;else if(u==="TXT"){let p=r,m=[],h=r+d;for(;p<h;){let g=n[p];if(p+1+g>h)break;m.push(String.fromCharCode(...n.slice(p+1,p+1+g))),p+=g+1}f=m.join("")}else if(u==="HTTPS"||u==="SVCB")if(d>=2){let p=n[r]<<8|n[r+1],{name:m,read:h}=rt(n,r+2),g=r+2+h,b=r+d,w=[];for(;g+4<=b;){let y=n[g]<<8|n[g+1],E=n[g+2]<<8|n[g+3];if(g+=4,g+E>b)break;if(y===1){let _=g,S=g+E,x=[];for(;_<S;){let T=n[_];if(_+1+T>S)break;let v="";for(let C=0;C<T;C++)v+=String.fromCharCode(n[_+1+C]);x.push(v),_+=T+1}w.push(`alpn=${x.join(",")}`)}else if(y===4){let _=[];for(let S=0;S+4<=E;S+=4)_.push(`${n[g+S]}.${n[g+S+1]}.${n[g+S+2]}.${n[g+S+3]}`);w.push(`ipv4hint=${_.join(",")}`)}else if(y===5){let _="";for(let S=0;S<E;S++)_+=String.fromCharCode(n[g+S]);w.push(`ech=${btoa(_)}`)}else if(y===6){let _=[];for(let S=0;S+16<=E;S+=16){let x=[];for(let T=0;T<16;T+=2)x.push((n[g+S+T]<<8|n[g+S+T+1]).toString(16));_.push(x.join(":"))}w.push(`ipv6hint=${_.join(",")}`)}else w.push(`key${y}=[${E}B]`);g+=E}f=`${p} ${m||"."}${w.length>0?" "+w.join(" "):""}`.trim()}else f=`[Raw: ${d} bytes]`;else f=`[Raw: ${d} bytes]`;t.push({name:i,type:u,data:f,ttl:l}),r+=d}return t}var zl=["cloudflare-ech.com","crypto.cloudflare.com","one.one.one.one","www.cloudflare.com","encryptedsni.com","cdnjs.com"];var Bt="cloudflare-ech.com",Gi="AEX+DQBBawAgACAUjjcEHSf2wlThCqPLx//d+m3qlWUe3nwuQaUVaVwQBgAEAAEAAQASY2xvdWRmbGFyZS1lY2guY29tAAA=";function Ji(n){if(n?.PRESET_ECH_FRONTING_DOMAINS)try{let e=JSON.parse(n.PRESET_ECH_FRONTING_DOMAINS);if(Array.isArray(e)&&e.length>0)return e.map(t=>typeof t=="string"?t:t?.domain||"").filter(Boolean)}catch(e){console.warn("[ECH] Failed to parse PRESET_ECH_FRONTING_DOMAINS from env:",e)}return[...zl]}function Xl(n,e=Bt){try{let t=atob(n),r=new Uint8Array(t.length);for(let T=0;T<t.length;T++)r[T]=t.charCodeAt(T);if(r.length<16||(r[2]<<8|r[3])!==65037)return n;let o=r[6],i=r[7]<<8|r[8],c=r[9]<<8|r[10],a=11,l=a+c;if(l+4>r.length)return n;let d=r.slice(a,l),u=l,f=r[u]<<8|r[u+1];if(u+=2,u+f+2>r.length)return n;let p=r.slice(u,u+f);u+=f;let m=r[u++],h=r[u++];if(u+h+2>r.length)return n;u+=h;let g=r[u]<<8|r[u+1];if(u+=2,u+g>r.length)return n;let b=r.slice(u,u+g),w=(e||Bt).trim().toLowerCase(),y=new Uint8Array(w.length);for(let T=0;T<w.length;T++)y[T]=w.charCodeAt(T);let E=[o,i>>8&255,i&255,c>>8&255,c&255,...Array.from(d),f>>8&255,f&255,...Array.from(p),m,y.length,...Array.from(y),g>>8&255,g&255,...Array.from(b)],_=[254,13,E.length>>8&255,E.length&255,...E],S=[_.length>>8&255,_.length&255,..._],x="";for(let T=0;T<S.length;T++)x+=String.fromCharCode(S[T]);return btoa(x)}catch(t){return console.error("Failed to rebuild ECH with fronting domain:",t),n}}function rr(n=Bt,e){return Xl(e||Gi,n)}function Ql(n){let e=new Uint8Array(16);if(n.includes("::")){let[t,r]=n.split("::"),s=t?t.split(":").filter(Boolean):[],o=r?r.split(":").filter(Boolean):[],i=0;for(let c of s){let a=parseInt(c,16);e[i++]=a>>8&255,e[i++]=a&255}i=16-o.length*2;for(let c of o){let a=parseInt(c,16);e[i++]=a>>8&255,e[i++]=a&255}}else{let t=n.split(":"),r=0;for(let s of t){let o=parseInt(s,16);e[r++]=o>>8&255,e[r++]=o&255}}return Array.from(e)}function Zl(n){let{priority:e=1,target:t=".",alpn:r=["h3","h2"],ipv4hints:s=[],ipv6hints:o=[],echBase64:i=null}=n,c=[];if(c.push(e>>8&255,e&255),!t||t===".")c.push(0);else{let a=t.split(".");for(let l of a){c.push(l.length);for(let d=0;d<l.length;d++)c.push(l.charCodeAt(d))}c.push(0)}if(r&&r.length>0){let a=[];for(let l of r){a.push(l.length);for(let d=0;d<l.length;d++)a.push(l.charCodeAt(d))}c.push(0,1),c.push(a.length>>8&255,a.length&255),c.push(...a)}if(s&&s.length>0){let a=[];for(let l of s){let d=l.split(".").map(Number);d.length===4&&d.every(u=>!isNaN(u)&&u>=0&&u<=255)&&a.push(...d)}a.length>0&&(c.push(0,4),c.push(a.length>>8&255,a.length&255),c.push(...a))}if(i)try{let a=atob(i),l=[];for(let d=0;d<a.length;d++)l.push(a.charCodeAt(d));c.push(0,5),c.push(l.length>>8&255,l.length&255),c.push(...l)}catch(a){console.error("Failed to decode base64 ech config:",a)}if(o&&o.length>0){let a=[];for(let l of o){let d=Ql(l);d&&d.length===16&&a.push(...d)}a.length>0&&(c.push(0,6),c.push(a.length>>8&255,a.length&255),c.push(...a))}return c}function Yi(n){let e=n.trim().split(/\s+/),t=parseInt(e[0],10)||1,r=e[1]||".",s,o,i,c;for(let a=2;a<e.length;a++){let l=e[a],d=l.indexOf("=");if(d===-1)continue;let u=l.substring(0,d),f=l.substring(d+1);u==="alpn"?s=f.split(","):u==="ipv4hint"?o=f.split(","):u==="ech"?i=f:u==="ipv6hint"&&(c=f.split(","))}return Zl({priority:t,target:r,alpn:s,ipv4hints:o,ipv6hints:c,echBase64:i})}function os(n){let e=n.split(".");if(e.length!==4)return null;let t=!1,r=e.reduce((s,o)=>{let i=Number(o);return(o===""||isNaN(i)||i<0||i>255||String(i)!==o)&&(t=!0),(s<<8)+i},0)>>>0;return t?null:r}function sr(n){let e=n.trim().toLowerCase();e.startsWith("[")&&e.endsWith("]")&&(e=e.slice(1,-1));let t="";if(e.includes(".")){let c=e.lastIndexOf(":");if(c===-1)return null;t=e.substring(c+1),e=e.substring(0,c)+":0:0"}let r=e.split("::");if(r.length>2)return null;let s=e;if(r.length===2){let c=r[0]?r[0].split(":"):[],a=r[1]?r[1].split(":"):[];if(c.includes("")||a.includes(""))return null;let l=8-(c.length+a.length);if(l<0)return null;let d=new Array(l).fill("0").join(":");s=[...c,d,...a].filter(Boolean).join(":")}let o=s.split(":");if(o.length!==8)return null;if(t){let c=os(t);if(c===null)return null;o[6]=(c>>>16).toString(16),o[7]=(c&65535).toString(16)}let i="";for(let c of o){if(c===""||c.length>4)return null;let a=parseInt(c,16);if(isNaN(a)||a<0||a>65535||c.toLowerCase()!==a.toString(16).padStart(c.length,"0"))return null;i+=c.padStart(4,"0")}try{return BigInt("0x"+i)}catch{return null}}function st(n){return os(n)!==null}function Ft(n){return sr(n)!==null}function No(n){if(!n||typeof n!="string")return null;let e=n.lastIndexOf("/");if(e===-1)return null;let t=n.slice(0,e).trim(),r=n.slice(e+1).trim(),s=parseInt(r,10);if(isNaN(s)||s<0)return null;if(t.includes(":")){if(s>128)return null;let o=sr(t);if(o===null)return null;let i=s===0?0n:~0n<<BigInt(128-s)&(1n<<128n)-1n;return{version:6,net:o&i,mask:i}}else{if(s>32)return null;let o=os(t);if(o===null)return null;let i=s===0?0:-1<<32-s>>>0;return{version:4,net:(o&i)>>>0,mask:i}}}function is(n){let e=[],t=[];for(let r of n){let s=No(r);s&&(s.version===4?e.push(s):t.push(s))}return r=>{if(!r)return!1;if(r.includes(":")){let s=sr(r);return s===null?!1:t.some(o=>(s&o.mask)===o.net)}else{let s=os(r);return s===null?!1:e.some(o=>(s&o.mask)>>>0===o.net)}}}var Io=[],Uo=null;function Mo(n){n&&n.length>0&&(Io=n,Uo=is(Io))}function as(){return Io}function cs(n){return Uo?Uo(n):!1}var gt=new Map,or=300*1e3,he=class{constructor(e){this.db=e}db;static clearMemoryCache(e){e?gt.delete(e):gt.clear()}async ensureTable(){try{await this.db.prepare("CREATE TABLE IF NOT EXISTS system_settings (key TEXT PRIMARY KEY, value TEXT NOT NULL, updated_at INTEGER NOT NULL)").run()}catch(e){console.warn("[SystemSettingsModel] Failed to ensure system_settings table:",e)}}async getAll(){try{let{results:e}=await this.db.prepare("SELECT key, value FROM system_settings").all(),t={},r=Date.now()+or;for(let s of e)t[s.key]=s.value,gt.set(s.key,{value:s.value,expiresAt:r});return t}catch(e){if((e instanceof Error?e.message:String(e)).includes("no such table"))return await this.ensureTable(),{};throw e}}async get(e){let t=gt.get(e);if(t&&t.expiresAt>Date.now())return t.value;try{let r=await this.db.prepare("SELECT value FROM system_settings WHERE key = ?").bind(e).first(),s=r?r.value:null;return gt.set(e,{value:s,expiresAt:Date.now()+or}),s}catch(r){if((r instanceof Error?r.message:String(r)).includes("no such table"))return await this.ensureTable(),null;throw r}}async set(e,t){let r=Math.floor(Date.now()/1e3);try{let s=await this.db.prepare("INSERT INTO system_settings (key, value, updated_at) VALUES (?, ?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value, updated_at=excluded.updated_at").bind(e,t,r).run();return s.success&&gt.set(e,{value:t,expiresAt:Date.now()+or}),s.success}catch(s){if((s instanceof Error?s.message:String(s)).includes("no such table")){await this.ensureTable();let i=await this.db.prepare("INSERT INTO system_settings (key, value, updated_at) VALUES (?, ?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value, updated_at=excluded.updated_at").bind(e,t,r).run();return i.success&&gt.set(e,{value:t,expiresAt:Date.now()+or}),i.success}throw s}}async setMany(e){let t=Math.floor(Date.now()/1e3),r=Object.entries(e).map(([o,i])=>this.db.prepare("INSERT INTO system_settings (key, value, updated_at) VALUES (?, ?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value, updated_at=excluded.updated_at").bind(o,String(i),t));try{r.length>0&&await this.db.batch(r)}catch(o){if((o instanceof Error?o.message:String(o)).includes("no such table"))await this.ensureTable(),r.length>0&&await this.db.batch(r);else throw o}let s=Date.now()+or;for(let[o,i]of Object.entries(e))gt.set(o,{value:String(i),expiresAt:s});return!0}};var zi=null,ir=null;async function Xi(n){as().length>0||(!ir&&n&&(ir=(async()=>{try{let t=new he(n),[r,s]=await Promise.all([t.get("cf_proxy_cidrs"),t.get("cf_active_ech_config")]);if(s&&(zi=s),r){let o=JSON.parse(r);if(Array.isArray(o)&&o.length>0){Mo(o);return}}await Bo(n,!0)}catch(t){console.warn("[ECH] Could not load Cloudflare IP ranges from DB:",t)}finally{ir=null}})()),ir&&await ir)}async function Bo(n,e=!1){let t=new he(n),r=Math.floor(Date.now()/1e3);if(!e){let s=await t.get("cf_proxy_cidrs_updated_at");if(s){let o=parseInt(s,10);if(!isNaN(o)&&r-o<86400)return{success:!0,updated:!1,count:as().length}}}try{let[s,o,i]=await Promise.all([fetch("https://www.cloudflare.com/ips-v4",{headers:{"User-Agent":"Obex-DNS/1.0"},signal:AbortSignal.timeout(5e3)}),fetch("https://www.cloudflare.com/ips-v6",{headers:{"User-Agent":"Obex-DNS/1.0"},signal:AbortSignal.timeout(5e3)}),fetch("https://cloudflare-dns.com/dns-query?name=cloudflare-ech.com&type=HTTPS",{headers:{Accept:"application/dns-json"},signal:AbortSignal.timeout(5e3)}).catch(()=>null)]);if(!s.ok||!o.ok)throw new Error(`Failed to fetch Cloudflare IPs: v4 HTTP ${s.status}, v6 HTTP ${o.status}`);let c=await s.text(),a=await o.text(),d=[...c.split(`
216
216
  `),...a.split(`
217
- `)].map(f=>f.trim()).filter(f=>f.length>0&&!f.startsWith("#")).filter(f=>Po(f)!==null),u=null;if(i&&i.ok)try{let f=await i.json();if(f.Answer)for(let p of f.Answer){let m=String(p.data).match(/ech=([A-Za-z0-9+/=]+)/);if(m){u=m[1];break}}}catch(f){console.warn("[ECH] Failed to parse live Cloudflare ECH config:",f)}if(d.length>=10){let f={cf_proxy_cidrs:JSON.stringify(d),cf_proxy_cidrs_updated_at:String(r)};return u&&(f.cf_active_ech_config=u,Wi=u),await n.setMany(f),ko(d),console.log(`[ECH] Synced ${d.length} Cloudflare IP ranges and active ECH config.`),{success:!0,updated:!0,count:d.length}}else throw new Error(`Received insufficient valid CIDRs: ${d.length}`)}catch(s){return console.warn("[ECH] Cloudflare IP/ECH sync failed:",s.message||s),{success:!1,updated:!1,count:qr().length}}}function ts(t,e){let n=[];if(t==="A")n=e.split(".").map(r=>parseInt(r)||0);else if(t==="AAAA"){let r=new Uint8Array(16).fill(0);if(e.includes("::")){let[s,o]=e.split("::"),i=s.split(":").filter(l=>l),c=o.split(":").filter(l=>l),a=0;for(let l of i){let d=parseInt(l,16);r[a++]=d>>8&255,r[a++]=d&255}a=16-c.length*2;for(let l of c){let d=parseInt(l,16);r[a++]=d>>8&255,r[a++]=d&255}}else{let s=e.split(":"),o=0;for(let i of s){let c=parseInt(i,16);r[o++]=c>>8&255,r[o++]=c&255}}n=Array.from(r)}else if(t==="CNAME"){let r=e.split(".");for(let s of r){n.push(s.length);for(let o=0;o<s.length;o++)n.push(s.charCodeAt(o))}n.push(0)}else if(t==="TXT")for(let r=0;r<e.length;r+=255){let s=e.substring(r,r+255);n.push(s.length);for(let o=0;o<s.length;o++)n.push(s.charCodeAt(o))}else(t==="HTTPS"||t==="SVCB")&&(n=Ki(e));return n}function Ut(t,e){let n=new Uint8Array(12),r=Math.floor(Math.random()*65535);n[0]=r>>8,n[1]=r&255,n[2]=1,n[3]=0,n[4]=0,n[5]=1,n[6]=0,n[7]=0,n[8]=0,n[9]=0,n[10]=0,n[11]=0;let s=t.split("."),o=[];for(let a of s){o.push(a.length);for(let l=0;l<a.length;l++)o.push(a.charCodeAt(l))}o.push(0);let i=Xn[e]||1;o.push(i>>8),o.push(i&255),o.push(0),o.push(1);let c=new Uint8Array(n.length+o.length);return c.set(n),c.set(new Uint8Array(o),n.length),c}function un(t){let e=new Uint8Array(12);return t&&t.length>=12&&e.set(t.slice(0,12)),e[2]=e[2]&1|128,e[3]=e[3]&240|2,e}function Oo(t,e,n=0){try{if(!t||t.length<12)return un(t);let r=new Uint8Array(12);r.set(t.slice(0,12)),r[2]=r[2]&1|132,r[3]=128|n&15;let s=12,o=t[4]<<8|t[5];for(let u=0;u<o;u++){let{read:f}=qe(t,s);if(f===0||(s+=f+4,s>t.length))return un(t)}let i=t.slice(12,s);if(r[4]=o>>8&255,r[5]=o&255,r[6]=e.length>>8&255,r[7]=e.length&255,r[8]=0,r[9]=0,r[10]=0,r[11]=0,e.length===0){let u=new Uint8Array(12+i.length);return u.set(r),u.set(i,12),u}let c=[],a=12+i.length;for(let u of e){let{name:f,type:p,value:m,ttl:h=60}=u,g=[];if(!f)g=[192,12];else{let S=f.split(".");for(let x of S){g.push(x.length);for(let T=0;T<x.length;T++)g.push(x.charCodeAt(T))}g.push(0)}let w=ts(p,m),b=w.length,y=new Uint8Array(g.length+10+b);y.set(g,0);let E=g.length,_=Xn[p]||1;y[E++]=_>>8,y[E++]=_&255,y[E++]=0,y[E++]=1,y[E++]=h>>24&255,y[E++]=h>>16&255,y[E++]=h>>8&255,y[E++]=h&255,y[E++]=b>>8&255,y[E++]=b&255,y.set(w,E),c.push(y),a+=y.length}let l=new Uint8Array(a);l.set(r,0),l.set(i,12);let d=12+i.length;for(let u of c)l.set(u,d),d+=u.length;return l}catch(r){console.error("Critical error in buildResponseMulti:",r);let s=new Uint8Array(12);return s.set(t.slice(0,12)),s[2]|=128,s[3]=s[3]&240|2,s}}function Ee(t,e,n,r=60,s=0){try{if(!t||t.length<12)return un(t);let o=new Uint8Array(12);o.set(t.slice(0,12)),o[2]=o[2]&1|132,o[3]=128|s&15;let i=12,c=t[4]<<8|t[5];for(let m=0;m<c;m++){let{read:h}=qe(t,i);if(h===0||(i+=h+4,i>t.length))return un(t)}let a=t.slice(12,i);if(o[4]=c>>8&255,o[5]=c&255,o[6]=0,o[7]=n?1:0,o[8]=0,o[9]=0,o[10]=0,o[11]=0,!n){let m=new Uint8Array(12+a.length);return m.set(o),m.set(a,12),m}let l=ts(e,n),d=l.length,u=new Uint8Array(12+d);u[0]=192,u[1]=12;let f=Xn[e]||1;u[2]=f>>8,u[3]=f&255,u[4]=0,u[5]=1,u[6]=r>>24&255,u[7]=r>>16&255,u[8]=r>>8&255,u[9]=r&255,u[10]=d>>8&255,u[11]=d&255,u.set(l,12);let p=new Uint8Array(12+a.length+u.length);return p.set(o),p.set(a,12),p.set(u,12+a.length),p}catch(o){console.error("Critical error in buildResponse:",o);let i=new Uint8Array(12);return i.set(t.slice(0,12)),i[2]|=128,i[3]=i[3]&240|2,i}}function jl(t){let e=t.lastIndexOf("/");if(e===-1)return null;let n=t.slice(0,e),r=parseInt(t.slice(e+1),10);if(isNaN(r))return null;if(n.includes(":")){let s=Vl(n);if(!s||r<0||r>128)return null;let o=Vi(s,r);return{family:2,prefixLen:r,addrBytes:o}}else{let s=n.split(".").map(Number);if(s.length!==4||s.some(c=>isNaN(c)||c<0||c>255)||r<0||r>32)return null;let o=new Uint8Array(s),i=Vi(o,r);return{family:1,prefixLen:r,addrBytes:i}}}function Vi(t,e){let n=Math.ceil(e/8),r=new Uint8Array(n);for(let o=0;o<n;o++)r[o]=t[o]??0;let s=e%8;return s!==0&&n>0&&(r[n-1]&=255<<8-s&255),r}function Vl(t){try{let e=t.split("::");if(e.length>2)return null;let n=e[0]?e[0].split(":"):[],r=e[1]?e[1].split(":"):[],s=8-n.length-r.length,o=[...n,...Array(s).fill("0"),...r];if(o.length!==8)return null;let i=new Uint8Array(16);for(let c=0;c<8;c++){let a=parseInt(o[c],16);if(isNaN(a))return null;i[c*2]=a>>8&255,i[c*2+1]=a&255}return i}catch{return null}}function Jl(t){let e=jl(t);if(!e)return null;let{family:n,prefixLen:r,addrBytes:s}=e,o=4+s.length,i=new Uint8Array(4+o),c=0;i[c++]=0,i[c++]=8,i[c++]=o>>8&255,i[c++]=o&255,i[c++]=n>>8&255,i[c++]=n&255,i[c++]=r,i[c++]=0,i.set(s,c);let a=i.length,l=new Uint8Array(11+a),d=0;return l[d++]=0,l[d++]=0,l[d++]=41,l[d++]=16,l[d++]=0,l[d++]=0,l[d++]=0,l[d++]=0,l[d++]=0,l[d++]=a>>8&255,l[d++]=a&255,l.set(i,d),l}function Io(t,e){let n=Jl(e);if(!n)return console.warn(`[ECS] Invalid CIDR "${e}", skipping injection.`),t;if(t.length<12)return t;let r=t[10]<<8|t[11],s=12,o=t[4]<<8|t[5];for(let f=0;f<o&&s<t.length;f++){for(;s<t.length;){let p=t[s];if(p===0){s++;break}if((p&192)===192){s+=2;break}s+=1+p}s+=4}let i=(t[6]<<8|t[7])+(t[8]<<8|t[9]);for(let f=0;f<i&&s<t.length;f++)s=No(t,s);let c=s,a=-1,l=-1,d=c;for(let f=0;f<r&&d<t.length;f++){let p=d;if(d<t.length&&t[d]===0&&(d+1<t.length?t[d+1]<<8|t[d+2]:-1)===41){a=p,d=No(t,d),l=d;break}d=No(t,d)}let u;if(a!==-1){let f=t.slice(0,a),p=t.slice(l);u=new Uint8Array(f.length+n.length+p.length),u.set(f,0),u.set(n,f.length),u.set(p,f.length+n.length)}else{u=new Uint8Array(t.length+n.length),u.set(t,0),u.set(n,t.length);let f=r+1;u[10]=f>>8&255,u[11]=f&255}return u}function No(t,e){if(e>=t.length)return e;for(;e<t.length;){let r=t[e];if(r===0){e++;break}if((r&192)===192){e+=2;break}e+=1+r}if(e+10>t.length)return t.length;let n=t[e+8]<<8|t[e+9];return e+=10+n,Math.min(e,t.length)}ge();var pn=class extends Map{constructor(n){super();this.maxEntries=n}maxEntries;set(n,r){if(!this.has(n)&&this.size>=this.maxEntries){let s=this.keys().next().value;s!==void 0&&this.delete(s)}return this.delete(n),super.set(n,r),this}},tr=new pn(3),nr=new pn(10),fn=new pn(500),rr=new pn(100);async function Gl(t,e){try{let n=await fetch(`https://api.cloudflare.com/client/v4/zones/${t.CF_ZONE_ID}/purge_cache`,{method:"POST",headers:{Authorization:`Bearer ${t.CF_PURGE_TOKEN}`,"Content-Type":"application/json"},body:JSON.stringify({tags:e})});if(!n.ok){let r=await n.text();console.error(`[Cache] Global cache purge failed (HTTP ${n.status}):`,r)}}catch(n){console.error("[Cache] Global cache purge error:",n?.message||n)}}var ns={async clear(t,e=!0,n){let r=!0,s;typeof e=="boolean"?(r=e,n&&typeof n=="object"&&(s=n)):e&&typeof e=="object"&&(s=e,typeof n=="boolean"&&(r=n)),nr.delete(t),r&&tr.delete(t),rr.clear();for(let o of fn.keys())o.startsWith(`${t}:`)&&fn.delete(o);try{if(typeof caches<"u"&&caches&&caches.default){let o=caches.default,i=[P.delete(o,`profile_v6:${t}`)];r&&i.push(o.delete(`https://obex.local/bloom-bin/${t}`)),await Promise.all(i)}}catch(o){console.error("Failed to clear cache API:",o)}if(s&&s.CF_ZONE_ID&&s.CF_PURGE_TOKEN){let o=[`profile-${t}`];r&&o.push(`bloom-${t}`),await Gl(s,o)}}};pe();var q=class{constructor(e){this.db=e}db;async getById(e){return await this.db.prepare("SELECT * FROM profiles WHERE id = ?").bind(e).first()}async findByKey(e){try{let n=await this.db.prepare(`
217
+ `)].map(f=>f.trim()).filter(f=>f.length>0&&!f.startsWith("#")).filter(f=>No(f)!==null),u=null;if(i&&i.ok)try{let f=await i.json();if(f.Answer)for(let p of f.Answer){let m=String(p.data).match(/ech=([A-Za-z0-9+/=]+)/);if(m){u=m[1];break}}}catch(f){console.warn("[ECH] Failed to parse live Cloudflare ECH config:",f)}if(d.length>=10){let f={cf_proxy_cidrs:JSON.stringify(d),cf_proxy_cidrs_updated_at:String(r)};return u&&(f.cf_active_ech_config=u,zi=u),await t.setMany(f),Mo(d),console.log(`[ECH] Synced ${d.length} Cloudflare IP ranges and active ECH config.`),{success:!0,updated:!0,count:d.length}}else throw new Error(`Received insufficient valid CIDRs: ${d.length}`)}catch(s){return console.warn("[ECH] Cloudflare IP/ECH sync failed:",s.message||s),{success:!1,updated:!1,count:as().length}}}function ls(n,e){let t=[];if(n==="A")t=e.split(".").map(r=>parseInt(r)||0);else if(n==="AAAA"){let r=new Uint8Array(16).fill(0);if(e.includes("::")){let[s,o]=e.split("::"),i=s.split(":").filter(l=>l),c=o.split(":").filter(l=>l),a=0;for(let l of i){let d=parseInt(l,16);r[a++]=d>>8&255,r[a++]=d&255}a=16-c.length*2;for(let l of c){let d=parseInt(l,16);r[a++]=d>>8&255,r[a++]=d&255}}else{let s=e.split(":"),o=0;for(let i of s){let c=parseInt(i,16);r[o++]=c>>8&255,r[o++]=c&255}}t=Array.from(r)}else if(n==="CNAME"){let r=e.split(".");for(let s of r){t.push(s.length);for(let o=0;o<s.length;o++)t.push(s.charCodeAt(o))}t.push(0)}else if(n==="TXT")for(let r=0;r<e.length;r+=255){let s=e.substring(r,r+255);t.push(s.length);for(let o=0;o<s.length;o++)t.push(s.charCodeAt(o))}else(n==="HTTPS"||n==="SVCB")&&(t=Yi(e));return t}function Ht(n,e){let t=new Uint8Array(12),r=crypto.getRandomValues(new Uint16Array(1))[0];t[0]=r>>8,t[1]=r&255,t[2]=1,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=0,t[11]=0;let s=n.split("."),o=[];for(let a of s){o.push(a.length);for(let l=0;l<a.length;l++)o.push(a.charCodeAt(l))}o.push(0);let i=nr[e]||1;o.push(i>>8),o.push(i&255),o.push(0),o.push(1);let c=new Uint8Array(t.length+o.length);return c.set(t),c.set(new Uint8Array(o),t.length),c}function yn(n){let e=new Uint8Array(12);return n&&n.length>=12&&e.set(n.slice(0,12)),e[2]=e[2]&1|128,e[3]=e[3]&240|2,e}function Fo(n,e,t=0){try{if(!n||n.length<12)return yn(n);let r=new Uint8Array(12);r.set(n.slice(0,12)),r[2]=r[2]&1|132,r[3]=128|t&15;let s=12,o=n[4]<<8|n[5];for(let u=0;u<o;u++){let{read:f}=rt(n,s);if(f===0||(s+=f+4,s>n.length))return yn(n)}let i=n.slice(12,s);if(r[4]=o>>8&255,r[5]=o&255,r[6]=e.length>>8&255,r[7]=e.length&255,r[8]=0,r[9]=0,r[10]=0,r[11]=0,e.length===0){let u=new Uint8Array(12+i.length);return u.set(r),u.set(i,12),u}let c=[],a=12+i.length;for(let u of e){let{name:f,type:p,value:m,ttl:h=60}=u,g=[];if(!f)g=[192,12];else{let S=f.split(".");for(let x of S){g.push(x.length);for(let T=0;T<x.length;T++)g.push(x.charCodeAt(T))}g.push(0)}let b=ls(p,m),w=b.length,y=new Uint8Array(g.length+10+w);y.set(g,0);let E=g.length,_=nr[p]||1;y[E++]=_>>8,y[E++]=_&255,y[E++]=0,y[E++]=1,y[E++]=h>>24&255,y[E++]=h>>16&255,y[E++]=h>>8&255,y[E++]=h&255,y[E++]=w>>8&255,y[E++]=w&255,y.set(b,E),c.push(y),a+=y.length}let l=new Uint8Array(a);l.set(r,0),l.set(i,12);let d=12+i.length;for(let u of c)l.set(u,d),d+=u.length;return l}catch(r){console.error("Critical error in buildResponseMulti:",r);let s=new Uint8Array(12);return s.set(n.slice(0,12)),s[2]|=128,s[3]=s[3]&240|2,s}}function Ee(n,e,t,r=60,s=0){try{if(!n||n.length<12)return yn(n);let o=new Uint8Array(12);o.set(n.slice(0,12)),o[2]=o[2]&1|132,o[3]=128|s&15;let i=12,c=n[4]<<8|n[5];for(let m=0;m<c;m++){let{read:h}=rt(n,i);if(h===0||(i+=h+4,i>n.length))return yn(n)}let a=n.slice(12,i);if(o[4]=c>>8&255,o[5]=c&255,o[6]=0,o[7]=t?1:0,o[8]=0,o[9]=0,o[10]=0,o[11]=0,!t){let m=new Uint8Array(12+a.length);return m.set(o),m.set(a,12),m}let l=ls(e,t),d=l.length,u=new Uint8Array(12+d);u[0]=192,u[1]=12;let f=nr[e]||1;u[2]=f>>8,u[3]=f&255,u[4]=0,u[5]=1,u[6]=r>>24&255,u[7]=r>>16&255,u[8]=r>>8&255,u[9]=r&255,u[10]=d>>8&255,u[11]=d&255,u.set(l,12);let p=new Uint8Array(12+a.length+u.length);return p.set(o),p.set(a,12),p.set(u,12+a.length),p}catch(o){console.error("Critical error in buildResponse:",o);let i=new Uint8Array(12);return i.set(n.slice(0,12)),i[2]|=128,i[3]=i[3]&240|2,i}}function ql(n){let e=n.lastIndexOf("/");if(e===-1)return null;let t=n.slice(0,e),r=parseInt(n.slice(e+1),10);if(isNaN(r))return null;if(t.includes(":")){let s=ed(t);if(!s||r<0||r>128)return null;let o=Qi(s,r);return{family:2,prefixLen:r,addrBytes:o}}else{let s=t.split(".").map(Number);if(s.length!==4||s.some(c=>isNaN(c)||c<0||c>255)||r<0||r>32)return null;let o=new Uint8Array(s),i=Qi(o,r);return{family:1,prefixLen:r,addrBytes:i}}}function Qi(n,e){let t=Math.ceil(e/8),r=new Uint8Array(t);for(let o=0;o<t;o++)r[o]=n[o]??0;let s=e%8;return s!==0&&t>0&&(r[t-1]&=255<<8-s&255),r}function ed(n){try{let e=n.split("::");if(e.length>2)return null;let t=e[0]?e[0].split(":"):[],r=e[1]?e[1].split(":"):[],s=8-t.length-r.length,o=[...t,...Array(s).fill("0"),...r];if(o.length!==8)return null;let i=new Uint8Array(16);for(let c=0;c<8;c++){let a=parseInt(o[c],16);if(isNaN(a))return null;i[c*2]=a>>8&255,i[c*2+1]=a&255}return i}catch{return null}}function td(n){let e=ql(n);if(!e)return null;let{family:t,prefixLen:r,addrBytes:s}=e,o=4+s.length,i=new Uint8Array(4+o),c=0;i[c++]=0,i[c++]=8,i[c++]=o>>8&255,i[c++]=o&255,i[c++]=t>>8&255,i[c++]=t&255,i[c++]=r,i[c++]=0,i.set(s,c);let a=i.length,l=new Uint8Array(11+a),d=0;return l[d++]=0,l[d++]=0,l[d++]=41,l[d++]=16,l[d++]=0,l[d++]=0,l[d++]=0,l[d++]=0,l[d++]=0,l[d++]=a>>8&255,l[d++]=a&255,l.set(i,d),l}function $o(n,e){let t=td(e);if(!t)return console.warn(`[ECS] Invalid CIDR "${e}", skipping injection.`),n;if(n.length<12)return n;let r=n[10]<<8|n[11],s=12,o=n[4]<<8|n[5];for(let f=0;f<o&&s<n.length;f++){for(;s<n.length;){let p=n[s];if(p===0){s++;break}if((p&192)===192){s+=2;break}s+=1+p}s+=4}let i=(n[6]<<8|n[7])+(n[8]<<8|n[9]);for(let f=0;f<i&&s<n.length;f++)s=Ho(n,s);let c=s,a=-1,l=-1,d=c;for(let f=0;f<r&&d<n.length;f++){let p=d;if(d<n.length&&n[d]===0&&(d+1<n.length?n[d+1]<<8|n[d+2]:-1)===41){a=p,d=Ho(n,d),l=d;break}d=Ho(n,d)}let u;if(a!==-1){let f=n.slice(0,a),p=n.slice(l);u=new Uint8Array(f.length+t.length+p.length),u.set(f,0),u.set(t,f.length),u.set(p,f.length+t.length)}else{u=new Uint8Array(n.length+t.length),u.set(n,0),u.set(t,n.length);let f=r+1;u[10]=f>>8&255,u[11]=f&255}return u}function Ho(n,e){if(e>=n.length)return e;for(;e<n.length;){let r=n[e];if(r===0){e++;break}if((r&192)===192){e+=2;break}e+=1+r}if(e+10>n.length)return n.length;let t=n[e+8]<<8|n[e+9];return e+=10+t,Math.min(e,n.length)}ge();var wn=class extends Map{constructor(t){super();this.maxEntries=t}maxEntries;set(t,r){if(!this.has(t)&&this.size>=this.maxEntries){let s=this.keys().next().value;s!==void 0&&this.delete(s)}return this.delete(t),super.set(t,r),this}},ar=new wn(3),cr=new wn(10),bn=new wn(500),lr=new wn(100);async function nd(n,e){try{let t=await fetch(`https://api.cloudflare.com/client/v4/zones/${n.CF_ZONE_ID}/purge_cache`,{method:"POST",headers:{Authorization:`Bearer ${n.CF_PURGE_TOKEN}`,"Content-Type":"application/json"},body:JSON.stringify({tags:e})});if(!t.ok){let r=await t.text();console.error(`[Cache] Global cache purge failed (HTTP ${t.status}):`,r)}}catch(t){console.error("[Cache] Global cache purge error:",t?.message||t)}}var ds={async clear(n,e=!0,t){let r=!0,s;typeof e=="boolean"?(r=e,t&&typeof t=="object"&&(s=t)):e&&typeof e=="object"&&(s=e,typeof t=="boolean"&&(r=t)),cr.delete(n),r&&ar.delete(n),lr.clear();for(let o of bn.keys())o.startsWith(`${n}:`)&&bn.delete(o);try{if(typeof caches<"u"&&caches&&caches.default){let o=caches.default,i=[P.delete(o,`profile_v6:${n}`)];r&&i.push(o.delete(`https://obex.local/bloom-bin/${n}`)),await Promise.all(i)}}catch(o){console.error("Failed to clear cache API:",o)}if(s&&s.CF_ZONE_ID&&s.CF_PURGE_TOKEN){let o=[`profile-${n}`];r&&o.push(`bloom-${n}`),await nd(s,o)}}};pe();var q=class{constructor(e){this.db=e}db;async getById(e){return await this.db.prepare("SELECT * FROM profiles WHERE id = ?").bind(e).first()}async findByKey(e){try{let t=await this.db.prepare(`
218
218
  SELECT p.*, ap.id as access_point_id, ap.name as access_point_name
219
219
  FROM access_points ap
220
220
  JOIN profiles p ON ap.profile_id = p.id
221
221
  WHERE ap.token = ?
222
- `).bind(e).first();return n||await this.db.prepare(`
222
+ `).bind(e).first();return t||await this.db.prepare(`
223
223
  SELECT p.*, NULL as access_point_id, NULL as access_point_name
224
224
  FROM profiles p
225
225
  WHERE p.profile_key = ? OR p.id = ?
226
- `).bind(e,e).first()||null}catch(n){return console.warn("[ProfileModel] findByKey D1 query failed:",n.message||n),null}}async list(e,n){let{results:r}=await this.db.prepare(`SELECT * FROM profiles ${e}`).bind(...n).all();return r}async listByOwner(e){let{results:n}=await this.db.prepare("SELECT * FROM profiles WHERE owner_id = ? ORDER BY created_at DESC").bind(e).all();return n}async findByName(e,n){return await this.db.prepare("SELECT * FROM profiles WHERE owner_id = ? AND name = ?").bind(e,n).first()}async create(e){let n=Math.floor(Date.now()/1e3),r=j(12),s=5;for(let o=0;o<s;o++){let i=Mt(5),c=e.profile_key||i,a=[this.db.prepare("INSERT INTO profiles (id, profile_key, owner_id, name, settings, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)").bind(e.id,c,e.owner_id,e.name,JSON.stringify(e.settings),n,n),this.db.prepare("INSERT INTO access_points (id, profile_id, name, token, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)").bind(r,e.id,"Device-1",i,n,n)];try{return(await this.db.batch(a)).every(d=>d.success)}catch(l){if(o<s-1&&(String(l).includes("UNIQUE constraint failed")||String(l).includes("SQLITE_CONSTRAINT")))continue;throw l}}return!1}async delete(e){return(await this.db.batch([this.db.prepare("DELETE FROM logs WHERE profile_id = ?").bind(e),this.db.prepare("DELETE FROM profiles WHERE id = ?").bind(e)])).every(r=>r.success)}async deleteByOwner(e){return(await this.db.batch([this.db.prepare("DELETE FROM logs WHERE profile_id IN (SELECT id FROM profiles WHERE owner_id = ?)").bind(e),this.db.prepare("DELETE FROM profiles WHERE owner_id = ?").bind(e)])).every(r=>r.success)}async updateName(e,n){let r=Math.floor(Date.now()/1e3);return(await this.db.prepare("UPDATE profiles SET name = ?, updated_at = ? WHERE id = ?").bind(n,r,e).run()).success}async updateSettings(e,n){let r=Math.floor(Date.now()/1e3);return(await this.db.prepare("UPDATE profiles SET settings = ?, updated_at = ? WHERE id = ?").bind(JSON.stringify(n),r,e).run()).success}async rotateKey(e,n){let r=Math.floor(Date.now()/1e3);return(await this.db.prepare("UPDATE profiles SET profile_key = ?, updated_at = ? WHERE id = ?").bind(n,r,e).run()).success}async updateLastActive(e,n){return(await this.db.prepare("UPDATE profiles SET last_active_at = ? WHERE id = ?").bind(n,e).run()).success}async getSyncTargets(e,n){let{results:r}=await this.db.prepare("SELECT id FROM profiles WHERE (list_updated_at IS NULL OR list_updated_at <= ?) AND EXISTS (SELECT 1 FROM lists WHERE lists.profile_id = profiles.id) ORDER BY list_updated_at ASC LIMIT ?").bind(e,n).all();return r}async updateListUpdatedAt(e,n){return(await this.db.prepare("UPDATE profiles SET list_updated_at = ? WHERE id = ?").bind(n,e).run()).success}};var En=class{constructor(e){this.db=e}db;async getRules(e){let{results:n}=await this.db.prepare("SELECT * FROM rules WHERE profile_id = ? ORDER BY id DESC").bind(e).all();return n}async addRule(e,n){let r=n.pattern?n.pattern.trim().toLowerCase():"",s=n.created_at??Math.floor(Date.now()/1e3);return(await this.db.prepare("INSERT INTO rules (profile_id, type, pattern, v_a, v_aaaa, v_txt, v_cname, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").bind(e,n.type,r,n.v_a||null,n.v_aaaa||null,n.v_txt||null,n.v_cname||null,s).run()).success}async addRulesBulk(e,n){if(!n||n.length===0)return 0;let r=Math.floor(Date.now()/1e3),s=n.map(i=>{let c=i.pattern?i.pattern.trim().toLowerCase():"",a=i.created_at??r;return this.db.prepare("INSERT INTO rules (profile_id, type, pattern, v_a, v_aaaa, v_txt, v_cname, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").bind(e,i.type,c,i.v_a||null,i.v_aaaa||null,i.v_txt||null,i.v_cname||null,a)}),o=0;for(let i=0;i<s.length;i+=100){let c=s.slice(i,i+100),a=await this.db.batch(c);for(let l of a)l.success&&(o+=l.meta.changes||1)}return o}async updateRule(e,n,r){let s=r.pattern?r.pattern.trim().toLowerCase():"";return(await this.db.prepare("UPDATE rules SET type = ?, pattern = ?, v_a = ?, v_aaaa = ?, v_txt = ?, v_cname = ? WHERE id = ? AND profile_id = ?").bind(r.type,s,r.v_a||null,r.v_aaaa||null,r.v_txt||null,r.v_cname||null,e,n).run()).success}async getRuleByPattern(e,n){return await this.db.prepare("SELECT * FROM rules WHERE profile_id = ? AND LOWER(pattern) = ?").bind(e,n.trim().toLowerCase()).first()}async getRuleByPatternExcludeId(e,n,r){return await this.db.prepare("SELECT * FROM rules WHERE profile_id = ? AND LOWER(pattern) = ? AND id != ?").bind(e,n.trim().toLowerCase(),r).first()}async deleteRule(e,n){return(await this.db.prepare("DELETE FROM rules WHERE id = ? AND profile_id = ?").bind(e,n).run()).success}};var Te=class t{size;hashes;bitArray;static FNV_PRIME=16777619;static FNV_SEED_0=2166136261;static encoder=new TextEncoder;constructor(e,n,r){this.size=e>>>0,this.hashes=n>>>0;let s=this.size+31>>>5;this.bitArray=r||new Uint32Array(s)}static create(e,n=1e-4){let r=Math.max(e,100),o=Math.ceil(-(r*Math.log(n))/Math.log(2)**2),i=Math.round(o/r*Math.log(2));return new t(o,i)}add(e){let n=t.FNV_SEED_0,r=e.length;for(let a=0;a<r;a++)n^=e.charCodeAt(a)&255,n=Math.imul(n,t.FNV_PRIME);n=n>>>0;let s=n^n>>>16;s=Math.imul(s,2246822507),s=s^s>>>13,s=Math.imul(s,3266489909),s=(s^s>>>16)>>>0;let o=this.bitArray,i=this.size,c=this.hashes;for(let a=0;a<c;a++){let l=(n+a*s)%i;o[l>>>5]|=1<<(l&31)}}test(e){let n=t.FNV_SEED_0,r=e.length;for(let a=0;a<r;a++)n^=e.charCodeAt(a)&255,n=Math.imul(n,t.FNV_PRIME);n=n>>>0;let s=n^n>>>16;s=Math.imul(s,2246822507),s=s^s>>>13,s=Math.imul(s,3266489909),s=(s^s>>>16)>>>0;let o=this.bitArray,i=this.size,c=this.hashes;for(let a=0;a<c;a++){let l=(n+a*s)%i;if((o[l>>>5]&1<<(l&31))===0)return!1}return!0}toUint8Array(){let e=new Uint8Array(8+this.bitArray.byteLength),n=new DataView(e.buffer);return n.setUint32(0,this.size,!0),n.setUint32(4,this.hashes,!0),e.set(new Uint8Array(this.bitArray.buffer,this.bitArray.byteOffset,this.bitArray.byteLength),8),e}static fromUint8Array(e){if(!e||e.byteLength<8)throw new Error("Invalid bloom filter buffer: header too short");let n=new DataView(e.buffer,e.byteOffset,8),r=n.getUint32(0,!0),s=n.getUint32(4,!0);if(r===0||s===0)throw new Error("Invalid bloom filter parameters: size and hashes must be positive integers");let o=e.byteOffset+8,i=e.byteLength-8,c=r+31>>>5,a=i>>2;if(a<c)throw new Error(`Invalid bloom filter buffer: bit array truncated (expected ${c} words, got ${a})`);let l;if(o%4===0)l=new Uint32Array(e.buffer,o,c);else{let d=new Uint8Array(c<<2);d.set(e.subarray(8,8+(c<<2))),l=new Uint32Array(d.buffer,0,c)}return new t(r,s,l)}merge(e){if(this.size!==e.size||this.hashes!==e.hashes)throw new Error("Cannot merge bloom filters with different sizes or hash counts.");let n=this.bitArray,r=e.bitArray,s=n.length;for(let o=0;o<s;o++)n[o]|=r[o]}fnv1a(e,n){let r=n>>>0;for(let s=0;s<e.length;s++)r^=e[s],r=Math.imul(r,t.FNV_PRIME);return r>>>0}fnv1aString(e,n){let r=n>>>0,s=e.length;for(let o=0;o<s;o++)r^=e.charCodeAt(o)&255,r=Math.imul(r,t.FNV_PRIME);return r>>>0}dump(){let e=new Uint8Array(this.bitArray.buffer,this.bitArray.byteOffset,this.bitArray.byteLength),n="",r=e.byteLength,s=32768;for(let o=0;o<r;o+=s)n+=String.fromCharCode.apply(null,e.subarray(o,Math.min(o+s,r)));return{size:this.size,hashes:this.hashes,data:btoa(n)}}static load(e){let n=atob(e.data),r=new Uint8Array(n.length);for(let i=0;i<n.length;i++)r[i]=n.charCodeAt(i);let s=r.length+3>>2,o=new Uint32Array(s);return new Uint8Array(o.buffer).set(r),new t(e.size,e.hashes,o)}};var wt=class{constructor(e){this.db=e}db;async clearProfileBlooms(e){return(await this.db.prepare("DELETE FROM profile_blooms WHERE profile_id = ?").bind(e).run()).success}async upsertProfileBloom(e,n,r){let s=new Uint8Array(n),o=[];o.push(this.db.prepare("DELETE FROM profile_blooms WHERE profile_id = ?").bind(e));let i=0;for(let a=0;a<s.length;a+=1572864){let l=s.slice(a,a+1572864).buffer;o.push(this.db.prepare("INSERT INTO profile_blooms (profile_id, chunk_index, bloom_filter_chunk, updated_at) VALUES (?, ?, ?, ?)").bind(e,i,l,r)),i++}return(await this.db.batch(o)).every(a=>a.success)}async getProfileBloom(e){let{results:n}=await this.db.prepare("SELECT bloom_filter_chunk FROM profile_blooms WHERE profile_id = ? ORDER BY chunk_index ASC").bind(e).all();if(!n||n.length===0)return null;let r=n.reduce((i,c)=>{let a=c.bloom_filter_chunk.byteLength??c.bloom_filter_chunk.length;return i+a},0),s=new Uint8Array(r),o=0;for(let i of n){let c=new Uint8Array(i.bloom_filter_chunk);s.set(c,o),o+=c.length}return s.buffer}async initializeStagingBloom(e,n,r,s){let i=Te.create(n,r).toUint8Array();return this.upsertStagingBloom(e,i.buffer,s)}async clearStagingBloom(e){return(await this.db.prepare("DELETE FROM profile_blooms_staging WHERE profile_id = ?").bind(e).run()).success}async upsertStagingBloom(e,n,r){let s=new Uint8Array(n),o=[];o.push(this.db.prepare("DELETE FROM profile_blooms_staging WHERE profile_id = ?").bind(e));let i=0;for(let a=0;a<s.length;a+=1572864){let l=s.slice(a,a+1572864).buffer;o.push(this.db.prepare("INSERT INTO profile_blooms_staging (profile_id, chunk_index, bloom_filter_chunk, updated_at) VALUES (?, ?, ?, ?)").bind(e,i,l,r)),i++}return(await this.db.batch(o)).every(a=>a.success)}async getStagingBloom(e){let{results:n}=await this.db.prepare("SELECT bloom_filter_chunk FROM profile_blooms_staging WHERE profile_id = ? ORDER BY chunk_index ASC").bind(e).all();if(!n||n.length===0)return null;let r=n.reduce((i,c)=>{let a=c.bloom_filter_chunk.byteLength??c.bloom_filter_chunk.length;return i+a},0),s=new Uint8Array(r),o=0;for(let i of n){let c=new Uint8Array(i.bloom_filter_chunk);s.set(c,o),o+=c.length}return s.buffer}async promoteStagingToActive(e,n){let{results:r}=await this.db.prepare("SELECT chunk_index, bloom_filter_chunk FROM profile_blooms_staging WHERE profile_id = ? ORDER BY chunk_index ASC").bind(e).all();if(!r||r.length===0)return await this.clearProfileBlooms(e),!0;let s=[this.db.prepare("DELETE FROM profile_blooms WHERE profile_id = ?").bind(e),...r.map(i=>this.db.prepare("INSERT INTO profile_blooms (profile_id, chunk_index, bloom_filter_chunk, updated_at) VALUES (?, ?, ?, ?)").bind(e,i.chunk_index,i.bloom_filter_chunk,n)),this.db.prepare("DELETE FROM profile_blooms_staging WHERE profile_id = ?").bind(e)];return(await this.db.batch(s)).every(i=>i.success)}};ge();var zi={async load(t,e){let{profileId:n,env:r,ctx:s}=t,o=tr.get(n),i=nr.get(n),c=Number(r.BLOOM_MEM_TTL)||6e5;if(i&&Date.now()-(i.timestamp||0)<3e5){e("load_config_l1_mem");let m=o&&Date.now()-o.ts<c?o.bloom:void 0;return{...i,bloom:m}}let l=caches.default,d=`profile_v6:${n}`,u=`https://obex.local/bloom-bin/${n}`,f=await P.get(l,d),p;if(f){if(e("load_config_l2_cache"),o&&Date.now()-o.ts<c)p=o.bloom;else try{let m=await l.match(u);if(m){e("load_bloom_l2_cache");let h=await m.arrayBuffer();p=Te.fromUint8Array(new Uint8Array(h)),tr.set(n,{bloom:p,ts:Date.now()})}}catch{}return nr.set(n,{...f,timestamp:Date.now()}),{...f,bloom:p}}try{let m=new q(r.DB),h=new En(r.DB),g=new wt(r.DB),[w,b,y]=await Promise.all([m.getById(n),h.getRules(n),g.getProfileBloom(n).catch(S=>(console.error("[Config] D1 Bloom loading failed:",S),null))]);if(!w)return i?(console.warn(`[Config] Profile ${n} not in D1, using stale memory config.`),{...i,bloom:o?.bloom}):null;let E=JSON.parse(w.settings);if(y){e("load_bloom_l3_d1");let S=new Uint8Array(y);p=Te.fromUint8Array(S),s.waitUntil(l.put(u,new Response(S,{headers:{"Content-Type":"application/octet-stream","Cache-Control":"public, max-age=604800","Cache-Tag":`bloom-${n}`}})))}let _={settings:E,rules:b};return p&&tr.set(n,{bloom:p,ts:Date.now()}),nr.set(n,{..._,timestamp:Date.now()}),s.waitUntil(P.set(l,d,_,86400,[`profile-${n}`])),e("load_config_full_sync"),{..._,bloom:p}}catch(m){return console.warn(`[Config] D1 profile fetch failed for ${n}:`,m?.message||m),i?(console.warn(`[Config] Serving stale config from memory for profile ${n}`),{...i,bloom:o?.bloom}):(console.warn(`[Config] Serving emergency fail-open safe fallback for profile ${n}`),{settings:{upstream:[r.FAIL_OPEN_UPSTREAM||"https://freedns.controld.com/no-ads-malware-typo"],default_policy:"ALLOW",log_retention_days:0,ecs:{enabled:!0,use_client_ip:!0}},rules:[],bloom:void 0})}}};function ms(t){let e=t.trim();if(!e.startsWith("sdns://"))throw new Error("Invalid DNS Stamp: must start with sdns://");let n=e.slice(7),r=n.length;for(;r>0&&n.charCodeAt(r-1)===61;)r--;let s=n.slice(0,r),o;if(typeof Buffer<"u")o=Buffer.from(s,"base64url").toString("latin1");else{let y=s.replace(/-/g,"+").replace(/_/g,"/"),E=y.length%4,_=E?y+"=".repeat(4-E):y;o=atob(_)}let i=new Uint8Array(o.length);for(let y=0;y<o.length;y++)i[y]=o.charCodeAt(y);if(i.length<9)throw new Error("DNS Stamp payload too short (minimum 9 bytes)");let c=0,a=i[c++],l=0n;for(let y=0;y<8;y++)l|=BigInt(i[c++])<<BigInt(y*8);let d=()=>{if(c>=i.length)return"";let y=i[c++];if(c+y>i.length)return"";let E=i.slice(c,c+y);return c+=y,new TextDecoder().decode(E)},u=()=>{let y=[];for(;c<i.length;){let E=i[c++];if(E===0)break;let _=E&127;if(c+_>i.length)break;let S=i.slice(c,c+_);if(c+=_,y.push(Array.from(S).map(x=>x.toString(16).padStart(2,"0")).join("")),(E&128)===0)break}return y},f="unknown",p,m,h,g,w,b="";switch(a){case 0:{f="dns",p=d(),p&&(b=p.includes(":")&&!p.startsWith("[")?`tcp://${p}`:`tcp://${p}:53`);break}case 1:{f="dnscrypt",p=d(),c+=32,w=d(),b=`dnscrypt://${w||p}`;break}case 2:{f="doh",p=d(),g=u(),m=d(),h=d()||"/dns-query";let y=m||p;h.startsWith("/")||(h=`/${h}`),b=`https://${y}${h}`;break}case 3:{f="dot",p=d(),g=u(),m=d();let y=m||p,E=p&&p.includes(":")?p.split(":").pop():"853";b=y?.includes(":")?`tls://${y}`:`tls://${y}:${E}`;break}case 4:{f="doq",p=d(),g=u(),m=d(),b=`quic://${m||p}:853`;break}case 5:{f="odoh",p=d(),g=u(),m=d(),h=d()||"/dns-query",b=`https://${m||p}${h}`;break}default:b=e;break}return{protocol:f,protocolId:a,props:l,serverAddress:p||void 0,hostname:m||void 0,path:h||void 0,hashes:g&&g.length>0?g:void 0,providerName:w||void 0,resolvedUrl:b}}var bt=/^[a-zA-Z\d~`!@#$%^&*()_\-+={[}\]|\\:;"'<,>.?\/]{12,100}$/,Et=/^[a-z_][a-z0-9_-]{4,31}$/,Wo=/^[a-zA-Z0-9_-]{1,30}$/,jo=/^[a-zA-Z0-9_-]{1,30}$/;var Vo=/^[\p{L}\p{N}_ ()-]{1,30}$/u,Ft=/^[a-zA-Z0-9]{5,12}$/,Zi=/^\d{6}$/,Qi=["localhost","metadata.google.internal","metadata.goog","169.254.169.254","instance-data","localtest.me"],Ql=[".localhost",".local",".internal",".lan",".home.arpa",".corp",".home",".localtest.me"];function Zl(t){let e=t.match(/(?:^|\.)(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\.(?:nip\.io|sslip\.io)$/i);if(e)return e[1];let n=t.match(/(?:^|\.)(\d{1,3})-(\d{1,3})-(\d{1,3})-(\d{1,3})\.(?:nip\.io|sslip\.io)$/i);return n?`${n[1]}.${n[2]}.${n[3]}.${n[4]}`:null}var ql=["0.0.0.0/8","10.0.0.0/8","100.64.0.0/10","127.0.0.0/8","169.254.0.0/16","172.16.0.0/12","192.0.0.0/24","192.0.2.0/24","192.88.99.0/24","192.168.0.0/16","198.18.0.0/15","198.51.100.0/24","203.0.113.0/24","224.0.0.0/4","240.0.0.0/4","255.255.255.255/32","::/128","::1/128","64:ff9b::/96","100::/64","2001:db8::/32","fc00::/7","fe80::/10","ff00::/8"],Ko=Zr(ql);function hs(t){if(!t||typeof t!="string")return!1;let e=t.trim();if(e.startsWith("[")&&e.endsWith("]")&&(e=e.slice(1,-1)),e.includes(":")&&e.includes(".")){let r=e.lastIndexOf(":"),s=e.substring(r+1);return Zn(s)?!Ko(s):!1}if(!Zn(e)&&!Qr(e))return!1;let n=Qn(e);if(n!==null&&n>>32n===0xffffn){let r=Number(n&0xffffffffn),s=`${r>>>24&255}.${r>>>16&255}.${r>>>8&255}.${r&255}`;return!Ko(s)}return!Ko(e)}function ze(t){try{if(t.startsWith("sdns://")){let o=ms(t);return ze(o.resolvedUrl)}let e;t.startsWith("tcp://")||t.startsWith("udp://")?e=t.replace(/^(tcp|udp):\/\//,"http://"):t.startsWith("tls://")||t.startsWith("dot://")?e=t.replace(/^(tls|dot):\/\//,"http://"):t.startsWith("http://")||t.startsWith("https://")?e=t:e=`http://${t}`;let n=new URL(e),r=n.hostname.replace(/^\[|\]$/g,"").toLowerCase();if(Qi.includes(r)||Qi.includes(n.hostname.toLowerCase()))return!1;for(let o of Ql)if(r.endsWith(o)||r===o.slice(1))return!1;if(r.includes("metadata.google"))return!1;let s=Zl(r);return!(s&&!hs(s)||(Zn(r)||Qr(r))&&!hs(r)||n.hostname.includes("@")||n.username||n.password)}catch{return!1}}async function Jo(t){if(!(typeof navigator<"u"&&navigator.userAgent==="Cloudflare-Workers"||typeof WebSocketPair<"u")&&typeof process<"u"&&!!process.versions?.node){if(t.secureTransport==="on"){let s=await import("node:tls"),o=await import("node:net");return new Promise((i,c)=>{let a=s.connect({host:t.hostname,port:t.port,servername:o.isIP(t.hostname)?void 0:t.hostname},()=>{let l=!1,d=new ReadableStream({start(f){a.on("data",p=>{f.enqueue(new Uint8Array(p.buffer,p.byteOffset,p.byteLength))}),a.on("end",()=>{try{f.close()}catch{}}),a.on("error",p=>{try{f.error(p)}catch{}})},cancel(){l||(l=!0,a.destroy())}}),u=new WritableStream({write(f){return new Promise((p,m)=>{a.write(f,h=>h?m(h):p())})},close(){return new Promise(f=>{a.end(()=>f())})},abort(f){a.destroy(f)}});i({readable:d,writable:u,close:async()=>{l||(l=!0,a.destroy())}})});a.on("error",c)})}let r=await import("node:net");return new Promise((s,o)=>{let i=r.createConnection({host:t.hostname,port:t.port},()=>{let c=!1,a=new ReadableStream({start(d){i.on("data",u=>{d.enqueue(new Uint8Array(u.buffer,u.byteOffset,u.byteLength))}),i.on("end",()=>{try{d.close()}catch{}}),i.on("error",u=>{try{d.error(u)}catch{}})},cancel(){c||(c=!0,i.destroy())}}),l=new WritableStream({write(d){return new Promise((u,f)=>{i.write(d,p=>p?f(p):u())})},close(){return new Promise(d=>{i.end(()=>d())})},abort(d){i.destroy(d)}});s({readable:a,writable:l,close:async()=>{c||(c=!0,i.destroy())}})});i.on("error",o)})}try{return(await import("cloudflare:sockets")).connect({hostname:t.hostname,port:t.port},{secureTransport:t.secureTransport||"off",allowHalfOpen:!1})}catch(r){throw new Error(`Socket connection failed in current environment: ${r}`)}}var _n=class extends Error{constructor(n,r,s,o){super(`Upstream HTTP ${n}${r?` ${r}`:""}`);this.status=n;this.statusText=r;this.responseBodySnippet=s;this.cfRay=o;this.name="UpstreamHttpError"}status;statusText;responseBodySnippet;cfRay};async function qi(t,e=5e3){let n=[],r=0,s=null,o,i=new Promise((c,a)=>{o=setTimeout(()=>a(new Error("Upstream Socket Timeout")),e)});try{for(;;){let{value:c,done:a}=await Promise.race([t.read(),i]);if(a||!c)throw new Error("Socket closed before complete DNS response received");if(n.push(c),r+=c.length,r>65537)throw new Error("DNS upstream message exceeded maximum RFC frame length (65535 bytes)");if(s===null&&r>=2){let l=n[0][0],d=n[0].length>1?n[0][1]:n[1][0];s=l<<8|d}if(s!==null&&r>=2+s){let l=new Uint8Array(r),d=0;for(let u of n)l.set(u,d),d+=u.length;return l.slice(2,2+s)}}}finally{o!==void 0&&clearTimeout(o)}}function pr(t,e){let n=t,r=e;if(n.startsWith("[")){let s=n.indexOf("]");if(s!==-1){let o=n.slice(1,s),i=n.slice(s+1);n=o,i.startsWith(":")&&(r=parseInt(i.slice(1),10)||e)}}else if(n.includes(":")){let s=n.split(":");n=s[0],r=parseInt(s[1],10)||e}return{host:n,port:r}}function _t(t){let e=t;if(t.startsWith("sdns://")){let n=ms(t);if(n.protocol==="dnscrypt")throw new Error("DNSCrypt (0x01) protocol in DNS Stamp is not supported; please use DoH (0x02) or DoT (0x03) DNS Stamps");if(n.protocol==="doq"&&(e=n.resolvedUrl||`quic://${n.hostname||n.serverAddress}:853`),!n.resolvedUrl&&n.protocol!=="doq")throw new Error(`Unsupported DNS Stamp protocol: 0x${n.protocolId.toString(16)}`);n.protocol!=="doq"&&(e=n.resolvedUrl)}if(e.startsWith("dot://")&&(e=e.replace(/^dot:\/\//,"tls://")),e.startsWith("quic://")||e.startsWith("doq://")){let n=e.replace(/^(quic|doq):\/\//,""),{host:r,port:s}=pr(n,853);return{effectiveUrl:`tls://${r}:${s}`,diagMethod:"DoQ",diagTarget:`quic://${r}:${s}`}}if(e.startsWith("tls://")){let n=e.replace(/^tls:\/\//,""),{host:r,port:s}=pr(n,853);return{effectiveUrl:e,diagMethod:"DoT",diagTarget:`tls://${r}:${s}`}}if(!e.startsWith("http://")&&!e.startsWith("https://")){let n=e.replace(/^(tcp|udp):\/\//,""),{host:r,port:s}=pr(n,53);return{effectiveUrl:e,diagMethod:"TCP",diagTarget:`tcp://${r}:${s}`}}return{effectiveUrl:e,diagMethod:"POST",diagTarget:e}}async function St(t,e){let{effectiveUrl:n,diagMethod:r,diagTarget:s}=t,o=Date.now(),i;if(n.startsWith("tls://")||n.startsWith("dot://")){let a=n.replace(/^(tls|dot):\/\//,""),{host:l,port:d}=pr(a,853),u=await Jo({hostname:l,port:d,secureTransport:"on"});try{let f=u.writable.getWriter(),p=u.readable.getReader(),m=new Uint8Array(e.length+2);m[0]=e.length>>8&255,m[1]=e.length&255,m.set(e,2),await f.write(m),f.releaseLock(),i=await qi(p,5e3)}finally{await u.close().catch(()=>{})}}else if(!n.startsWith("http://")&&!n.startsWith("https://")){let a=n.replace(/^(tcp|udp):\/\//,""),{host:l,port:d}=pr(a,53),u=await Jo({hostname:l,port:d,secureTransport:"off"});try{let f=u.writable.getWriter(),p=u.readable.getReader(),m=new Uint8Array(e.length+2);m[0]=e.length>>8&255,m[1]=e.length&255,m.set(e,2),await f.write(m),f.releaseLock(),i=await qi(p,5e3)}finally{await u.close().catch(()=>{})}}else{let a=await fetch(n,{method:"POST",headers:{Accept:"application/dns-message","Content-Type":"application/dns-message","User-Agent":"Obex-DNS/1.0"},body:e,signal:AbortSignal.timeout(5e3)});if(!a.ok){let d="";try{d=(await a.text()).replace(/<[^>]*>?/gm," ").replace(/\s+/g," ").trim().slice(0,300)}catch{}let u=a.headers.get("cf-ray")||void 0;throw new _n(a.status,a.statusText,d,u)}let l=await a.arrayBuffer();i=new Uint8Array(l)}let c=Date.now()-o;return{answer:i,latency:c,diagMethod:r,diagTarget:s}}function ea(t,e,n){let r,s=e.raw;if(n.ecs?.enabled){let o=t.headers.get("CF-Connecting-IP")||"127.0.0.1";r=n.ecs.use_client_ip?`${o}/${o.includes(":")?48:24}`:e.type==="AAAA"?n.ecs.ipv6_cidr||n.ecs.ipv4_cidr:n.ecs.ipv4_cidr||n.ecs.ipv6_cidr,r&&(s=Io(e.raw,r))}return{queryRaw:s,ecs:r}}async function ta(t,e,n,r,s,o,i,c){let a=t.type==="HTTPS"||t.type==="SVCB"||t.type==="TYPE65"||t.type==="TYPE64",l=typeof s.best_effort_ech=="boolean"?s.best_effort_ech:!!s.best_effort_ech?.enabled,d=n,u=e,f=c;if(a){let p=(r.env.SERVERFULL_DOT_DOMAIN||r.env.DOT_DOMAIN||"").toLowerCase().trim(),m=t.name.toLowerCase().trim(),h=m.startsWith("_dns.")||!!(p&&(m===`_dns.${p}`||m.endsWith(`._dns.${p}`))),g=!!(p&&(m===p||m.endsWith(`.${p}`)));if(h||g){let w=r.env.SERVERFULL_ECH_FRONTING_DOMAIN||typeof s.best_effort_ech=="object"&&s.best_effort_ech?.fronting_domain||It,b=r.env.SERVERFULL_ECH_CONFIG||zn(w),y=r.env.SERVERFULL_HTTPS_PORT||r.env.HTTPS_PORT||10443,E=r.env.SERVERFULL_DOT_PORT||r.env.DOT_PORT||853;if(h){let _=t.type==="HTTPS"||t.type==="TYPE65"?"HTTPS":"SVCB",S=`1 . alpn=doq,dot port=${E} ech=${b}`;return d=Ee(t.raw,_,S,300,0),u=Ce(d),f="DDR SVCB (DoQ/DoT/H3/ECH)",{answer:d,parsedAnswers:u,effectiveReason:f}}if(g){let _=t.type==="SVCB"||t.type==="TYPE64"?"SVCB":"HTTPS",S=`1 . alpn=h3,h2 port=${y} ech=${b}`;return d=Ee(t.raw,_,S,300,0),u=Ce(d),f="Server HTTPS (H3/ECH)",{answer:d,parsedAnswers:u,effectiveReason:f}}}if(l){await ji(r.env.DB);let w=[],b=[],y;for(let _ of u){let S=_.data.match(/ipv4hint=([^\s]+)/);S&&w.push(...S[1].split(","));let x=_.data.match(/ipv6hint=([^\s]+)/);x&&b.push(...x[1].split(","));let T=_.data.match(/ech=([A-Za-z0-9+/=]+)/);T&&(y=T[1])}let E=w.some(es)||b.some(es);if(!E)try{let _=Ut(t.name,"A"),S=await i(o,{name:t.name,type:"A",raw:_},r,s,"PASS");if(S.answer&&S.answer.length>0){let x=Ce(S.answer);for(let T of x)T.type==="A"&&(w.push(T.data),es(T.data)&&(E=!0))}}catch(_){console.warn("Failed to probe A records for ECH check:",_)}if(E){let _=typeof s.best_effort_ech=="object"&&s.best_effort_ech?.fronting_domain?s.best_effort_ech.fronting_domain:It,S=zn(_,y),x=t.type==="SVCB"||t.type==="TYPE64"?"SVCB":"HTTPS",T=["alpn=h3,h2"];w.length>0&&T.push(`ipv4hint=${Array.from(new Set(w)).join(",")}`),T.push(`ech=${S}`),b.length>0&&T.push(`ipv6hint=${Array.from(new Set(b)).join(",")}`);let v=`1 . ${T.join(" ")}`;d=Ee(t.raw,x,v,300,0),u=Ce(d),f="ECH Rewritten"}}}return{answer:d,parsedAnswers:u,effectiveReason:f}}var ed=0;function fr(){let t=ed++%1e3;return Date.now()*1e3+t}var gs=class{constructor(e){this.db=e}db;createInsertStatement(e){let n=e.id??fr();return this.db.prepare("INSERT INTO logs (profile_id, timestamp, id, access_point_id, client_ip, geo_country, domain, record_type, action, reason, answer, dest_geoip, ecs, upstream, latency, dest_country_code, dest_country, dest_isp, encrypt_version, kem_key_id, encrypted_payload) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").bind(e.profile_id,e.timestamp,n,e.access_point_id||null,e.client_ip,e.geo_country||null,e.domain,e.record_type,e.action,e.reason||null,e.answer||null,e.dest_geoip||null,e.ecs||null,e.upstream||null,e.latency||null,e.dest_country_code||null,e.dest_country||null,e.dest_isp||null,e.encrypt_version??0,e.kem_key_id||null,e.encrypted_payload||null)}async insert(e){return(await this.createInsertStatement(e).run()).success}async getLogs(e,n){let r="";n.export?r=`
226
+ `).bind(e,e).first()||null}catch(t){return console.warn("[ProfileModel] findByKey D1 query failed:",t.message||t),null}}async list(e,t){let{results:r}=await this.db.prepare(`SELECT * FROM profiles ${e}`).bind(...t).all();return r}async listByOwner(e){let{results:t}=await this.db.prepare("SELECT * FROM profiles WHERE owner_id = ? ORDER BY created_at DESC").bind(e).all();return t}async findByName(e,t){return await this.db.prepare("SELECT * FROM profiles WHERE owner_id = ? AND name = ?").bind(e,t).first()}async create(e){let t=Math.floor(Date.now()/1e3),r=j(12),s=5;for(let o=0;o<s;o++){let i=$t(5),c=e.profile_key||i,a=[this.db.prepare("INSERT INTO profiles (id, profile_key, owner_id, name, settings, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)").bind(e.id,c,e.owner_id,e.name,JSON.stringify(e.settings),t,t),this.db.prepare("INSERT INTO access_points (id, profile_id, name, token, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)").bind(r,e.id,"Device-1",i,t,t)];try{return(await this.db.batch(a)).every(d=>d.success)}catch(l){if(o<s-1&&(String(l).includes("UNIQUE constraint failed")||String(l).includes("SQLITE_CONSTRAINT")))continue;throw l}}return!1}async delete(e){return(await this.db.batch([this.db.prepare("DELETE FROM logs WHERE profile_id = ?").bind(e),this.db.prepare("DELETE FROM profiles WHERE id = ?").bind(e)])).every(r=>r.success)}async deleteByOwner(e){return(await this.db.batch([this.db.prepare("DELETE FROM logs WHERE profile_id IN (SELECT id FROM profiles WHERE owner_id = ?)").bind(e),this.db.prepare("DELETE FROM profiles WHERE owner_id = ?").bind(e)])).every(r=>r.success)}async updateName(e,t){let r=Math.floor(Date.now()/1e3);return(await this.db.prepare("UPDATE profiles SET name = ?, updated_at = ? WHERE id = ?").bind(t,r,e).run()).success}async updateSettings(e,t){let r=Math.floor(Date.now()/1e3);return(await this.db.prepare("UPDATE profiles SET settings = ?, updated_at = ? WHERE id = ?").bind(JSON.stringify(t),r,e).run()).success}async rotateKey(e,t){let r=Math.floor(Date.now()/1e3);return(await this.db.prepare("UPDATE profiles SET profile_key = ?, updated_at = ? WHERE id = ?").bind(t,r,e).run()).success}async updateLastActive(e,t){return(await this.db.prepare("UPDATE profiles SET last_active_at = ? WHERE id = ?").bind(t,e).run()).success}async getSyncTargets(e,t){let{results:r}=await this.db.prepare("SELECT id FROM profiles WHERE (list_updated_at IS NULL OR list_updated_at <= ?) AND EXISTS (SELECT 1 FROM lists WHERE lists.profile_id = profiles.id) ORDER BY list_updated_at ASC LIMIT ?").bind(e,t).all();return r}async updateListUpdatedAt(e,t){return(await this.db.prepare("UPDATE profiles SET list_updated_at = ? WHERE id = ?").bind(t,e).run()).success}};var An=class{constructor(e){this.db=e}db;async getRules(e){let{results:t}=await this.db.prepare("SELECT * FROM rules WHERE profile_id = ? ORDER BY id DESC").bind(e).all();return t}async addRule(e,t){let r=t.pattern?t.pattern.trim().toLowerCase():"",s=t.created_at??Math.floor(Date.now()/1e3);return(await this.db.prepare("INSERT INTO rules (profile_id, type, pattern, v_a, v_aaaa, v_txt, v_cname, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").bind(e,t.type,r,t.v_a||null,t.v_aaaa||null,t.v_txt||null,t.v_cname||null,s).run()).success}async addRulesBulk(e,t){if(!t||t.length===0)return 0;let r=Math.floor(Date.now()/1e3),s=t.map(i=>{let c=i.pattern?i.pattern.trim().toLowerCase():"",a=i.created_at??r;return this.db.prepare("INSERT INTO rules (profile_id, type, pattern, v_a, v_aaaa, v_txt, v_cname, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").bind(e,i.type,c,i.v_a||null,i.v_aaaa||null,i.v_txt||null,i.v_cname||null,a)}),o=0;for(let i=0;i<s.length;i+=100){let c=s.slice(i,i+100),a=await this.db.batch(c);for(let l of a)l.success&&(o+=l.meta.changes||1)}return o}async updateRule(e,t,r){let s=r.pattern?r.pattern.trim().toLowerCase():"";return(await this.db.prepare("UPDATE rules SET type = ?, pattern = ?, v_a = ?, v_aaaa = ?, v_txt = ?, v_cname = ? WHERE id = ? AND profile_id = ?").bind(r.type,s,r.v_a||null,r.v_aaaa||null,r.v_txt||null,r.v_cname||null,e,t).run()).success}async getRuleByPattern(e,t){return await this.db.prepare("SELECT * FROM rules WHERE profile_id = ? AND LOWER(pattern) = ?").bind(e,t.trim().toLowerCase()).first()}async getRuleByPatternExcludeId(e,t,r){return await this.db.prepare("SELECT * FROM rules WHERE profile_id = ? AND LOWER(pattern) = ? AND id != ?").bind(e,t.trim().toLowerCase(),r).first()}async deleteRule(e,t){return(await this.db.prepare("DELETE FROM rules WHERE id = ? AND profile_id = ?").bind(e,t).run()).success}};var xe=class n{size;hashes;bitArray;static FNV_PRIME=16777619;static FNV_SEED_0=2166136261;static encoder=new TextEncoder;constructor(e,t,r){this.size=e>>>0,this.hashes=t>>>0;let s=this.size+31>>>5;this.bitArray=r||new Uint32Array(s)}static create(e,t=1e-4){let r=Math.max(e,100),o=Math.ceil(-(r*Math.log(t))/Math.log(2)**2),i=Math.round(o/r*Math.log(2));return new n(o,i)}add(e){let t=n.FNV_SEED_0,r=e.length;for(let a=0;a<r;a++)t^=e.charCodeAt(a)&255,t=Math.imul(t,n.FNV_PRIME);t=t>>>0;let s=t^t>>>16;s=Math.imul(s,2246822507),s=s^s>>>13,s=Math.imul(s,3266489909),s=(s^s>>>16)>>>0;let o=this.bitArray,i=this.size,c=this.hashes;for(let a=0;a<c;a++){let l=(t+a*s)%i;o[l>>>5]|=1<<(l&31)}}test(e){let t=n.FNV_SEED_0,r=e.length;for(let a=0;a<r;a++)t^=e.charCodeAt(a)&255,t=Math.imul(t,n.FNV_PRIME);t=t>>>0;let s=t^t>>>16;s=Math.imul(s,2246822507),s=s^s>>>13,s=Math.imul(s,3266489909),s=(s^s>>>16)>>>0;let o=this.bitArray,i=this.size,c=this.hashes;for(let a=0;a<c;a++){let l=(t+a*s)%i;if((o[l>>>5]&1<<(l&31))===0)return!1}return!0}toUint8Array(){let e=new Uint8Array(8+this.bitArray.byteLength),t=new DataView(e.buffer);return t.setUint32(0,this.size,!0),t.setUint32(4,this.hashes,!0),e.set(new Uint8Array(this.bitArray.buffer,this.bitArray.byteOffset,this.bitArray.byteLength),8),e}static fromUint8Array(e){if(!e||e.byteLength<8)throw new Error("Invalid bloom filter buffer: header too short");let t=new DataView(e.buffer,e.byteOffset,8),r=t.getUint32(0,!0),s=t.getUint32(4,!0);if(r===0||s===0)throw new Error("Invalid bloom filter parameters: size and hashes must be positive integers");let o=e.byteOffset+8,i=e.byteLength-8,c=r+31>>>5,a=i>>2;if(a<c)throw new Error(`Invalid bloom filter buffer: bit array truncated (expected ${c} words, got ${a})`);let l;if(o%4===0)l=new Uint32Array(e.buffer,o,c);else{let d=new Uint8Array(c<<2);d.set(e.subarray(8,8+(c<<2))),l=new Uint32Array(d.buffer,0,c)}return new n(r,s,l)}merge(e){if(this.size!==e.size||this.hashes!==e.hashes)throw new Error("Cannot merge bloom filters with different sizes or hash counts.");let t=this.bitArray,r=e.bitArray,s=t.length;for(let o=0;o<s;o++)t[o]|=r[o]}fnv1a(e,t){let r=t>>>0;for(let s=0;s<e.length;s++)r^=e[s],r=Math.imul(r,n.FNV_PRIME);return r>>>0}fnv1aString(e,t){let r=t>>>0,s=e.length;for(let o=0;o<s;o++)r^=e.charCodeAt(o)&255,r=Math.imul(r,n.FNV_PRIME);return r>>>0}dump(){let e=new Uint8Array(this.bitArray.buffer,this.bitArray.byteOffset,this.bitArray.byteLength),t="",r=e.byteLength,s=32768;for(let o=0;o<r;o+=s)t+=String.fromCharCode.apply(null,e.subarray(o,Math.min(o+s,r)));return{size:this.size,hashes:this.hashes,data:btoa(t)}}static load(e){let t=atob(e.data),r=new Uint8Array(t.length);for(let i=0;i<t.length;i++)r[i]=t.charCodeAt(i);let s=r.length+3>>2,o=new Uint32Array(s);return new Uint8Array(o.buffer).set(r),new n(e.size,e.hashes,o)}};var _t=class{constructor(e){this.db=e}db;async clearProfileBlooms(e){return(await this.db.prepare("DELETE FROM profile_blooms WHERE profile_id = ?").bind(e).run()).success}async upsertProfileBloom(e,t,r){let s=new Uint8Array(t),o=[];o.push(this.db.prepare("DELETE FROM profile_blooms WHERE profile_id = ?").bind(e));let i=0;for(let a=0;a<s.length;a+=1572864){let l=s.slice(a,a+1572864).buffer;o.push(this.db.prepare("INSERT INTO profile_blooms (profile_id, chunk_index, bloom_filter_chunk, updated_at) VALUES (?, ?, ?, ?)").bind(e,i,l,r)),i++}return(await this.db.batch(o)).every(a=>a.success)}async getProfileBloom(e){let{results:t}=await this.db.prepare("SELECT bloom_filter_chunk FROM profile_blooms WHERE profile_id = ? ORDER BY chunk_index ASC").bind(e).all();if(!t||t.length===0)return null;let r=t.reduce((i,c)=>{let a=c.bloom_filter_chunk.byteLength??c.bloom_filter_chunk.length;return i+a},0),s=new Uint8Array(r),o=0;for(let i of t){let c=new Uint8Array(i.bloom_filter_chunk);s.set(c,o),o+=c.length}return s.buffer}async initializeStagingBloom(e,t,r,s){let i=xe.create(t,r).toUint8Array();return this.upsertStagingBloom(e,i.buffer,s)}async clearStagingBloom(e){return(await this.db.prepare("DELETE FROM profile_blooms_staging WHERE profile_id = ?").bind(e).run()).success}async upsertStagingBloom(e,t,r){let s=new Uint8Array(t),o=[];o.push(this.db.prepare("DELETE FROM profile_blooms_staging WHERE profile_id = ?").bind(e));let i=0;for(let a=0;a<s.length;a+=1572864){let l=s.slice(a,a+1572864).buffer;o.push(this.db.prepare("INSERT INTO profile_blooms_staging (profile_id, chunk_index, bloom_filter_chunk, updated_at) VALUES (?, ?, ?, ?)").bind(e,i,l,r)),i++}return(await this.db.batch(o)).every(a=>a.success)}async getStagingBloom(e){let{results:t}=await this.db.prepare("SELECT bloom_filter_chunk FROM profile_blooms_staging WHERE profile_id = ? ORDER BY chunk_index ASC").bind(e).all();if(!t||t.length===0)return null;let r=t.reduce((i,c)=>{let a=c.bloom_filter_chunk.byteLength??c.bloom_filter_chunk.length;return i+a},0),s=new Uint8Array(r),o=0;for(let i of t){let c=new Uint8Array(i.bloom_filter_chunk);s.set(c,o),o+=c.length}return s.buffer}async promoteStagingToActive(e,t){let{results:r}=await this.db.prepare("SELECT chunk_index, bloom_filter_chunk FROM profile_blooms_staging WHERE profile_id = ? ORDER BY chunk_index ASC").bind(e).all();if(!r||r.length===0)return await this.clearProfileBlooms(e),!0;let s=[this.db.prepare("DELETE FROM profile_blooms WHERE profile_id = ?").bind(e),...r.map(i=>this.db.prepare("INSERT INTO profile_blooms (profile_id, chunk_index, bloom_filter_chunk, updated_at) VALUES (?, ?, ?, ?)").bind(e,i.chunk_index,i.bloom_filter_chunk,t)),this.db.prepare("DELETE FROM profile_blooms_staging WHERE profile_id = ?").bind(e)];return(await this.db.batch(s)).every(i=>i.success)}};ge();var na={async load(n,e){let{profileId:t,env:r,ctx:s}=n,o=ar.get(t),i=cr.get(t),c=Number(r.BLOOM_MEM_TTL)||6e5;if(i&&Date.now()-(i.timestamp||0)<3e5){e("load_config_l1_mem");let m=o&&Date.now()-o.ts<c?o.bloom:void 0;return{...i,bloom:m}}let l=caches.default,d=`profile_v6:${t}`,u=`https://obex.local/bloom-bin/${t}`,f=await P.get(l,d),p;if(f){if(e("load_config_l2_cache"),o&&Date.now()-o.ts<c)p=o.bloom;else try{let m=await l.match(u);if(m){e("load_bloom_l2_cache");let h=await m.arrayBuffer();p=xe.fromUint8Array(new Uint8Array(h)),ar.set(t,{bloom:p,ts:Date.now()})}}catch{}return cr.set(t,{...f,timestamp:Date.now()}),{...f,bloom:p}}try{let m=new q(r.DB),h=new An(r.DB),g=new _t(r.DB),[b,w,y]=await Promise.all([m.getById(t),h.getRules(t),g.getProfileBloom(t).catch(S=>(console.error("[Config] D1 Bloom loading failed:",S),null))]);if(!b)return i?(console.warn(`[Config] Profile ${t} not in D1, using stale memory config.`),{...i,bloom:o?.bloom}):null;let E=JSON.parse(b.settings);if(y){e("load_bloom_l3_d1");let S=new Uint8Array(y);p=xe.fromUint8Array(S),s.waitUntil(l.put(u,new Response(S,{headers:{"Content-Type":"application/octet-stream","Cache-Control":"public, max-age=604800","Cache-Tag":`bloom-${t}`}})))}let _={settings:E,rules:w};return p&&ar.set(t,{bloom:p,ts:Date.now()}),cr.set(t,{..._,timestamp:Date.now()}),s.waitUntil(P.set(l,d,_,86400,[`profile-${t}`])),e("load_config_full_sync"),{..._,bloom:p}}catch(m){return console.warn(`[Config] D1 profile fetch failed for ${t}:`,m?.message||m),i?(console.warn(`[Config] Serving stale config from memory for profile ${t}`),{...i,bloom:o?.bloom}):(console.warn(`[Config] Serving emergency fail-open safe fallback for profile ${t}`),{settings:{upstream:[r.FAIL_OPEN_UPSTREAM||"https://freedns.controld.com/no-ads-malware-typo"],default_policy:"ALLOW",log_retention_days:0,ecs:{enabled:!0,use_client_ip:!0}},rules:[],bloom:void 0})}}};function wr(n){let e=n.trim();if(!e.startsWith("sdns://"))throw new Error("Invalid DNS Stamp: must start with sdns://");let t=e.slice(7),r=t.length;for(;r>0&&t.charCodeAt(r-1)===61;)r--;let s=t.slice(0,r),o;if(typeof Buffer<"u")o=Buffer.from(s,"base64url").toString("latin1");else{let y=s.replace(/-/g,"+").replace(/_/g,"/"),E=y.length%4,_=E?y+"=".repeat(4-E):y;o=atob(_)}let i=new Uint8Array(o.length);for(let y=0;y<o.length;y++)i[y]=o.charCodeAt(y);if(i.length<9)throw new Error("DNS Stamp payload too short (minimum 9 bytes)");let c=0,a=i[c++],l=0n;for(let y=0;y<8;y++)l|=BigInt(i[c++])<<BigInt(y*8);let d=()=>{if(c>=i.length)return"";let y=i[c++];if(c+y>i.length)return"";let E=i.slice(c,c+y);return c+=y,new TextDecoder().decode(E)},u=()=>{let y=[];for(;c<i.length;){let E=i[c++];if(E===0)break;let _=E&127;if(c+_>i.length)break;let S=i.slice(c,c+_);if(c+=_,y.push(Array.from(S).map(x=>x.toString(16).padStart(2,"0")).join("")),(E&128)===0)break}return y},f="unknown",p,m,h,g,b,w="";switch(a){case 0:{f="dns",p=d(),p&&(w=p.includes(":")&&!p.startsWith("[")?`tcp://${p}`:`tcp://${p}:53`);break}case 1:{f="dnscrypt",p=d(),c+=32,b=d(),w=`dnscrypt://${b||p}`;break}case 2:{f="doh",p=d(),g=u(),m=d(),h=d()||"/dns-query";let y=m||p;h.startsWith("/")||(h=`/${h}`),w=`https://${y}${h}`;break}case 3:{f="dot",p=d(),g=u(),m=d();let y=m||p,E=p&&p.includes(":")?p.split(":").pop():"853";w=y?.includes(":")?`tls://${y}`:`tls://${y}:${E}`;break}case 4:{f="doq",p=d(),g=u(),m=d(),w=`quic://${m||p}:853`;break}case 5:{f="odoh",p=d(),g=u(),m=d(),h=d()||"/dns-query",w=`https://${m||p}${h}`;break}default:w=e;break}return{protocol:f,protocolId:a,props:l,serverAddress:p||void 0,hostname:m||void 0,path:h||void 0,hashes:g&&g.length>0?g:void 0,providerName:b||void 0,resolvedUrl:w}}var St=/^[a-zA-Z\d~`!@#$%^&*()_\-+={[}\]|\\:;"'<,>.?\/]{12,100}$/,Rt=/^[a-z_][a-z0-9_-]{4,31}$/,zo=/^[a-zA-Z0-9_-]{1,30}$/,Xo=/^[a-zA-Z0-9_-]{1,30}$/;var Qo=/^[\p{L}\p{N}_ ()-]{1,30}$/u,Wt=/^[a-zA-Z0-9]{5,12}$/,sa=/^\d{6}$/,ra=["localhost","metadata.google.internal","metadata.goog","169.254.169.254","instance-data","localtest.me"],id=[".localhost",".local",".internal",".lan",".home.arpa",".corp",".home",".localtest.me"];function ad(n){let e=n.match(/(?:^|\.)(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\.(?:nip\.io|sslip\.io)$/i);if(e)return e[1];let t=n.match(/(?:^|\.)(\d{1,3})-(\d{1,3})-(\d{1,3})-(\d{1,3})\.(?:nip\.io|sslip\.io)$/i);return t?`${t[1]}.${t[2]}.${t[3]}.${t[4]}`:null}var cd=["0.0.0.0/8","10.0.0.0/8","100.64.0.0/10","127.0.0.0/8","169.254.0.0/16","172.16.0.0/12","192.0.0.0/24","192.0.2.0/24","192.88.99.0/24","192.168.0.0/16","198.18.0.0/15","198.51.100.0/24","203.0.113.0/24","224.0.0.0/4","240.0.0.0/4","255.255.255.255/32","::/128","::1/128","64:ff9b::/96","100::/64","2001:db8::/32","fc00::/7","fe80::/10","ff00::/8"],Yo=is(cd);function qe(n){if(!n||typeof n!="string")return!1;let e=n.trim();if(e.startsWith("[")&&e.endsWith("]")&&(e=e.slice(1,-1)),e.includes(":")&&e.includes(".")){let r=e.lastIndexOf(":"),s=e.substring(r+1);return st(s)?!Yo(s):!1}if(!st(e)&&!Ft(e))return!1;let t=sr(e);if(t!==null&&t>>32n===0xffffn){let r=Number(t&0xffffffffn),s=`${r>>>24&255}.${r>>>16&255}.${r>>>8&255}.${r&255}`;return!Yo(s)}return!Yo(e)}function at(n){try{if(n.startsWith("sdns://")){let o=wr(n);return at(o.resolvedUrl)}let e;n.startsWith("tcp://")||n.startsWith("udp://")?e=n.replace(/^(tcp|udp):\/\//,"http://"):n.startsWith("tls://")||n.startsWith("dot://")?e=n.replace(/^(tls|dot):\/\//,"http://"):n.startsWith("http://")||n.startsWith("https://")?e=n:e=`http://${n}`;let t=new URL(e),r=t.hostname.replace(/^\[|\]$/g,"").toLowerCase();if(ra.includes(r)||ra.includes(t.hostname.toLowerCase()))return!1;for(let o of id)if(r.endsWith(o)||r===o.slice(1))return!1;if(r.includes("metadata.google"))return!1;let s=ad(r);return!(s&&!qe(s)||(st(r)||Ft(r))&&!qe(r)||t.hostname.includes("@")||t.username||t.password)}catch{return!1}}async function oa(n){if(!at(n))return!1;if(typeof process<"u"&&process.versions?.node)try{let e=n;n.startsWith("sdns://")&&(e=wr(n).resolvedUrl);let t;e.startsWith("tcp://")||e.startsWith("udp://")?t=e.replace(/^(tcp|udp):\/\//,"http://"):e.startsWith("tls://")||e.startsWith("dot://")?t=e.replace(/^(tls|dot):\/\//,"http://"):e.startsWith("http://")||e.startsWith("https://")?t=e:t=`http://${e}`;let s=new URL(t).hostname.replace(/^\[|\]$/g,"").toLowerCase();if(st(s)||Ft(s))return!0;let i=await(await import("node:dns/promises")).lookup(s,{all:!0});if(!i||i.length===0)return!1;for(let c of i)if(!qe(c.address))return!1}catch{return!1}return!0}async function Zo(n){if(!(typeof navigator<"u"&&navigator.userAgent==="Cloudflare-Workers"||typeof WebSocketPair<"u")&&typeof process<"u"&&!!process.versions?.node){if(n.secureTransport==="on"){let s=await import("node:tls"),o=await import("node:net");return new Promise((i,c)=>{let a=s.connect({host:n.hostname,port:n.port,servername:o.isIP(n.hostname)?void 0:n.hostname},()=>{let l=!1,d=new ReadableStream({start(f){a.on("data",p=>{f.enqueue(new Uint8Array(p.buffer,p.byteOffset,p.byteLength))}),a.on("end",()=>{try{f.close()}catch{}}),a.on("error",p=>{try{f.error(p)}catch{}})},cancel(){l||(l=!0,a.destroy())}}),u=new WritableStream({write(f){return new Promise((p,m)=>{a.write(f,h=>h?m(h):p())})},close(){return new Promise(f=>{a.end(()=>f())})},abort(f){a.destroy(f)}});i({readable:d,writable:u,close:async()=>{l||(l=!0,a.destroy())}})});a.on("error",c)})}let r=await import("node:net");return new Promise((s,o)=>{let i=r.createConnection({host:n.hostname,port:n.port},()=>{let c=!1,a=new ReadableStream({start(d){i.on("data",u=>{d.enqueue(new Uint8Array(u.buffer,u.byteOffset,u.byteLength))}),i.on("end",()=>{try{d.close()}catch{}}),i.on("error",u=>{try{d.error(u)}catch{}})},cancel(){c||(c=!0,i.destroy())}}),l=new WritableStream({write(d){return new Promise((u,f)=>{i.write(d,p=>p?f(p):u())})},close(){return new Promise(d=>{i.end(()=>d())})},abort(d){i.destroy(d)}});s({readable:a,writable:l,close:async()=>{c||(c=!0,i.destroy())}})});i.on("error",o)})}try{return(await import("cloudflare:sockets")).connect({hostname:n.hostname,port:n.port},{secureTransport:n.secureTransport||"off",allowHalfOpen:!1})}catch(r){throw new Error(`Socket connection failed in current environment: ${r}`)}}var vn=class extends Error{constructor(t,r,s,o){super(`Upstream HTTP ${t}${r?` ${r}`:""}`);this.status=t;this.statusText=r;this.responseBodySnippet=s;this.cfRay=o;this.name="UpstreamHttpError"}status;statusText;responseBodySnippet;cfRay};async function ia(n,e=5e3){let t=[],r=0,s=null,o,i=new Promise((c,a)=>{o=setTimeout(()=>a(new Error("Upstream Socket Timeout")),e)});try{for(;;){let{value:c,done:a}=await Promise.race([n.read(),i]);if(a||!c)throw new Error("Socket closed before complete DNS response received");if(t.push(c),r+=c.length,r>65537)throw new Error("DNS upstream message exceeded maximum RFC frame length (65535 bytes)");if(s===null&&r>=2){let l=t[0][0],d=t[0].length>1?t[0][1]:t[1][0];s=l<<8|d}if(s!==null&&r>=2+s){let l=new Uint8Array(r),d=0;for(let u of t)l.set(u,d),d+=u.length;return l.slice(2,2+s)}}}finally{o!==void 0&&clearTimeout(o)}}function br(n,e){let t=n,r=e;if(t.startsWith("[")){let s=t.indexOf("]");if(s!==-1){let o=t.slice(1,s),i=t.slice(s+1);t=o,i.startsWith(":")&&(r=parseInt(i.slice(1),10)||e)}}else if(t.includes(":")){let s=t.split(":");t=s[0],r=parseInt(s[1],10)||e}return{host:t,port:r}}function Tt(n){let e=n;if(n.startsWith("sdns://")){let t=wr(n);if(t.protocol==="dnscrypt")throw new Error("DNSCrypt (0x01) protocol in DNS Stamp is not supported; please use DoH (0x02) or DoT (0x03) DNS Stamps");if(t.protocol==="doq"&&(e=t.resolvedUrl||`quic://${t.hostname||t.serverAddress}:853`),!t.resolvedUrl&&t.protocol!=="doq")throw new Error(`Unsupported DNS Stamp protocol: 0x${t.protocolId.toString(16)}`);t.protocol!=="doq"&&(e=t.resolvedUrl)}if(e.startsWith("dot://")&&(e=e.replace(/^dot:\/\//,"tls://")),e.startsWith("quic://")||e.startsWith("doq://")){let t=e.replace(/^(quic|doq):\/\//,""),{host:r,port:s}=br(t,853);return{effectiveUrl:`tls://${r}:${s}`,diagMethod:"DoQ",diagTarget:`quic://${r}:${s}`}}if(e.startsWith("tls://")){let t=e.replace(/^tls:\/\//,""),{host:r,port:s}=br(t,853);return{effectiveUrl:e,diagMethod:"DoT",diagTarget:`tls://${r}:${s}`}}if(!e.startsWith("http://")&&!e.startsWith("https://")){let t=e.replace(/^(tcp|udp):\/\//,""),{host:r,port:s}=br(t,53);return{effectiveUrl:e,diagMethod:"TCP",diagTarget:`tcp://${r}:${s}`}}return{effectiveUrl:e,diagMethod:"POST",diagTarget:e}}async function xt(n,e){let{effectiveUrl:t,diagMethod:r,diagTarget:s}=n,o=Date.now(),i;if(t.startsWith("tls://")||t.startsWith("dot://")){let a=t.replace(/^(tls|dot):\/\//,""),{host:l,port:d}=br(a,853),u=await Zo({hostname:l,port:d,secureTransport:"on"});try{let f=u.writable.getWriter(),p=u.readable.getReader(),m=new Uint8Array(e.length+2);m[0]=e.length>>8&255,m[1]=e.length&255,m.set(e,2),await f.write(m),f.releaseLock(),i=await ia(p,5e3)}finally{await u.close().catch(()=>{})}}else if(!t.startsWith("http://")&&!t.startsWith("https://")){let a=t.replace(/^(tcp|udp):\/\//,""),{host:l,port:d}=br(a,53),u=await Zo({hostname:l,port:d,secureTransport:"off"});try{let f=u.writable.getWriter(),p=u.readable.getReader(),m=new Uint8Array(e.length+2);m[0]=e.length>>8&255,m[1]=e.length&255,m.set(e,2),await f.write(m),f.releaseLock(),i=await ia(p,5e3)}finally{await u.close().catch(()=>{})}}else{let a=await fetch(t,{method:"POST",headers:{Accept:"application/dns-message","Content-Type":"application/dns-message","User-Agent":"Obex-DNS/1.0"},body:e,signal:AbortSignal.timeout(5e3)});if(!a.ok){let d="";try{d=(await a.text()).replace(/<[^>]*>?/gm," ").replace(/\s+/g," ").trim().slice(0,300)}catch{}let u=a.headers.get("cf-ray")||void 0;throw new vn(a.status,a.statusText,d,u)}let l=await a.arrayBuffer();i=new Uint8Array(l)}let c=Date.now()-o;return{answer:i,latency:c,diagMethod:r,diagTarget:s}}function aa(n,e,t){let r,s=e.raw;if(t.ecs?.enabled){let o=n.headers.get("CF-Connecting-IP")||"127.0.0.1";r=t.ecs.use_client_ip?`${o}/${o.includes(":")?48:24}`:e.type==="AAAA"?t.ecs.ipv6_cidr||t.ecs.ipv4_cidr:t.ecs.ipv4_cidr||t.ecs.ipv6_cidr,r&&(s=$o(e.raw,r))}return{queryRaw:s,ecs:r}}async function ca(n,e,t,r,s,o,i,c){let a=n.type==="HTTPS"||n.type==="SVCB"||n.type==="TYPE65"||n.type==="TYPE64",l=typeof s.best_effort_ech=="boolean"?s.best_effort_ech:!!s.best_effort_ech?.enabled,d=t,u=e,f=c;if(a){let p=(r.env.SERVERFULL_DOT_DOMAIN||r.env.DOT_DOMAIN||"").toLowerCase().trim(),m=n.name.toLowerCase().trim(),h=m.startsWith("_dns.")||!!(p&&(m===`_dns.${p}`||m.endsWith(`._dns.${p}`))),g=!!(p&&(m===p||m.endsWith(`.${p}`)));if(h||g){let b=r.env.SERVERFULL_ECH_FRONTING_DOMAIN||typeof s.best_effort_ech=="object"&&s.best_effort_ech?.fronting_domain||Bt,w=r.env.SERVERFULL_ECH_CONFIG||rr(b),y=r.env.SERVERFULL_HTTPS_PORT||r.env.HTTPS_PORT||10443,E=r.env.SERVERFULL_DOT_PORT||r.env.DOT_PORT||853;if(h){let _=n.type==="HTTPS"||n.type==="TYPE65"?"HTTPS":"SVCB",S=`1 . alpn=doq,dot port=${E} ech=${w}`;return d=Ee(n.raw,_,S,300,0),u=ke(d),f="DDR SVCB (DoQ/DoT/H3/ECH)",{answer:d,parsedAnswers:u,effectiveReason:f}}if(g){let _=n.type==="SVCB"||n.type==="TYPE64"?"SVCB":"HTTPS",S=`1 . alpn=h3,h2 port=${y} ech=${w}`;return d=Ee(n.raw,_,S,300,0),u=ke(d),f="Server HTTPS (H3/ECH)",{answer:d,parsedAnswers:u,effectiveReason:f}}}if(l){await Xi(r.env.DB);let b=[],w=[],y;for(let _ of u){let S=_.data.match(/ipv4hint=([^\s]+)/);S&&b.push(...S[1].split(","));let x=_.data.match(/ipv6hint=([^\s]+)/);x&&w.push(...x[1].split(","));let T=_.data.match(/ech=([A-Za-z0-9+/=]+)/);T&&(y=T[1])}let E=b.some(cs)||w.some(cs);if(!E)try{let _=Ht(n.name,"A"),S=await i(o,{name:n.name,type:"A",raw:_},r,s,"PASS");if(S.answer&&S.answer.length>0){let x=ke(S.answer);for(let T of x)T.type==="A"&&(b.push(T.data),cs(T.data)&&(E=!0))}}catch(_){console.warn("Failed to probe A records for ECH check:",_)}if(E){let _=typeof s.best_effort_ech=="object"&&s.best_effort_ech?.fronting_domain?s.best_effort_ech.fronting_domain:Bt,S=rr(_,y),x=n.type==="SVCB"||n.type==="TYPE64"?"SVCB":"HTTPS",T=["alpn=h3,h2"];b.length>0&&T.push(`ipv4hint=${Array.from(new Set(b)).join(",")}`),T.push(`ech=${S}`),w.length>0&&T.push(`ipv6hint=${Array.from(new Set(w)).join(",")}`);let v=`1 . ${T.join(" ")}`;d=Ee(n.raw,x,v,300,0),u=ke(d),f="ECH Rewritten"}}}return{answer:d,parsedAnswers:u,effectiveReason:f}}ge();var jt=new Map,la=336*60*60*1e3;async function Er(n){if(!qe(n))return null;let e=`geoip:${n}`,t=Date.now(),r=jt.get(e);if(r){if(t<r.expiresAt)return r.data;jt.delete(e)}let s=null;if(typeof caches<"u"&&caches.default&&(s=caches.default),s)try{let i=await P.get(s,e);if(i)return jt.set(e,{data:i,expiresAt:t+la}),i}catch(i){console.warn("Cloudflare Cache API read error, falling back to memory/network:",i)}let o=async i=>{if(jt.size>=1e5){let c=jt.keys().next().value;c!==void 0&&jt.delete(c)}if(jt.set(e,{data:i,expiresAt:t+la}),s)try{await P.set(s,e,i,86400*14)}catch(c){console.warn("Cloudflare Cache API write error:",c)}};try{let i=await fetch(`http://ip-api.com/json/${n}?fields=status,country,countryCode,regionName,city,isp,org,as,timezone`,{cf:{cacheTtlByStatus:{"200-299":1209600,"400-499":5,"500-599":0},cacheEverything:!0}});if(i.ok){let c=await i.json();if(c.status==="success"){let a={country:c.country,country_code:c.countryCode,region:c.regionName,city:c.city,isp:c.isp,org:c.org,as:c.as,timezone:c.timezone};return await o(a),a}}}catch{}try{let i=await fetch(`https://ipwho.is/${n}`);if(i.ok){let c=await i.json();if(c.success){let a={country:c.country,country_code:c.country_code,region:c.region,city:c.city,isp:c.connection?.isp,org:c.connection?.org,as:c.connection?.asn?`AS${c.connection.asn} ${c.connection?.org||""}`.trim():void 0,timezone:c.timezone?.id};return await o(a),a}}}catch(i){console.error("GeoIP Fetch Error:",i)}return null}async function Vt(n,e){let t=n.cf?.country||n.headers.get("CF-IPCountry");if(t&&t!=="UN"&&t!=="UNKNOWN"&&t!=="XX")return t.toUpperCase();if(!qe(e))return"LAN";try{let r=await Er(e);if(r?.country_code)return r.country_code.toUpperCase()}catch{}return"UNKNOWN"}var ld=0;function _r(){let n=ld++%1e3;return Date.now()*1e3+n}var Ss=class{constructor(e){this.db=e}db;createInsertStatement(e){let t=e.id??_r();return this.db.prepare("INSERT INTO logs (profile_id, timestamp, id, access_point_id, client_ip, geo_country, domain, record_type, action, reason, answer, dest_geoip, ecs, upstream, latency, dest_country_code, dest_country, dest_isp, encrypt_version, kem_key_id, encrypted_payload) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").bind(e.profile_id,e.timestamp,t,e.access_point_id||null,e.client_ip,e.geo_country||null,e.domain,e.record_type,e.action,e.reason||null,e.answer||null,e.dest_geoip||null,e.ecs||null,e.upstream||null,e.latency||null,e.dest_country_code||null,e.dest_country||null,e.dest_isp||null,e.encrypt_version??0,e.kem_key_id||null,e.encrypted_payload||null)}async insert(e){return(await this.createInsertStatement(e).run()).success}async getLogs(e,t){let r="";t.export?r=`
227
227
  SELECT l.profile_id, l.access_point_id, l.timestamp, l.client_ip, l.geo_country, l.domain, l.record_type, l.action, l.reason, l.answer, l.dest_geoip, l.ecs, l.upstream, l.latency, l.dest_country_code, l.dest_country, l.dest_isp, l.encrypt_version, l.kem_key_id, l.encrypted_payload, k.kem_ct
228
228
  FROM logs l
229
229
  LEFT JOIN kem_keys k ON l.kem_key_id = k.id
@@ -232,14 +232,14 @@ SQL: ${this.sql}`),n}}},xo=class{constructor(e){this.rawDb=e}rawDb;prepare(e){re
232
232
  FROM logs l
233
233
  LEFT JOIN access_points ap ON l.access_point_id = ap.id
234
234
  LEFT JOIN kem_keys k ON l.kem_key_id = k.id
235
- `;let s=["l.profile_id = ?"],o=[e];n.access_point_id&&(s.push("l.access_point_id = ?"),o.push(n.access_point_id)),n.status&&(s.push("l.action = ?"),o.push(n.status)),n.geo_country&&(s.push("l.geo_country = ?"),o.push(n.geo_country.toUpperCase())),n.reason&&(s.push("l.reason = ?"),o.push(n.reason)),n.domain&&(s.push("l.domain = ?"),o.push(n.domain)),n.record_type&&(s.push("l.record_type = ?"),o.push(n.record_type)),n.search&&(s.push("l.domain LIKE ?"),o.push(`%${n.search}%`)),n.before&&(s.push("l.timestamp < ?"),o.push(n.before)),s.push("l.timestamp >= ?"),o.push(n.since),s.push("l.timestamp <= ?"),o.push(n.until),n.dest_country&&(s.push("COALESCE(l.dest_country_code, json_extract(l.dest_geoip, '$.country_code')) = ?"),o.push(n.dest_country.toUpperCase())),n.isp&&(s.push("COALESCE(l.dest_isp, json_extract(l.dest_geoip, '$.isp')) = ?"),o.push(n.isp));let i=r+" WHERE "+s.join(" AND ");if(n.export)i+=" ORDER BY l.timestamp DESC LIMIT 5000";else{let a=n.limit!==void 0&&!isNaN(n.limit)&&n.limit>0?n.limit:50;a>100&&(a=100),i+=` ORDER BY l.timestamp DESC LIMIT ${a}`}let{results:c}=await this.db.prepare(i).bind(...o).all();return c}async getLog(e,n,r){return r!==void 0&&!isNaN(r)?await this.db.prepare(`
235
+ `;let s=["l.profile_id = ?"],o=[e];t.access_point_id&&(s.push("l.access_point_id = ?"),o.push(t.access_point_id)),t.status&&(s.push("l.action = ?"),o.push(t.status)),t.geo_country&&(s.push("l.geo_country = ?"),o.push(t.geo_country.toUpperCase())),t.reason&&(s.push("l.reason = ?"),o.push(t.reason)),t.domain&&(s.push("l.domain = ?"),o.push(t.domain)),t.record_type&&(s.push("l.record_type = ?"),o.push(t.record_type)),t.search&&(s.push("l.domain LIKE ?"),o.push(`%${t.search}%`)),t.before&&(s.push("l.timestamp < ?"),o.push(t.before)),s.push("l.timestamp >= ?"),o.push(t.since),s.push("l.timestamp <= ?"),o.push(t.until),t.dest_country&&(s.push("COALESCE(l.dest_country_code, json_extract(l.dest_geoip, '$.country_code')) = ?"),o.push(t.dest_country.toUpperCase())),t.isp&&(s.push("COALESCE(l.dest_isp, json_extract(l.dest_geoip, '$.isp')) = ?"),o.push(t.isp));let i=r+" WHERE "+s.join(" AND ");if(t.export)i+=" ORDER BY l.timestamp DESC LIMIT 5000";else{let a=t.limit!==void 0&&!isNaN(t.limit)&&t.limit>0?t.limit:50;a>100&&(a=100),i+=` ORDER BY l.timestamp DESC LIMIT ${a}`}let{results:c}=await this.db.prepare(i).bind(...o).all();return c}async getLog(e,t,r){return r!==void 0&&!isNaN(r)?await this.db.prepare(`
236
236
  SELECT l.*, p.name as profile_name, ap.name as access_point_name, k.kem_ct
237
237
  FROM logs l
238
238
  JOIN profiles p ON l.profile_id = p.id
239
239
  LEFT JOIN access_points ap ON l.access_point_id = ap.id
240
240
  LEFT JOIN kem_keys k ON l.kem_key_id = k.id
241
241
  WHERE l.profile_id = ? AND l.timestamp = ? AND l.id = ?
242
- `).bind(e,r,n).first():await this.db.prepare(`
242
+ `).bind(e,r,t).first():await this.db.prepare(`
243
243
  SELECT l.*, p.name as profile_name, ap.name as access_point_name, k.kem_ct
244
244
  FROM logs l
245
245
  JOIN profiles p ON l.profile_id = p.id
@@ -247,11 +247,11 @@ SQL: ${this.sql}`),n}}},xo=class{constructor(e){this.rawDb=e}rawDb;prepare(e){re
247
247
  LEFT JOIN kem_keys k ON l.kem_key_id = k.id
248
248
  WHERE l.profile_id = ? AND l.id = ?
249
249
  LIMIT 1
250
- `).bind(e,n).first()}async deleteByOwner(e){return(await this.db.prepare("DELETE FROM logs WHERE profile_id IN (SELECT id FROM profiles WHERE owner_id = ?)").bind(e).run()).success}async cleanup(e,n,r=1e3){let s=0,o=Math.min(1e3,r);for(;s<r;){let i=Math.min(o,r-s),a=(await this.db.prepare(`
250
+ `).bind(e,t).first()}async deleteByOwner(e){return(await this.db.prepare("DELETE FROM logs WHERE profile_id IN (SELECT id FROM profiles WHERE owner_id = ?)").bind(e).run()).success}async cleanup(e,t,r=1e3){let s=0,o=Math.min(1e3,r);for(;s<r;){let i=Math.min(o,r-s),a=(await this.db.prepare(`
251
251
  DELETE FROM logs WHERE (profile_id, timestamp, id) IN (
252
252
  SELECT profile_id, timestamp, id FROM logs WHERE profile_id = ? AND timestamp < ? LIMIT ?
253
253
  )
254
- `).bind(e,n,i).run()).meta.changes||0;if(s+=a,a<i)break}return s}};var ys=class{constructor(e){this.db=e}db;async getLatestRollupHour(e){return null}async getLatestClientRollupHour(e){return null}async getLatestDestinationRollupHour(e){return null}async aggregateHourlyRollups(e,n,r=2){return 0}};var Sn=class{constructor(e){this.db=e}db;async getById(e){try{return await this.db.prepare("SELECT id, profile_id, kem_ct, created_at, expires_at FROM kem_keys WHERE id = ?").bind(e).first()}catch(n){return console.error(`[KemKeyModel] Failed to fetch kem_key ${e}:`,n),null}}async hasDependents(e){try{return await this.db.prepare("SELECT 1 FROM logs WHERE kem_key_id = ? LIMIT 1").bind(e).first()!==null}catch(n){return console.error(`[KemKeyModel] Failed to check dependents for kem_key ${e}:`,n),!0}}async cleanupOrphans(e=3600,n=1e3){let r=Math.floor(Date.now()/1e3)-e;try{let s=await this.db.prepare(`
254
+ `).bind(e,t,i).run()).meta.changes||0;if(s+=a,a<i)break}return s}};var Rs=class{constructor(e){this.db=e}db;async getLatestRollupHour(e){return null}async getLatestClientRollupHour(e){return null}async getLatestDestinationRollupHour(e){return null}async aggregateHourlyRollups(e,t,r=2){return 0}};var Pn=class{constructor(e){this.db=e}db;async getById(e){try{return await this.db.prepare("SELECT id, profile_id, kem_ct, created_at, expires_at FROM kem_keys WHERE id = ?").bind(e).first()}catch(t){return console.error(`[KemKeyModel] Failed to fetch kem_key ${e}:`,t),null}}async hasDependents(e){try{return await this.db.prepare("SELECT 1 FROM logs WHERE kem_key_id = ? LIMIT 1").bind(e).first()!==null}catch(t){return console.error(`[KemKeyModel] Failed to check dependents for kem_key ${e}:`,t),!0}}async cleanupOrphans(e=3600,t=1e3){let r=Math.floor(Date.now()/1e3)-e;try{let s=await this.db.prepare(`
255
255
  DELETE FROM kem_keys
256
256
  WHERE id IN (
257
257
  SELECT k.id FROM kem_keys k
@@ -261,25 +261,25 @@ SQL: ${this.sql}`),n}}},xo=class{constructor(e){this.rawDb=e}rawDb;prepare(e){re
261
261
  )
262
262
  LIMIT ?
263
263
  )
264
- `).bind(r,n).run();return s.meta?.changes??s.meta?.rows_written??0}catch(s){return console.error("[KemKeyModel] Failed to cleanup orphaned kem_keys:",s),0}}async cleanupProfileOrphans(e,n=3600){let r=Math.floor(Date.now()/1e3)-n;try{let s=await this.db.prepare(`
264
+ `).bind(r,t).run();return s.meta?.changes??s.meta?.rows_written??0}catch(s){return console.error("[KemKeyModel] Failed to cleanup orphaned kem_keys:",s),0}}async cleanupProfileOrphans(e,t=3600){let r=Math.floor(Date.now()/1e3)-t;try{let s=await this.db.prepare(`
265
265
  DELETE FROM kem_keys
266
266
  WHERE profile_id = ?
267
267
  AND created_at <= ?
268
268
  AND NOT EXISTS (
269
269
  SELECT 1 FROM logs l WHERE l.kem_key_id = kem_keys.id
270
270
  )
271
- `).bind(e,r).run();return s.meta?.changes??s.meta?.rows_written??0}catch(s){return console.error(`[KemKeyModel] Failed to cleanup profile orphan kem_keys for ${e}:`,s),0}}};var ws=class{constructor(e,n){this.db=e;this.settingsModel=n??new he(e)}db;settingsModel;async cleanupGlobal(e=30,n=1e3,r=2e4){try{let{results:s}=await this.db.prepare("SELECT id, settings FROM profiles").all();if(!s||s.length===0)return;let o=new Date().toISOString().slice(0,10),i=0;if(r>0)try{let m=await this.settingsModel.get("log_cleanup_daily_date"),h=await this.settingsModel.get("log_cleanup_daily_count");m===o&&h&&(i=parseInt(h,10)||0)}catch(m){console.warn("[LogRetentionModel] Failed to read daily cleanup settings:",m)}let c=r>0?Math.max(0,r-i):n,a=r<=0||c>0;r>0&&c<=0&&console.log(`[LogRetentionModel] cleanupGlobal: daily budget reached (${i}/${r}), skipping raw log deletion for today (${o})`);let l=r>0?Math.min(n,c):n,d=Math.max(1,Math.floor(l/s.length)),u=[];for(let m of s){let h=30;try{let b=JSON.parse(m.settings);b?.log_retention_days!=null&&(h=Number(b.log_retention_days))}catch{}let g=Math.min(h,e),w=Math.floor(Date.now()/1e3-g*24*3600);a&&l>0&&u.push(this.db.prepare(`
271
+ `).bind(e,r).run();return s.meta?.changes??s.meta?.rows_written??0}catch(s){return console.error(`[KemKeyModel] Failed to cleanup profile orphan kem_keys for ${e}:`,s),0}}};var Ts=class{constructor(e,t){this.db=e;this.settingsModel=t??new he(e)}db;settingsModel;async cleanupGlobal(e=30,t=1e3,r=2e4){try{let{results:s}=await this.db.prepare("SELECT id, settings FROM profiles").all();if(!s||s.length===0)return;let o=new Date().toISOString().slice(0,10),i=0;if(r>0)try{let m=await this.settingsModel.get("log_cleanup_daily_date"),h=await this.settingsModel.get("log_cleanup_daily_count");m===o&&h&&(i=parseInt(h,10)||0)}catch(m){console.warn("[LogRetentionModel] Failed to read daily cleanup settings:",m)}let c=r>0?Math.max(0,r-i):t,a=r<=0||c>0;r>0&&c<=0&&console.log(`[LogRetentionModel] cleanupGlobal: daily budget reached (${i}/${r}), skipping raw log deletion for today (${o})`);let l=r>0?Math.min(t,c):t,d=Math.max(1,Math.floor(l/s.length)),u=[];for(let m of s){let h=30;try{let w=JSON.parse(m.settings);w?.log_retention_days!=null&&(h=Number(w.log_retention_days))}catch{}let g=Math.min(h,e),b=Math.floor(Date.now()/1e3-g*24*3600);a&&l>0&&u.push(this.db.prepare(`
272
272
  DELETE FROM logs WHERE (profile_id, timestamp, id) IN (
273
273
  SELECT profile_id, timestamp, id FROM logs WHERE profile_id = ? AND timestamp < ? LIMIT ?
274
274
  )
275
- `).bind(m.id,w,d))}let f=50,p=0;if(u.length>0){for(let m=0;m<u.length;m+=f){let h=u.slice(m,m+f),g=await this.db.batch(h);if(Array.isArray(g))for(let w of g)w?.meta?.changes!==void 0?p+=w.meta.changes:w?.meta?.rows_written!==void 0&&(p+=w.meta.rows_written)}if(r>0){let m=i+p;try{await this.settingsModel.setMany({log_cleanup_daily_date:o,log_cleanup_daily_count:String(m)})}catch(h){console.warn("[LogRetentionModel] Failed to persist daily cleanup count:",h)}}}try{let h=await new Sn(this.db).cleanupOrphans();h>0&&console.log(`[LogRetentionModel] Cleaned up ${h} orphaned kem_keys with zero referencing logs.`)}catch(m){console.warn("[LogRetentionModel] Failed to cleanup orphaned kem_keys:",m)}console.log(`[LogRetentionModel] cleanupGlobal: processed ${s.length} profile(s), maxRetentionDays=${e}d, batchLimit=${n} (effective=${l}, perProfile=${d}), dailyBudget=${r} (today: ${i+p}/${r})`)}catch(s){console.error("[LogRetentionModel] cleanupGlobal failed:",s.message||s)}}};var bs=class{constructor(e){this.db=e}db;async getSummary(e,n,r,s,o){let i="SELECT action, COUNT(*) as count FROM logs WHERE profile_id = ? AND timestamp >= ? AND timestamp <= ?",c=[e,n,r];s&&(i+=" AND domain LIKE ?",c.push(`%${s}%`)),o&&(i+=" AND access_point_id = ?",c.push(o)),i+=" GROUP BY action";let{results:a}=await this.db.prepare(i).bind(...c).all();return a}async getTrend(e,n,r,s,o){let c=new Set(["(timestamp/60)*60","(timestamp/300)*300","(timestamp/900)*900","(timestamp/3600)*3600","(timestamp/86400)*86400"]).has(s.trim())?s.trim():"(timestamp/3600)*3600",a=`SELECT ${c} as timestamp, action, COUNT(*) as count FROM logs WHERE profile_id = ? AND timestamp >= ? AND timestamp <= ?`,l=[e,n,r];o&&(a+=" AND access_point_id = ?",l.push(o)),a+=` GROUP BY ${c}, action ORDER BY timestamp ASC`;let{results:d}=await this.db.prepare(a).bind(...l).all();return d}};var Es=class{constructor(e){this.db=e}db;async getTopAllowed(e,n,r,s){let o="SELECT domain, COUNT(*) as count FROM logs WHERE profile_id = ? AND timestamp >= ? AND timestamp <= ? AND action = 'PASS'",i=[e,n,r];s&&(o+=" AND access_point_id = ?",i.push(s)),o+=" GROUP BY domain ORDER BY count DESC LIMIT 10";let{results:c}=await this.db.prepare(o).bind(...i).all();return c}async getTopBlocked(e,n,r,s){let o="SELECT domain, COUNT(*) as count FROM logs WHERE profile_id = ? AND timestamp >= ? AND timestamp <= ? AND action IN ('BLOCK', 'REDIRECT')",i=[e,n,r];s&&(o+=" AND access_point_id = ?",i.push(s)),o+=" GROUP BY domain ORDER BY count DESC LIMIT 10";let{results:c}=await this.db.prepare(o).bind(...i).all();return c}};var _s=class{constructor(e){this.db=e}db;async getClients(e,n,r,s){let o="SELECT client_ip, geo_country, COUNT(*) as count FROM logs WHERE profile_id = ? AND timestamp >= ? AND timestamp <= ?",i=[e,n,r];s&&(o+=" AND access_point_id = ?",i.push(s)),o+=" GROUP BY client_ip, geo_country ORDER BY count DESC LIMIT 20";let{results:c}=await this.db.prepare(o).bind(...i).all();return c}};var Ss=class{constructor(e){this.db=e}db;async getDestinations(e,n,r,s,o=250){let i=`
275
+ `).bind(m.id,b,d))}let f=50,p=0;if(u.length>0){for(let m=0;m<u.length;m+=f){let h=u.slice(m,m+f),g=await this.db.batch(h);if(Array.isArray(g))for(let b of g)b?.meta?.changes!==void 0?p+=b.meta.changes:b?.meta?.rows_written!==void 0&&(p+=b.meta.rows_written)}if(r>0){let m=i+p;try{await this.settingsModel.setMany({log_cleanup_daily_date:o,log_cleanup_daily_count:String(m)})}catch(h){console.warn("[LogRetentionModel] Failed to persist daily cleanup count:",h)}}}try{let h=await new Pn(this.db).cleanupOrphans();h>0&&console.log(`[LogRetentionModel] Cleaned up ${h} orphaned kem_keys with zero referencing logs.`)}catch(m){console.warn("[LogRetentionModel] Failed to cleanup orphaned kem_keys:",m)}console.log(`[LogRetentionModel] cleanupGlobal: processed ${s.length} profile(s), maxRetentionDays=${e}d, batchLimit=${t} (effective=${l}, perProfile=${d}), dailyBudget=${r} (today: ${i+p}/${r})`)}catch(s){console.error("[LogRetentionModel] cleanupGlobal failed:",s.message||s)}}};var xs=class{constructor(e){this.db=e}db;async getSummary(e,t,r,s,o){let i="SELECT action, COUNT(*) as count FROM logs WHERE profile_id = ? AND timestamp >= ? AND timestamp <= ?",c=[e,t,r];s&&(i+=" AND domain LIKE ?",c.push(`%${s}%`)),o&&(i+=" AND access_point_id = ?",c.push(o)),i+=" GROUP BY action";let{results:a}=await this.db.prepare(i).bind(...c).all();return a}async getTrend(e,t,r,s,o){let c=new Set(["(timestamp/60)*60","(timestamp/300)*300","(timestamp/900)*900","(timestamp/3600)*3600","(timestamp/86400)*86400"]).has(s.trim())?s.trim():"(timestamp/3600)*3600",a=`SELECT ${c} as timestamp, action, COUNT(*) as count FROM logs WHERE profile_id = ? AND timestamp >= ? AND timestamp <= ?`,l=[e,t,r];o&&(a+=" AND access_point_id = ?",l.push(o)),a+=` GROUP BY ${c}, action ORDER BY timestamp ASC`;let{results:d}=await this.db.prepare(a).bind(...l).all();return d}};var As=class{constructor(e){this.db=e}db;async getTopAllowed(e,t,r,s){let o="SELECT domain, COUNT(*) as count FROM logs WHERE profile_id = ? AND timestamp >= ? AND timestamp <= ? AND action = 'PASS'",i=[e,t,r];s&&(o+=" AND access_point_id = ?",i.push(s)),o+=" GROUP BY domain ORDER BY count DESC LIMIT 10";let{results:c}=await this.db.prepare(o).bind(...i).all();return c}async getTopBlocked(e,t,r,s){let o="SELECT domain, COUNT(*) as count FROM logs WHERE profile_id = ? AND timestamp >= ? AND timestamp <= ? AND action IN ('BLOCK', 'REDIRECT')",i=[e,t,r];s&&(o+=" AND access_point_id = ?",i.push(s)),o+=" GROUP BY domain ORDER BY count DESC LIMIT 10";let{results:c}=await this.db.prepare(o).bind(...i).all();return c}};var vs=class{constructor(e){this.db=e}db;async getClients(e,t,r,s){let o="SELECT client_ip, geo_country, COUNT(*) as count FROM logs WHERE profile_id = ? AND timestamp >= ? AND timestamp <= ?",i=[e,t,r];s&&(o+=" AND access_point_id = ?",i.push(s)),o+=" GROUP BY client_ip, geo_country ORDER BY count DESC LIMIT 20";let{results:c}=await this.db.prepare(o).bind(...i).all();return c}};var Ps=class{constructor(e){this.db=e}db;async getDestinations(e,t,r,s,o=250){let i=`
276
276
  SELECT
277
277
  COALESCE(dest_country_code, json_extract(dest_geoip, '$.country_code')) as country_code,
278
278
  COALESCE(dest_country, json_extract(dest_geoip, '$.country')) as country,
279
279
  COUNT(*) as count
280
280
  FROM logs
281
281
  WHERE profile_id = ? AND timestamp >= ? AND timestamp <= ? AND (dest_country_code IS NOT NULL OR dest_geoip IS NOT NULL)
282
- `,c=[e,n,r];s&&(i+=" AND access_point_id = ?",c.push(s)),i+=` GROUP BY country_code ORDER BY count DESC LIMIT ${o}`;let{results:a}=await this.db.prepare(i).bind(...c).all();return a}async getISPByCountry(e,n,r,s,o,i=250){let c=`
282
+ `,c=[e,t,r];s&&(i+=" AND access_point_id = ?",c.push(s)),i+=` GROUP BY country_code ORDER BY count DESC LIMIT ${o}`;let{results:a}=await this.db.prepare(i).bind(...c).all();return a}async getISPByCountry(e,t,r,s,o,i=250){let c=`
283
283
  SELECT
284
284
  COALESCE(dest_isp, json_extract(dest_geoip, '$.isp')) as name,
285
285
  COUNT(*) as count
@@ -290,7 +290,7 @@ SQL: ${this.sql}`),n}}},xo=class{constructor(e){this.rawDb=e}rawDb;prepare(e){re
290
290
  AND (dest_country_code IS NOT NULL OR dest_geoip IS NOT NULL)
291
291
  AND COALESCE(dest_isp, json_extract(dest_geoip, '$.isp')) IS NOT NULL
292
292
  AND COALESCE(dest_isp, json_extract(dest_geoip, '$.isp')) != ''
293
- `,a=[e,r,s];n&&(c+=" AND UPPER(COALESCE(dest_country_code, json_extract(dest_geoip, '$.country_code'))) = ?",a.push(n.toUpperCase())),o&&(c+=" AND access_point_id = ?",a.push(o)),c+=` GROUP BY name ORDER BY count DESC LIMIT ${i}`;let{results:l}=await this.db.prepare(c).bind(...a).all();return l.map(d=>({name:d.name||"Unknown",count:d.count}))}};var Rs=class{constructor(e,n){this.db=e;this.traffic=new bs(e),this.domains=new Es(e),this.clients=new _s(e),this.destinations=new Ss(e)}db;traffic;domains;clients;destinations;async getSummary(e,n,r,s,o){return this.traffic.getSummary(e,n,r,s,o)}async getTrend(e,n,r,s,o){return this.traffic.getTrend(e,n,r,s,o)}async getTopAllowed(e,n,r,s){return this.domains.getTopAllowed(e,n,r,s)}async getTopBlocked(e,n,r,s){return this.domains.getTopBlocked(e,n,r,s)}async getClients(e,n,r,s){return this.clients.getClients(e,n,r,s)}async getDestinations(e,n,r,s,o=250){return this.destinations.getDestinations(e,n,r,s,o)}async getISPByCountry(e,n,r,s,o,i=250){return this.destinations.getISPByCountry(e,n,r,s,o,i)}async getAnalytics(e,n,r,s,o){let[i,c,a,l,d,u]=await Promise.all([this.getSummary(e,n,r,void 0,o),this.getTrend(e,n,r,s,o),this.getTopAllowed(e,n,r,o),this.getTopBlocked(e,n,r,o),this.getClients(e,n,r,o),this.getDestinations(e,n,r,o)]);return{summary:i,trend:c,top_allowed:a,top_blocked:l,clients:d,destinations:u}}};var Oe=class{constructor(e){this.db=e;this.core=new gs(e),this.aggregation=new ys(e),this.retention=new ws(e),this.analytics=new Rs(e,this.aggregation),this.kemKeys=new Sn(e)}db;core;aggregation;retention;analytics;kemKeys;createInsertStatement(e){return this.core.createInsertStatement(e)}async insert(e){return this.core.insert(e)}async getLogs(e,n){return this.core.getLogs(e,n)}async getLog(e,n,r){return this.core.getLog(e,n,r)}async deleteByOwner(e){return this.core.deleteByOwner(e)}async cleanup(e,n,r=1e3){return this.core.cleanup(e,n,r)}async cleanupGlobal(e=30,n=1e3,r=2e4){return this.retention.cleanupGlobal(e,n,r)}async getLatestRollupHour(e){return this.aggregation.getLatestRollupHour(e)}async getLatestClientRollupHour(e){return this.aggregation.getLatestClientRollupHour(e)}async getLatestDestinationRollupHour(e){return this.aggregation.getLatestDestinationRollupHour(e)}async aggregateHourlyRollups(e,n,r=2){return this.aggregation.aggregateHourlyRollups(e,n,r)}async getSummary(e,n,r,s,o){return this.analytics.getSummary(e,n,r,s,o)}async getTrend(e,n,r,s,o){return this.analytics.getTrend(e,n,r,s,o)}async getTopAllowed(e,n,r,s){return this.analytics.getTopAllowed(e,n,r,s)}async getTopBlocked(e,n,r,s){return this.analytics.getTopBlocked(e,n,r,s)}async getClients(e,n,r,s){return this.analytics.getClients(e,n,r,s)}async getDestinations(e,n,r,s,o=250){return this.analytics.getDestinations(e,n,r,s,o)}async getISPByCountry(e,n,r,s,o,i=250){return this.analytics.getISPByCountry(e,n,r,s,o,i)}async getAnalytics(e,n,r,s,o){return this.analytics.getAnalytics(e,n,r,s,o)}};ge();function Ht(t){return t instanceof Uint8Array||ArrayBuffer.isView(t)&&t.constructor.name==="Uint8Array"&&"BYTES_PER_ELEMENT"in t&&t.BYTES_PER_ELEMENT===1}var Ts=t=>t?`"${t}" `:"";function ue(t,e=""){if(typeof t!="number")throw new TypeError(Ts(e)+"expected number, got "+typeof t);if(!Number.isSafeInteger(t)||t<0)throw new RangeError(Ts(e)+"expected integer >= 0, got "+t);return t}function sa(t,e=""){if(typeof t!="boolean")throw new TypeError(Ts(e)+"expected boolean, got type="+typeof t);return t}function X(t,e,n=""){if(Ht(t)&&(e===void 0||t.length===e))return t;e!==void 0&&ue(e,"length");let r=Ht(t),s=e!==void 0?` of length ${e}`:"",o=r?`length=${t.length}`:`type=${typeof t}`,i=Ts(n)+"expected Uint8Array"+s+", got "+o;throw r?new RangeError(i):new TypeError(i)}function Rn(t){if(typeof t!="function"||typeof t.create!="function")throw new TypeError("expected hash wrapped by utils.createHasher");if(ue(t.outputLen),ue(t.blockLen),t.outputLen<1||t.blockLen<1)throw new Error("hash blockLen / outputLen must be >= 1")}var td=(t,e)=>{if(t===null||typeof t!="object"||Array.isArray(t))throw new TypeError((e==="object"?"":`"${e}" `)+"expected object, got type="+typeof t)},na=(t,e)=>{td(t,e);let n=Object.getPrototypeOf(t);if(n!==Object.prototype&&n!==null)throw new TypeError(`"${e}" expected plain object`);if(Object.hasOwn(t,"__proto__"))throw new TypeError(`"${e}.__proto__" is not allowed`)};function nt(t,e=!0){if(t.destroyed)throw new Error("hash was destroyed");if(e&&t.finished)throw new Error("digest() was already called")}function Tn(t,e){X(t,void 0,"output");let n=e.outputLen;if(!(t.length>=n))throw new RangeError('"output" expected length >= '+n)}function mr(t){return new Uint32Array(t.buffer,t.byteOffset,Math.floor(t.byteLength/4))}function Rt(...t){for(let e=0;e<t.length;e++)t[e].fill(0)}function xs(t){return new DataView(t.buffer,t.byteOffset,t.byteLength)}function Be(t,e){return t<<32-e|t>>>e}var oa=new Uint8Array(new Uint32Array([287454020]).buffer)[0]===68;function nd(t){return t<<24&4278190080|t<<8&16711680|t>>>8&65280|t>>>24&255}function rd(t){for(let e=0;e<t.length;e++)t[e]=nd(t[e]);return t}var xn=oa?t=>t:rd,ia=typeof Uint8Array.from([]).toHex=="function"&&typeof Uint8Array.fromHex=="function",sd=Array.from({length:256},(t,e)=>e.toString(16).padStart(2,"0"));function hr(t){if(X(t),ia)return t.toHex();let e="";for(let n=0;n<t.length;n++)e+=sd[t[n]];return e}function ra(t){return t>=48&&t<=57?t-48:t>=65&&t<=70?t-55:t>=97&&t<=102?t-87:void 0}function Go(t){if(typeof t!="string")throw new TypeError("hex string expected, got "+typeof t);if(ia)try{return Uint8Array.fromHex(t)}catch(s){throw s instanceof SyntaxError?new RangeError(s.message):s}let e=t.length,n=e/2;if(e%2)throw new RangeError("hex string expected, got unpadded hex of length "+e);let r=new Uint8Array(n);for(let s=0,o=0;s<n;s++,o+=2){let i=ra(t.charCodeAt(o)),c=ra(t.charCodeAt(o+1));if(i===void 0||c===void 0){let a=t[o]+t[o+1];throw new RangeError('hex string expected, got non-hex character "'+a+'" at index '+o)}r[s]=i*16+c}return r}function Yo(...t){let e=0;for(let r=0;r<t.length;r++){let s=t[r];X(s),e+=s.length}let n=new Uint8Array(e);for(let r=0,s=0;r<t.length;r++){let o=t[r];n.set(o,s),s+=o.length}return n}function Xo(t,e,n="opts"){return na(t,"defaults"),e!==void 0&&na(e,n),Object.assign(Object.create(null),t,e)}function gr(t,e={}){if(typeof t!="function")throw new TypeError('"hashCons" expected function, got type='+typeof t);e=Xo({},e,"info");let n=(s,o)=>t(o).update(s).digest(),r=t(void 0);return n.outputLen=r.outputLen,n.blockLen=r.blockLen,n.canXOF=r.canXOF,n.create=s=>t(s),Object.assign(n,e),Object.freeze(n)}function As(t=32){ue(t,"bytesLength");let e=typeof globalThis=="object"?globalThis.crypto:null;if(typeof e?.getRandomValues!="function")throw new Error("crypto.getRandomValues must be defined");if(t>65536)throw new RangeError(`"bytesLength" expected <= 65536, got ${t}`);return e.getRandomValues(new Uint8Array(t))}var $t=t=>({oid:Uint8Array.from([6,9,96,134,72,1,101,3,4,2,t])});function yr(t,e,n=()=>{}){if(!Array.isArray(t))throw new TypeError(`"${e}" expected array, got type=${typeof t}`);for(let r=0;r<t.length;r++)n(t[r],`${e}[${r}]`);return t}var fe=(t,e,n)=>X(t,e,n),zo=ue;function ca(t,e=""){if(typeof t!="string"){let n=e&&`"${e}" `;throw new TypeError(n+"expected string, got type="+typeof t)}return t}function Tt(t,e="object"){if(t===null||typeof t!="object"||Array.isArray(t))throw new TypeError(e==="object"?"expected valid options object":`"${e}" expected object, got type=${typeof t}`);return t}function Ne(t,e){if(typeof t!="function")throw new TypeError(`"${e}" is invalid: expected function, got ${typeof t}`);return t}var Qo=hr,Fe=(...t)=>Yo(...t),Ps=t=>Go(t),An=Ht,Cs=t=>As(t),vs=BigInt(0),aa=BigInt(1),od=t=>t?`"${t}" `:"";function He(t,e=""){if(typeof t!="boolean")throw new TypeError(od(e)+"expected boolean, got type="+typeof t);return t}function Ds(t){if(typeof t=="bigint"){if(!xt(t))throw new RangeError("positive bigint expected, got "+t)}else zo(t);return t}function Kt(t,e=""){if(typeof t!="number"){let n=e&&`"${e}" `;throw new TypeError(n+"expected number, got type="+typeof t)}if(!Number.isSafeInteger(t)){let n=e&&`"${e}" `;throw new RangeError(n+"expected safe integer, got "+t)}}function wr(t){let e=Ds(t).toString(16);return e.length&1?"0"+e:e}function la(t){if(typeof t!="string")throw new TypeError("hex string expected, got "+typeof t);return t===""?vs:BigInt("0x"+t)}function $e(t){return la(hr(t))}function ks(t){return la(hr(id(X(t)).reverse()))}function br(t,e){if(ue(e),e===0)throw new Error("zero output length is invalid");t=Ds(t);let n=e*2,r=t.toString(16);if(r.length>n)throw new RangeError("number is too large");return Go(r.padStart(n,"0"))}function Zo(t,e){return br(t,e).reverse()}function id(t){return Uint8Array.from(fe(t))}function da(t){if(typeof t!="string")throw new TypeError("ascii string expected, got "+typeof t);return Uint8Array.from(t,(e,n)=>{let r=e.charCodeAt(0);if(e.length!==1||r>127)throw new RangeError(`string contains non-ASCII character "${t[n]}" with code ${r} at position ${n}`);return r})}function xt(t){return typeof t=="bigint"&&vs<=t}function qo(t,e,n){return xt(t)&&xt(e)&&xt(n)&&e<=t&&t<n}function ei(t,e,n,r){if(!qo(e,n,r))throw new RangeError("expected valid "+t+": "+n+" <= n < "+r+", got "+e)}function vn(t){if(t<vs)throw new Error("expected non-negative bigint, got "+t);return t===vs?0:t.toString(2).length}var Er=t=>(Kt(t,"n"),(aa<<BigInt(t))-aa);function ua(t,e,n){if(ue(t,"hashLen"),ue(e,"qByteLen"),typeof n!="function")throw new TypeError("hmacFn must be a function");let r=g=>new Uint8Array(g),s=Uint8Array.of(),o=Uint8Array.of(0),i=Uint8Array.of(1),c=1e3,a=r(t),l=r(t),d=0,u=()=>{a.fill(1),l.fill(0),d=0},f=(...g)=>n(l,Fe(a,...g)),p=(g=s)=>{l=f(o,g),a=f(),g.length!==0&&(l=f(i,g),a=f())},m=()=>{if(d++>=c)throw new Error("drbg: tried max amount of iterations");let g=0,w=[];for(;g<e;){a=f();let b=a.slice();w.push(b),g+=a.length}return Fe(...w)};return(g,w)=>{u(),p(g);let b;for(;(b=w(m()))===void 0;)p();return u(),b}}function Qe(t,e={},n={},r="object"){Tt(t,r),Tt(e,"fields"),Tt(n,"optFields");function s(i,c,a){let l=r==="object"?`param "${String(i)}"`:`"${r}.${String(i)}"`,d=t[i];if(!Object.hasOwn(t,i)&&(a?d!==void 0:c!=="function"))throw new TypeError(`${l} is invalid: expected own property`);if(a&&d===void 0)return;let u=typeof d;if(u!==c||d===null)throw new TypeError(`${l} is invalid: expected ${c}, got ${u}`)}let o=(i,c)=>Object.entries(i).forEach(([a,l])=>s(a,l,c));o(e,!1),o(n,!0)}var ye=BigInt(0),ee=BigInt(1),At=BigInt(2),ha=BigInt(3),ti=BigInt(4),ga=BigInt(5),ad=BigInt(7),ya=BigInt(8),cd=BigInt(9),ld=BigInt(15),wa=BigInt(16),dd=BigInt("0x10000000000000000");function ve(t,e){if(e<=ye)throw new Error("mod: expected positive modulus, got "+e);let n=t%e;return n>=ye?n:e+n}function ba(t,e,n){if(n<=ee)throw new Error("pow: expected modulus > 1, got "+n);if(typeof e!="bigint")throw new TypeError("invalid exponent: expected bigint, got "+typeof e);if(e<ye)throw new Error("invalid exponent, negatives unsupported");if(e===ye)return ee;if(e===ee)return t;let r=t%n;if(r<ye&&(r+=n),e<dd){let c=ee;for(;e>ye;)e&ee&&(c=c*r%n),r=r*r%n,e>>=ee;return c}let s=[];for(;e>ye;)s.push(Number(e&ld)),e>>=ti;let o=new Array(16);o[0]=ee,o[1]=r;for(let c=2;c<16;c++)o[c]=o[c-1]*r%n;let i=o[s[s.length-1]];for(let c=s.length-2;c>=0;c--){i=i*i%n,i=i*i%n,i=i*i%n,i=i*i%n;let a=s[c];a!==0&&(i=i*o[a]%n)}return i}function pa(t,e){if(t===ye)throw new Error("invert: expected non-zero number");if(e<=ee)throw new Error("invert: expected modulus > 1, got "+e);let n=ve(t,e),r=e,s=ye,o=ee;for(;n!==ye;){let c=r/n,a=r-n*c,l=s-o*c;r=n,n=a,s=o,o=l}if(r!==ee)throw new Error("invert: does not exist");return ve(s,e)}function Ea(t,e){if(e<=ee)throw new Error("invertCt: expected prime modulus > 1, got "+e);let n=ve(t,e);if(n===ye)throw new Error("invertCt: expected non-zero number");let r=ba(n,e-At,e);if(ve(n*r,e)!==ee)throw new Error("invertCt: does not exist");return r}function ni(t,e,n){let r=t;if(!r.eql(r.sqr(e),n))throw new Error("Cannot find square root")}function ri(t,e){if((t&ee)===ye)throw new Error(e+": expected odd modulus, got "+t)}function _a(t,e){let n=t,r=(n.ORDER+ee)/ti,s=n.pow(e,r);return ni(n,s,e),s}function ud(t,e){let n=t,r=(n.ORDER-ga)/ya,s=n.mul(e,At),o=n.pow(s,r),i=n.mul(e,o),c=n.mul(n.mul(i,At),o),a=n.mul(i,n.sub(c,n.ONE));return ni(n,a,e),a}function pd(t){let e=Os(t),n=Sa(t),r=n(e,e.neg(e.ONE)),s=n(e,r),o=n(e,e.neg(r)),i=(t+ad)/wa;return((c,a)=>{let l=c,d=l.pow(a,i),u=l.mul(d,r),f=l.mul(d,s),p=l.mul(d,o),m=l.eql(l.sqr(u),a),h=l.eql(l.sqr(f),a);d=l.cmov(d,u,m),u=l.cmov(p,f,h);let g=l.eql(l.sqr(u),a),w=l.cmov(d,u,g);return ni(l,w,a),w})}function Sa(t){if(t<ha)throw new Error("sqrt is not defined for small field");ri(t,"tonelliShanks");let e=t-ee,n=0;for(;e%At===ye;)e/=At,n++;let r=At,s=Os(t);for(;fa(s,r)===1;)if(r++>1e3)throw new Error("Cannot find square root: probably non-prime P");if(n===1)return _a;let o=s.pow(r,e),i=(e+ee)/At;return function(a,l){let d=a;if(d.is0(l))return l;if(fa(d,l)!==1)throw new Error("Cannot find square root");let u=n,f=d.mul(d.ONE,o),p=d.pow(l,e),m=d.pow(l,i);for(;!d.eql(p,d.ONE);){if(d.is0(p))throw new Error("Cannot find square root: probably non-prime P");let h=1,g=d.sqr(p);for(;!d.eql(g,d.ONE);)if(h++,g=d.sqr(g),h===u)throw new Error("Cannot find square root");let w=ee<<BigInt(u-h-1),b=d.pow(f,w);u=h,f=d.sqr(b),p=d.mul(p,f),m=d.mul(m,b)}return m}}function fd(t){return ri(t,"Fp.sqrt"),t%ti===ha?_a:t%ya===ga?ud:t%wa===cd?pd(t):Sa(t)}var md=["create","isValid","is0","neg","inv","sqrt","sqr","eql","add","sub","mul","pow","div","addN","subN","mulN","sqrN"];function Pn(t){if(Tt(t,"field"),typeof t.ORDER!="bigint")throw new TypeError('param "ORDER" is invalid: expected bigint, got '+typeof t.ORDER);Kt(t.BYTES,"BYTES"),Kt(t.BITS,"BITS");for(let e of md)Ne(t[e],"field."+e);if(t.BYTES<1||t.BITS<1)throw new Error("invalid field: expected BYTES/BITS > 0");if(t.ORDER<=ee)throw new Error("invalid field: expected ORDER > 1, got "+t.ORDER);return t}function si(t,e,n=!1){Pn(t),yr(e,"nums"),He(n,"passZero");let r=t,s=new Array(e.length).fill(n?r.ZERO:void 0),o=e.reduce((c,a,l)=>r.is0(a)?c:(s[l]=c,r.mul(c,a)),r.ONE),i=r.inv(o);return e.reduceRight((c,a,l)=>r.is0(a)?c:(s[l]=r.mul(c,s[l]),r.mul(c,a)),i),s}function fa(t,e){Pn(t);let n=t;ri(n.ORDER,"FpLegendre");let r=(n.ORDER-ee)/At,s=n.pow(e,r),o=n.eql(s,n.ONE),i=n.eql(s,n.ZERO),c=n.eql(s,n.neg(n.ONE));if(!o&&!i&&!c)throw new Error("invalid Legendre symbol result");return o?1:i?0:-1}function hd(t,e){if(e!==void 0&&zo(e),t<=ye)throw new Error("invalid n length: expected positive n, got "+t);if(e!==void 0&&e<1)throw new Error("invalid n length: expected positive bit length, got "+e);let n=vn(t);if(e!==void 0&&e<n)throw new Error(`invalid n length: expected nBitLength (${e}) >= bitLen(n) (${n})`);let r=e!==void 0?e:n,s=Math.ceil(r/8);return{nBitLength:r,nByteLength:s}}var ma=new WeakMap,Ls=class{ORDER;BITS;BYTES;isLE;ZERO=ye;ONE=ee;_lengths;_mod;constructor(e,n={}){if(e<=ee)throw new Error("invalid field: expected ORDER > 1, got "+e);let r;this.isLE=!1,n!=null&&typeof n=="object"&&(typeof n.BITS=="number"&&(r=n.BITS),typeof n.sqrt=="function"&&Object.defineProperty(this,"sqrt",{value:n.sqrt,enumerable:!0}),typeof n.isLE=="boolean"&&(this.isLE=n.isLE),n.allowedLengths&&(this._lengths=Object.freeze(n.allowedLengths.slice())),typeof n.modFromBytes=="boolean"&&(this._mod=n.modFromBytes));let{nBitLength:s,nByteLength:o}=hd(e,r);if(o>2048)throw new Error("invalid field: expected ORDER of <= 2048 bytes");this.ORDER=e,this.BITS=s,this.BYTES=o,Object.freeze(this)}create(e){return ve(e,this.ORDER)}isValid(e){if(typeof e!="bigint")throw new TypeError("invalid field element: expected bigint, got "+typeof e);return ye<=e&&e<this.ORDER}is0(e){return e===ye}isValidNot0(e){return!this.is0(e)&&this.isValid(e)}isOdd(e){return(e&ee)===ee}neg(e){return ve(-e,this.ORDER)}eql(e,n){return e===n}sqr(e){return ve(e*e,this.ORDER)}add(e,n){return ve(e+n,this.ORDER)}sub(e,n){return ve(e-n,this.ORDER)}mul(e,n){return ve(e*n,this.ORDER)}pow(e,n){return ba(e,n,this.ORDER)}div(e,n){return ve(e*pa(n,this.ORDER),this.ORDER)}sqrN(e){return e*e}addN(e,n){return e+n}subN(e,n){return e-n}mulN(e,n){return e*n}inv(e){return pa(e,this.ORDER)}sqrt(e){let n=ma.get(this);return n||ma.set(this,n=fd(this.ORDER)),n(this,e)}toBytes(e){return this.isLE?Zo(e,this.BYTES):br(e,this.BYTES)}fromBytes(e,n=!1){fe(e);let{_lengths:r,BYTES:s,isLE:o,ORDER:i,_mod:c}=this;if(r){if(e.length<1||!r.includes(e.length)||e.length>s)throw new Error("Field.fromBytes: expected "+r+" bytes, got "+e.length);let l=new Uint8Array(s);l.set(e,o?0:l.length-e.length),e=l}if(e.length!==s)throw new Error("Field.fromBytes: expected "+s+" bytes, got "+e.length);let a=o?ks(e):$e(e);if(c&&(a=ve(a,i)),!n&&!this.isValid(a))throw new Error("invalid field element: outside of range 0..ORDER");return a}invertBatch(e){return si(this,e,!0)}cmov(e,n,r){return He(r,"condition"),r?n:e}};function Os(t,e={}){return Object.freeze(Ls.prototype),new Ls(t,e)}function Ra(t){if(typeof t!="bigint")throw new Error("field order must be bigint");if(t<=ee)throw new Error("field order must be greater than 1");let e=vn(t-ee);return Math.ceil(e/8)}function Ns(t){let e=Ra(t);return e+Math.ceil(e/2)}function oi(t,e,n=!1){fe(t);let r=t.length,s=Ra(e),o=Math.max(Ns(e),16);if(r<o||r>1024)throw new Error("expected "+o+"-1024 bytes of input, got "+r);let i=n?ks(t):$e(t),c=ve(i,e-ee)+ee;return n?Zo(c,s):br(c,s)}var ci=BigInt(0),_r=BigInt(1),gd=BigInt(4),ii=16,Ta=128,yd=5,xa=2**31;function Cn(t){let e=t;if(typeof e!="function")throw new TypeError('"Point" expected constructor, got type='+typeof t);Ne(e.fromAffine,"Point.fromAffine"),Ne(e.fromBytes,"Point.fromBytes"),Ne(e.fromHex,"Point.fromHex"),Tt(e.BASE,"Point.BASE"),Tt(e.ZERO,"Point.ZERO"),Pn(e.Fp),Pn(e.Fn)}function va(t,e){Cn(t),Pa(e,t);let n=si(t.Fp,e.map(r=>r.Z));return e.map((r,s)=>t.fromAffine(r.toAffine(n[s])))}function wd(t,e,n=1){if(!Number.isSafeInteger(t)||t<n||t>e)throw new Error("invalid window size, expected ["+n+".."+e+"], got W="+t)}function bd(t,e){let n=t*(4*e+128);if(n>xa)throw new Error("invalid window size: table would need ~"+Math.ceil(n/2**20)+" MiB, max "+xa/2**20+" MiB")}function li(t,e){if(t!==void 0){Ne(t,"randomBytes");try{let n=t(e);if(!An(n)||n.length!==e)return}catch{return}return t}}function Pa(t,e){yr(t,"points"),t.forEach((n,r)=>{if(!(n instanceof e))throw new Error("invalid point at index "+r)})}function Ed(t,e,n){if(!Array.isArray(t))throw new Error("array of scalars expected");t.forEach((r,s)=>{if(!(n===void 0?e.isValid(r):xt(r)&&r<n))throw new Error("invalid scalar at index "+s)})}var Ca=new WeakMap;function ai(t){return Ca.get(t)||1}function _d(t,e){let n=t.double(),r=[t];for(let s=1;s<e;s++)r.push(r[s-1].add(n));return r}function Sd(t,e){let n=2**e,r=n/2,s=BigInt(n-1),o=[];for(;t>ci;){let i=0;t&_r&&(i=Number(t&s),i>=r&&(i-=n),t-=BigInt(i)),o.push(i),t>>=_r}return o}function Rd(t,e,n){let r=2**e,s=r/2,o=BigInt(r-1),i=BigInt(e),c=[];for(let a=0;a<n;a++){let l=Number(t&o);t>>=i,l>s&&(l-=r,t+=_r),c.push(l)}if(t!==ci)throw new Error("invalid wnaf");return c}function Td(t,e,n){let r=0;for(let o of n)r=Math.max(r,o.length);let s=t;for(let o=r-1;o>=0;o--){o!==r-1&&(s=s.double());for(let i=0;i<n.length;i++){let c=n[i][o];if(c){let a=e[i][Math.abs(c)-1>>1];s=s.add(c<0?a.negate():a)}}}return s}var Is=class{Point;BASE;ZERO;randomBytes;wnafPrecomputes=new WeakMap;baseCanBeBlinded;bits;constructor(e,n){Cn(e),this.randomBytes=li(n,ii),this.Point=e,this.BASE=e.BASE,this.ZERO=e.ZERO,this.bits=e.Fn.BITS}buildWnafTable(e,n,r){let s=Math.ceil(r/n)+1,o=2**(n-1),i=[],c=e;for(let a=0;a<s;a++){let l=c;for(let d=0;d<o;d++)i.push(l),l=l.add(c);c=i[i.length-1].double()}return{W:n,bits:r,windows:s,comp:i}}wnafCachedCT(e,n){let{W:r,windows:s,comp:o}=e,i=2**(r-1),c=Rd(n,r,s),a=this.ZERO,l=this.BASE;for(let d=0;d<s;d++){let u=c[d],f=d*i,p=Math.abs(u)-1,m=o[f];for(let g=1;g<i;g++)m=g===p?o[f+g]:m;let h=m.negate();u===0?l=l.add(o[f]):a=a.add(u<0?h:m)}return{p:a,f:l}}getWnafPrecomputes(e,n,r,s){let o=this.wnafPrecomputes.get(n),i=o?.find(c=>c.W===e&&c.bits===r);return i||(i=this.buildWnafTable(n,e,r),typeof s=="function"&&(i={...i,comp:s(i.comp)}),o||(o=[],this.wnafPrecomputes.set(n,o)),o.push(i)),i}assertPoint(e){if(!(e instanceof this.Point))throw new TypeError('"point" expected Point instance, got type='+typeof e)}validateMulInput(e,n){if(this.assertPoint(e),!qo(n,_r,this.Point.Fn.ORDER))throw new Error("invalid scalar")}runCT(e,n,r,s){let o=ai(e);return o===1?this.fixedWindowCT(e,n,r):this.wnafCachedCT(this.getWnafPrecomputes(o,e,r,s),n)}mulCT(e,n,r){return this.validateMulInput(e,n),this.runCT(e,n,this.bits,r)}mulCTBlinded(e,n,r){if(this.validateMulInput(e,n),this.randomBytes===void 0)throw new Error("randomBytes is required for scalar blinding");let s=this.Point.Fn.BITS+Ta,o=this.randomBytes(ii);if(!An(o)||o.length!==ii)throw new Error("randomBytes returned invalid byte array");o[0]=o[0]&63|128;let i=n+$e(o)*this.Point.Fn.ORDER;return this.runCT(e,i,s,r)}fixedWindowCT(e,n,r){let s=yd,o=1<<s,i=Er(s),c=new Array(o);c[0]=this.ZERO;for(let d=1;d<o;d++)c[d]=c[d-1].add(e);let a=Math.ceil(r/s),l=this.ZERO;for(let d=a-1;d>=0;d--){if(d!==a-1)for(let p=0;p<s;p++)l=l.double();let u=Number(n>>BigInt(d*s)&i),f=c[0];for(let p=1;p<o;p++)f=p===u?c[p]:f;l=l.add(f)}return{p:l,f:l}}shouldBlind(e,n){return this.randomBytes===void 0?!1:n===_r?!0:e!==this.BASE?!1:(this.baseCanBeBlinded===void 0&&(this.baseCanBeBlinded=this.mulUnsafe(this.BASE,this.Point.Fn.ORDER).is0()),this.baseCanBeBlinded)}mulSecret(e,n,r,s){return this.shouldBlind(e,r)?this.mulCTBlinded(e,n,s):this.mulCT(e,n,s)}mulUnsafe(e,n,r){if(this.assertPoint(e),!xt(n))throw new Error("invalid scalar");let s=ai(e);if(s===1||n>=this.Point.Fn.ORDER)return Us(this.Point,[e],[n],!0);let o=this.getWnafPrecomputes(s,e,this.bits,r);return this.wnafCachedCT(o,n).p}setWindowSize(e,n){this.assertPoint(e),wd(n,this.bits);let r=Math.ceil((this.bits+Ta)/n)+1;bd(r*2**(n-1),this.Point.Fp.BYTES),Ca.set(e,n),this.wnafPrecomputes.delete(e)}hasWindowSize(e){return ai(e)!==1}};function Us(t,e,n,r=!1){if(Cn(t),Pa(e,t),He(r,"allowOversized"),Ed(n,t.Fn,r?t.Fn.ORDER**gd:void 0),e.length!==n.length)throw new Error("arrays of points and scalars must have equal length");let s=e.map(i=>_d(i,4)),o=n.map(i=>Sd(i,4));return Td(t.ZERO,s,o)}function Aa(t,e,n){if(e){if(e.ORDER!==t)throw new Error("Field.ORDER must match order: Fp == p, Fn == n");return Pn(e),e}else return Os(t,{isLE:n})}function Da(t,e,n={},r){if(t!=="weierstrass"&&t!=="edwards")throw new Error('expected curve type "weierstrass" or "edwards"');if(r===void 0&&(r=t==="edwards"),!e||typeof e!="object")throw new Error(`expected valid ${t} CURVE object`);Qe(n);for(let a of["p","n","h"]){let l=e[a];if(!(xt(l)&&l!==ci))throw new Error(`CURVE.${a} must be positive bigint`)}let s=Aa(e.p,n.Fp,r),o=Aa(e.n,n.Fn,r),c=["Gx","Gy","a",t==="weierstrass"?"b":"d"];for(let a of c)if(!s.isValid(e[a]))throw new Error(`CURVE.${a} must be valid field element of CURVE.Fp`);return e=Object.freeze(Object.assign({},e)),{CURVE:e,Fp:s,Fn:o}}function ka(t,e){return function(r){let s=t(r);return{secretKey:s,publicKey:e(s)}}}var Ms=class{oHash;iHash;blockLen;outputLen;canXOF=!1;finished=!1;destroyed=!1;constructor(e,n){if(Rn(e),X(n,void 0,"key"),this.iHash=e.create(),typeof this.iHash.update!="function")throw new Error("expected Hash instance");this.blockLen=this.iHash.blockLen,this.outputLen=this.iHash.outputLen;let r=this.blockLen,s=new Uint8Array(r);s.set(n.length>r?e.create().update(n).digest():n);for(let o=0;o<s.length;o++)s[o]^=54;this.iHash.update(s),this.oHash=e.create();for(let o=0;o<s.length;o++)s[o]^=106;this.oHash.update(s),Rt(s)}update(e){return nt(this),this.iHash.update(e),this}digestInto(e){nt(this),Tn(e,this),this.finished=!0;let n=e.subarray(0,this.outputLen);this.iHash.digestInto(n),this.oHash.update(n),this.oHash.digestInto(n),this.destroy()}digest(){let e=new Uint8Array(this.oHash.outputLen);return this.digestInto(e),e}_cloneInto(e){e||=Object.create(Object.getPrototypeOf(this),{});let{oHash:n,iHash:r,finished:s,destroyed:o,blockLen:i,outputLen:c,canXOF:a}=this;return e=e,e.finished=s,e.destroyed=o,e.blockLen=i,e.outputLen=c,e.canXOF=a,e.oHash=n._cloneInto(e.oHash),e.iHash=r._cloneInto(e.iHash),e}clone(){return this._cloneInto()}destroy(){this.destroyed=!0,this.oHash.destroy(),this.iHash.destroy()}},La=(()=>{let t=((e,n,r)=>new Ms(e,n).update(r).digest());return t.create=(e,n)=>new Ms(e,n),t})();var xd=BigInt(0),di=class extends Error{constructor(e=""){super(e)}},rt={Err:di,_tlv:{encode:(t,e)=>{let{Err:n}=rt;if(Kt(t,"tag"),t<0||t>255)throw new n("tlv.encode: wrong tag");if(ca(e,"data"),e.length&1)throw new n("tlv.encode: unpadded data");let r=e.length/2,s=wr(r);if(s.length/2&128)throw new n("tlv.encode: long form length too big");let o=r>127?wr(s.length/2|128):"";return wr(t)+o+s+e},decode(t,e){let{Err:n}=rt;e=fe(e,void 0,"DER data");let r=0;if(t<0||t>255)throw new n("tlv.decode: wrong tag");if(e.length<2||e[r++]!==t)throw new n("tlv.decode: wrong tlv");let s=e[r++],o=!!(s&128),i=0;if(!o)i=s;else{let a=s&127;if(!a)throw new n("tlv.decode(long): indefinite length not supported");if(a>4)throw new n("tlv.decode(long): byte length is too big");let l=e.subarray(r,r+a);if(l.length!==a)throw new n("tlv.decode: length bytes not complete");if(l[0]===0)throw new n("tlv.decode(long): zero leftmost byte");for(let d of l)i=i<<8|d;if(r+=a,i<128)throw new n("tlv.decode(long): not minimal encoding")}let c=e.subarray(r,r+i);if(c.length!==i)throw new n("tlv.decode: wrong value length");return{v:c,l:e.subarray(r+i)}}},_int:{encode(t){let{Err:e}=rt;if(Ds(t),t<xd)throw new e("integer: negative integers are not allowed");let n=wr(t);if(Number.parseInt(n[0],16)&8&&(n="00"+n),n.length&1)throw new e("unexpected DER parsing assertion: unpadded hex");return n},decode(t){let{Err:e}=rt;if(t.length<1)throw new e("invalid signature integer: empty");if(t[0]&128)throw new e("invalid signature integer: negative");if(t.length>1&&t[0]===0&&!(t[1]&128))throw new e("invalid signature integer: unnecessary leading zero");return $e(t)}},toSig(t,e){let{Err:n,_int:r,_tlv:s}=rt;if(e!==void 0&&(Kt(e,"maxScalarBytes"),e<1))throw new n("invalid signature: maxScalarBytes must be positive");let o=fe(t,void 0,"signature"),{v:i,l:c}=s.decode(48,o);if(c.length)throw new n("invalid signature: left bytes after parsing");let{v:a,l}=s.decode(2,i),{v:d,l:u}=s.decode(2,l);if(u.length)throw new n("invalid signature: left bytes after parsing");if(e!==void 0&&(a.length>e||d.length>e))throw new n("invalid signature: integer too large");return{r:r.decode(a),s:r.decode(d)}},hexFromSig(t){let{_tlv:e,_int:n}=rt;Qe(t,{r:"bigint",s:"bigint"},{},"sig");let r=e.encode(2,n.encode(t.r)),s=e.encode(2,n.encode(t.s)),o=r+s;return e.encode(48,o)}},Bs=(Object.freeze(rt._tlv),Object.freeze(rt._int),Object.freeze(rt));var Oa=(t,e)=>(t+(t>=0?e:-e)/Na)/e;function Ad(t,e,n){ei("scalar",t,st,n);let[[r,s],[o,i]]=e,c=Oa(i*t,n),a=Oa(-s*t,n),l=t-c*r-a*o,d=-c*s-a*i,u=l<st,f=d<st;u&&(l=-l),f&&(d=-d);let p=Er(Math.ceil(vn(n)/2))+Wt;if(l<st||l>=p||d<st||d>=p)throw new Error("splitScalar (endomorphism): failed for k");return{k1neg:u,k1:l,k2neg:f,k2:d}}function fi(t){if(!["compact","recovered","der"].includes(t))throw new Error('Signature format must be "compact", "recovered", or "der"');return t}function ui(t,e){Qe(t);let n={};for(let r of Object.keys(e))n[r]=t[r]===void 0?e[r]:t[r];return He(n.lowS,"lowS"),He(n.prehash,"prehash"),n.format!==void 0&&fi(n.format),n}var st=BigInt(0),Wt=BigInt(1),Na=BigInt(2),pi=BigInt(3),vd=BigInt(4);function Ia(t,e={}){let n=Da("weierstrass",t,e),r=n.Fp,s=n.Fn,o=n.CURVE,{h:i,n:c}=o;Qe(e,{},{allowInfinityPoint:"boolean",clearCofactor:"function",isTorsionFree:"function",fromBytes:"function",toBytes:"function",endo:"object",randomBytes:"function"});let{endo:a,allowInfinityPoint:l,clearCofactor:d,isTorsionFree:u,fromBytes:f,toBytes:p}=e,m=e.randomBytes===void 0?Cs:e.randomBytes;if(a&&(!r.is0(o.a)||typeof a.beta!="bigint"||!Array.isArray(a.basises)))throw new Error('invalid endo: expected "beta": bigint and "basises": array');let h=a?{beta:a.beta,basises:a.basises.map(k=>[...k])}:void 0,g=Ma(r,s);function w(){if(!r.isOdd)throw new Error("compression is not supported: Field does not have .isOdd()")}function b(k,R,A){if(R.is0()){if(!l)throw new Error("bad point: ZERO");return Uint8Array.of(0)}let{x:D,y:O}=R.toAffine(),I=r.toBytes(D);if(He(A,"isCompressed"),A){w();let U=!r.isOdd(O);return Fe(Ua(U),I)}else return Fe(Uint8Array.of(4),I,r.toBytes(O))}function y(k){fe(k,void 0,"Point");let{publicKey:R,publicKeyUncompressed:A}=g,D=k.length,O=k[0],I=k.subarray(1);if(l&&D===1&&O===0)return{x:r.ZERO,y:r.ZERO};if(D===R&&(O===2||O===3)){let U=r.fromBytes(I);if(!r.isValid(U))throw new Error("bad point: is not on curve, wrong x");let $=T(U),B;try{B=r.sqrt($)}catch(W){let J=W instanceof Error?": "+W.message:"";throw new Error("bad point: is not on curve, sqrt error"+J)}w();let F=r.isOdd(B);return(O&1)===1!==F&&(B=r.neg(B)),{x:U,y:B}}else if(D===A&&O===4){let U=r.BYTES,$=r.fromBytes(I.subarray(0,U)),B=r.fromBytes(I.subarray(U,U*2));if(!v($,B))throw new Error("bad point: is not on curve");return{x:$,y:B}}else throw new Error(`bad point: got length ${D}, expected compressed=${R} or uncompressed=${A}`)}let E=p===void 0?b:p,_=f===void 0?y:f,S=r.mul(o.b,pi),x=r.is0(o.a)?k=>r.ZERO:k=>r.mul(o.a,k);function T(k){let R=r.sqr(k),A=r.mul(R,k);return r.add(r.add(A,r.mul(k,o.a)),o.b)}function v(k,R){let A=r.sqr(R),D=T(k);return r.eql(A,D)}if(!v(o.Gx,o.Gy))throw new Error("bad curve params: generator point");let C=r.mul(r.pow(o.a,pi),vd),L=r.mul(r.sqr(o.b),BigInt(27));if(r.is0(r.add(C,L)))throw new Error("bad curve params: a or b");function H(k,R,A=!1){if(!r.isValid(R)||A&&r.is0(R))throw new Error(`bad point coordinate ${k}`);return typeof R=="object"&&R!==null?r.create(R):R}function V(k){if(!(k instanceof K))throw new Error("Weierstrass Point expected")}function Q(k){if(!h||!h.basises)throw new Error("no endo");return Ad(k,h.basises,s.ORDER)}function Z(k,R,A,D){if(!s.isValid(D))throw new RangeError("invalid scalar: out of range");if(h){let{k1neg:O,k1:I,k2neg:U,k2:$}=Q(D),B=new K(r.mul(A.X,h.beta),A.Y,A.Z);k.push(O?A.negate():A,U?B.negate():B),R.push(I,$)}else k.push(A),R.push(D)}let _e=new WeakSet;class K{static BASE=new K(o.Gx,o.Gy,r.ONE);static ZERO=new K(r.ZERO,r.ONE,r.ZERO);static Fp=r;static Fn=s;X;Y;Z;constructor(R,A,D){this.X=H("x",R),this.Y=H("y",A,!0),this.Z=H("z",D),Object.freeze(this)}static CURVE(){return o}static fromAffine(R){let{x:A,y:D}=R||{};if(!R||!r.isValid(A)||!r.isValid(D))throw new Error("invalid affine point");if(R instanceof K)throw new Error("projective point not allowed");return r.is0(A)&&r.is0(D)?K.ZERO:new K(A,D,r.ONE)}static fromBytes(R){let A=K.fromAffine(_(fe(R,void 0,"point")));return A.assertValidity(),A}static fromHex(R){return K.fromBytes(Ps(R))}get x(){return this.toAffine().x}get y(){return this.toAffine().y}precompute(R=6,A=!0){return ie.setWindowSize(this,R),A||this.multiply(pi),this}assertValidity(){let R=this;if(R.is0()){if(l&&r.is0(R.X)&&r.eql(R.Y,r.ONE)&&r.is0(R.Z))return;throw new Error("bad point: ZERO")}if(_e.has(R))return;let{x:A,y:D}=R.toAffine();if(!r.isValid(A)||!r.isValid(D))throw new Error("bad point: x or y not field elements");if(!v(A,D))throw new Error("bad point: equation left != right");if(!R.isTorsionFree())throw new Error("bad point: not in prime-order subgroup");_e.add(R)}hasEvenY(){let{y:R}=this.toAffine();if(!r.isOdd)throw new Error("Field doesn't support isOdd");return!r.isOdd(R)}equals(R){V(R);let{X:A,Y:D,Z:O}=this,{X:I,Y:U,Z:$}=R,B=r.eql(r.mul(A,$),r.mul(I,O)),F=r.eql(r.mul(D,$),r.mul(U,O));return B&&F}negate(){return new K(this.X,r.neg(this.Y),this.Z)}double(){let{X:R,Y:A,Z:D}=this,O=r.ZERO,I=r.ZERO,U=r.ZERO,$=r.mul(R,R),B=r.mul(A,A),F=r.mul(D,D),N=r.mul(R,A);return N=r.add(N,N),U=r.mul(R,D),U=r.add(U,U),O=x(U),I=r.mul(S,F),I=r.add(O,I),O=r.sub(B,I),I=r.add(B,I),I=r.mul(O,I),O=r.mul(N,O),U=r.mul(S,U),F=x(F),N=r.sub($,F),N=x(N),N=r.add(N,U),U=r.add($,$),$=r.add(U,$),$=r.add($,F),$=r.mul($,N),I=r.add(I,$),F=r.mul(A,D),F=r.add(F,F),$=r.mul(F,N),O=r.sub(O,$),U=r.mul(F,B),U=r.add(U,U),U=r.add(U,U),new K(O,I,U)}add(R){V(R);let{X:A,Y:D,Z:O}=this,{X:I,Y:U,Z:$}=R,B=r.ZERO,F=r.ZERO,N=r.ZERO,W=r.mul(A,I),J=r.mul(D,U),te=r.mul(O,$),Pe=r.add(A,D),se=r.add(I,U);Pe=r.mul(Pe,se),se=r.add(W,J),Pe=r.sub(Pe,se),se=r.add(A,O);let ce=r.add(I,$);return se=r.mul(se,ce),ce=r.add(W,te),se=r.sub(se,ce),ce=r.add(D,O),B=r.add(U,$),ce=r.mul(ce,B),B=r.add(J,te),ce=r.sub(ce,B),N=x(se),B=r.mul(S,te),N=r.add(B,N),B=r.sub(J,N),N=r.add(J,N),F=r.mul(B,N),J=r.add(W,W),J=r.add(J,W),te=x(te),se=r.mul(S,se),J=r.add(J,te),te=r.sub(W,te),te=x(te),se=r.add(se,te),W=r.mul(J,se),F=r.add(F,W),W=r.mul(ce,se),B=r.mul(Pe,B),B=r.sub(B,W),W=r.mul(Pe,J),N=r.mul(ce,N),N=r.add(N,W),new K(B,F,N)}subtract(R){return V(R),this.add(R.negate())}is0(){return this.equals(K.ZERO)}multiply(R){if(!s.isValidNot0(R))throw new RangeError("invalid scalar: out of range");let{p:A,f:D}=ie.mulSecret(this,R,i,Se);return Se([A,D])[0]}multiplyUnsafe(R){let A=this,D=R;if(!s.isValid(D))throw new RangeError("invalid scalar: out of range");if(D===st||A.is0())return K.ZERO;if(D===Wt)return A;if(ie.hasWindowSize(this))return ie.mulUnsafe(A,D,Se);let O=[],I=[];return Z(O,I,A,D),Us(K,O,I)}mulAddUnsafe(R,A,D){V(A);let O=[],I=[];return Z(O,I,this,R),Z(O,I,A,D),Us(K,O,I)}toAffine(R){let A=this,D=R;if(D!=null&&!r.isValid(D))throw new RangeError('"invertedZ" expected valid field element');let{X:O,Y:I,Z:U}=A;if(r.eql(U,r.ONE))return{x:O,y:I};let $=A.is0();D==null&&(D=$?r.ONE:r.inv(U));let B=r.mul(O,D),F=r.mul(I,D),N=r.mul(U,D);if($)return{x:r.ZERO,y:r.ZERO};if(!r.eql(N,r.ONE))throw new Error("invZ was invalid");return{x:B,y:F}}isTorsionFree(){return i===Wt?!0:u?u(K,this):ie.mulUnsafe(this,c).is0()}clearCofactor(){return i===Wt?this:d?d(K,this):this.multiplyUnsafe(i)}isSmallOrder(){return i===Wt?this.is0():this.clearCofactor().is0()}toBytes(R=!0){return He(R,"isCompressed"),this.assertValidity(),E(K,this,R)}toHex(R=!0){return Qo(this.toBytes(R))}toString(){return`<Point ${this.is0()?"ZERO":this.toHex()}>`}}let Se=k=>va(K,k),ie=new Is(K,m);return ie.bits>=6&&K.BASE.precompute(6),Object.freeze(K.prototype),Object.freeze(K),K}function Ua(t){return Uint8Array.of(t?2:3)}function Ma(t,e){return{secretKey:e.BYTES,publicKey:1+t.BYTES,publicKeyUncompressed:1+2*t.BYTES,publicKeyHasPrefix:!0,signature:2*e.BYTES}}function Pd(t,e={}){Cn(t);let{Fn:n}=t,r=e.randomBytes===void 0?Cs:e.randomBytes,s=Object.assign(Ma(t.Fp,n),{seed:Math.max(Ns(n.ORDER),16)});function o(p){try{let m=n.fromBytes(p);return n.isValidNot0(m)}catch{return!1}}function i(p,m){let{publicKey:h,publicKeyUncompressed:g}=s;try{let w=p.length;return m===!0&&w!==h||m===!1&&w!==g?!1:!t.fromBytes(p).is0()}catch{return!1}}function c(p){return p=p===void 0?r(s.seed):p,oi(fe(p,s.seed,"seed"),n.ORDER)}function a(p,m=!0){return t.BASE.multiply(n.fromBytes(p)).toBytes(m)}function l(p){let{secretKey:m,publicKey:h,publicKeyUncompressed:g}=s,w=n._lengths;if(!An(p))return;let b=fe(p,void 0,"key").length,y=b===h||b===g,E=b===m||!!w?.includes(b);if(!(y&&E))return y}function d(p,m,h=!0){if(l(p)===!0)throw new Error("first arg must be private key");if(l(m)===!1)throw new Error("second arg must be public key");let g=n.fromBytes(p),w=t.fromBytes(m);if(w.is0())throw new Error("invalid public key: point at infinity");return w.multiply(g).toBytes(h)}let u={isValidSecretKey:o,isValidPublicKey:i,randomSecretKey:c},f=ka(c,a);return Object.freeze(u),Object.freeze(s),Object.freeze({getPublicKey:a,getSharedSecret:d,keygen:f,Point:t,utils:u,lengths:s})}function Ba(t,e,n={}){Cn(t);let r=e;Rn(r),Qe(n,{},{hmac:"function",lowS:"boolean",randomBytes:"function",bits2int:"function",bits2int_modN:"function"});let s=Object.assign({},n),o=s.randomBytes===void 0?Cs:s.randomBytes,i=s.hmac===void 0?(k,R)=>La(r,k,R):s.hmac,{Fp:c,Fn:a}=t,{ORDER:l,BITS:d}=a,u=Ns(l),f=li(o,u),{keygen:p,getPublicKey:m,getSharedSecret:h,utils:g,lengths:w}=Pd(t,s),b={prehash:!0,lowS:typeof s.lowS=="boolean"?s.lowS:!0,format:"compact",extraEntropy:!1},y=l*Na+Wt<c.ORDER;function E(k){let R=l>>Wt;return k>R}function _(k,R){if(!a.isValidNot0(R))throw new Error(`invalid signature ${k}: out of range 1..Point.Fn.ORDER`);return R}function S(){if(!c.isOdd)throw new Error("Field doesn't support isOdd")}function x(k,R,A){return S(),(k===A?0:2)|Number(c.isOdd(R))}function T(){if(y)throw new Error('"recovered" sig type is not supported for cofactor >2 curves')}function v(k,R){fi(R);let A=w.signature,D=R==="compact"?A:R==="recovered"?A+1:void 0;return fe(k,D)}class C{r;s;recovery;constructor(R,A,D){if(this.r=_("r",R),this.s=_("s",A),D!=null){if(T(),![0,1,2,3].includes(D))throw new Error("invalid recovery id");this.recovery=D}Object.freeze(this)}static fromBytes(R,A=b.format){v(R,A);let D;if(A==="der"){if(R.length>2*a.BYTES+16)throw new Bs.Err("invalid signature: DER signature too long");let{r:$,s:B}=Bs.toSig(fe(R),a.BYTES+1);return new C($,B)}A==="recovered"&&(D=R[0],A="compact",R=R.subarray(1));let O=w.signature/2,I=R.subarray(0,O),U=R.subarray(O,O*2);return new C(a.fromBytes(I),a.fromBytes(U),D)}static fromHex(R,A){return this.fromBytes(Ps(R),A)}assertRecovery(){let{recovery:R}=this;if(R==null)throw new Error("invalid recovery id: must be present");return R}addRecoveryBit(R){return new C(this.r,this.s,R)}recoverPublicKey(R){let{r:A,s:D}=this,O=this.assertRecovery(),I=O===2||O===3?A+l:A;if(!c.isValid(I))throw new Error("invalid recovery id: sig.r+curve.n != R.x");let U=c.toBytes(I),$=t.fromBytes(Fe(Ua((O&1)===0),U)),B=a.inv(I),F=H(fe(R,void 0,"msgHash")),N=a.create(-F*B),W=a.create(D*B),J=t.BASE.mulAddUnsafe(N,$,W);if(J.is0())throw new Error("invalid recovery: point at infinify");return J.assertValidity(),J}hasHighS(){return E(this.s)}toBytes(R=b.format){if(fi(R),R==="der")return Ps(Bs.hexFromSig(this));let{r:A,s:D}=this,O=a.toBytes(A),I=a.toBytes(D);return R==="recovered"?(T(),Fe(Uint8Array.of(this.assertRecovery()),O,I)):Fe(O,I)}toHex(R){return Qo(this.toBytes(R))}}Object.freeze(C.prototype),Object.freeze(C);let L=s.bits2int===void 0?function(R){if(R.length>8192)throw new Error("input is too large");let A=$e(R),D=R.length*8-d;return D>0?A>>BigInt(D):A}:s.bits2int,H=s.bits2int_modN===void 0?function(R){return a.create(L(R))}:s.bits2int_modN,V=Er(d);function Q(k){return ei("num < 2^"+d,k,st,V),a.toBytes(k)}function Z(k,R){return fe(k,void 0,"message"),R?fe(r(k),void 0,"prehashed message"):k}function _e(k,R,A){let{lowS:D,prehash:O,extraEntropy:I}=ui(A,b);k=Z(k,O);let U=H(k),$=a.fromBytes(R);if(!a.isValidNot0($))throw new Error("invalid private key");let B=[Q($),Q(U)];if(I!=null&&I!==!1){let J=I===!0?o(w.secretKey):I;B.push(fe(J,void 0,"extraEntropy"))}let F=Fe(...B),N=U;function W(J){let te=L(J);if(!a.isValidNot0(te))return;let Pe=t.BASE.multiply(te).toAffine(),se=a.create(Pe.x);if(se===st)return;let ce;if(f!==void 0){let Gn=$e(oi(f(u),l)),Pl=a.inv(a.mul(Gn,te)),Cl=a.mul(Gn,N),Dl=a.mul(Gn,$);ce=a.create(Pl*a.create(Cl+Dl*se))}else{let Gn=Ea(te,l);ce=a.create(Gn*a.create(N+se*$))}if(ce===st)return;let Eo=x(Pe.x,Pe.y,se),Ii=ce;return D&&E(ce)&&(Ii=a.neg(ce),Eo^=1),new C(se,Ii,y?void 0:Eo)}return{seed:F,k2sig:W}}function K(k,R,A={}){let{seed:D,k2sig:O}=_e(k,R,A);return ua(r.outputLen,a.BYTES,i)(D,O).toBytes(A.format)}function Se(k,R,A,D={}){let{lowS:O,prehash:I,format:U}=ui(D,b);if(A=fe(A,void 0,"publicKey"),R=Z(R,I),!An(k)){let $=k instanceof C?", use sig.toBytes()":"";throw new Error("verify expects Uint8Array signature"+$)}v(k,U);try{let $=C.fromBytes(k,U),B=t.fromBytes(A);if(B.is0()||O&&$.hasHighS())return!1;let{r:F,s:N}=$,W=H(R),J=a.inv(N),te=a.create(W*J),Pe=a.create(F*J),se=t.BASE.mulAddUnsafe(te,B,Pe);if(se.is0())return!1;let ce=se.toAffine();return!(a.create(ce.x)!==F||U==="recovered"&&$.recovery!==x(ce.x,ce.y,F))}catch{return!1}}function ie(k,R,A={}){let{prehash:D}=ui(A,b);return R=Z(R,D),C.fromBytes(k,"recovered").recoverPublicKey(R).toBytes()}return Object.freeze({keygen:p,getPublicKey:m,getSharedSecret:h,utils:g,lengths:w,Point:t,sign:K,verify:Se,recoverPublicKey:ie,Signature:C,hash:r})}var Fs=BigInt(4294967295),Fa=BigInt(32);function Cd(t,e=!1){return e?{h:Number(t&Fs),l:Number(t>>Fa&Fs)}:{h:Number(t>>Fa&Fs)|0,l:Number(t&Fs)|0}}function Ha(t,e=!1){let n=t.length,r=new Uint32Array(n),s=new Uint32Array(n);for(let o=0;o<n;o++){let{h:i,l:c}=Cd(t[o],e);[r[o],s[o]]=[i,c]}return[r,s]}var Dd=t=>t/2**32|0,kd=t=>t>>>0;function $a(t,e,n,r){let s=Dd(n),o=kd(n);t.setUint32(e,r?o:s,r),t.setUint32(e+4,r?s:o,r)}function Ka(t,e,n){return t&e^~t&n}function Wa(t,e,n){return t&e^t&n^e&n}var Hs=class{blockLen;outputLen;canXOF=!1;padOffset;isLE;buffer;view;finished=!1;length=0;pos=0;destroyed=!1;constructor(e,n,r,s){this.blockLen=e,this.outputLen=n,this.padOffset=r,this.isLE=s,this.buffer=new Uint8Array(e),this.view=xs(this.buffer)}update(e){nt(this),X(e);let{view:n,buffer:r,blockLen:s}=this,o=e.length,i=!1;for(let c=0;c<o;){let a=Math.min(s-this.pos,o-c);if(a===s){let l=xs(e);for(;s<=o-c;c+=s)this.process(l,c);i=!0;continue}r.set(c===0&&a===o?e:e.subarray(c,c+a),this.pos),this.pos+=a,c+=a,this.pos===s&&(this.process(n,0),this.pos=0,i=!0)}return this.length+=e.length,i&&this.roundClean(),this}digestInto(e){nt(this),Tn(e,this),this.finished=!0;let{buffer:n,view:r,blockLen:s,isLE:o}=this,{pos:i}=this;n[i++]=128,n.fill(0,i),this.padOffset>s-i&&(this.process(r,0),n.fill(0)),$a(r,s-8,this.length*8,o),this.process(r,0),this.roundClean();let c=e===n?r:xs(e),a=this.outputLen,l=a/4,d=this.get();if(a%4||l>d.length)throw new Error("invalid outputLen");for(let u=0;u<l;u++)c.setUint32(4*u,d[u],o)}digest(){let{buffer:e,outputLen:n}=this;this.digestInto(e);let r=e.slice(0,n);return this.destroy(),r}_cloneIntoMeta(e){let{buffer:n,length:r,finished:s,destroyed:o,pos:i}=this;return e.destroyed=o,e.finished=s,e.length=r,e.pos=i,i&&e.buffer.set(n),e}clone(){return this._cloneInto()}},ja=Uint32Array.from([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]);var Ld=Uint32Array.from([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),vt=new Uint32Array(64),mi=class extends Hs{A=0;B=0;C=0;D=0;E=0;F=0;G=0;H=0;constructor(e,n){super(64,e,8,!1),this.A=n[0]|0,this.B=n[1]|0,this.C=n[2]|0,this.D=n[3]|0,this.E=n[4]|0,this.F=n[5]|0,this.G=n[6]|0,this.H=n[7]|0}get(){let{A:e,B:n,C:r,D:s,E:o,F:i,G:c,H:a}=this;return[e,n,r,s,o,i,c,a]}set(e,n,r,s,o,i,c,a){this.A=e|0,this.B=n|0,this.C=r|0,this.D=s|0,this.E=o|0,this.F=i|0,this.G=c|0,this.H=a|0}_cloneInto(e){return(e||=new this.constructor).set(...this.get()),this._cloneIntoMeta(e)}process(e,n){for(let u=0;u<16;u++,n+=4)vt[u]=e.getUint32(n,!1);for(let u=16;u<64;u++){let f=vt[u-15],p=vt[u-2],m=Be(f,7)^Be(f,18)^f>>>3,h=Be(p,17)^Be(p,19)^p>>>10;vt[u]=h+vt[u-7]+m+vt[u-16]|0}let{A:r,B:s,C:o,D:i,E:c,F:a,G:l,H:d}=this;for(let u=0;u<64;u++){let f=Be(c,6)^Be(c,11)^Be(c,25),p=d+f+Ka(c,a,l)+Ld[u]+vt[u]|0,h=(Be(r,2)^Be(r,13)^Be(r,22))+Wa(r,s,o)|0;d=l,l=a,a=c,c=i+p|0,i=o,o=s,s=r,r=p+h|0}r=r+this.A|0,s=s+this.B|0,o=o+this.C|0,i=i+this.D|0,c=c+this.E|0,a=a+this.F|0,l=l+this.G|0,d=d+this.H|0,this.set(r,s,o,i,c,a,l,d)}roundClean(){Rt(vt)}destroy(){this.destroyed=!0,this.set(0,0,0,0,0,0,0,0),Rt(this.buffer)}},hi=class extends mi{constructor(){super(32,ja)}};var Va=gr(()=>new hi,$t(1));function Sr(t,e="n"){if(typeof t!="number")throw new TypeError(`wrong u32 integer "${e}": expected number, got type=${typeof t}`);if(!Number.isSafeInteger(t)||t<0||t>4294967295)throw new RangeError(`wrong u32 integer "${e}": expected 0..4294967295, got ${t}`);return t}function Ga(t){return Sr(t,"x"),(t&t-1)===0&&t!==0}function gi(t,e){if(Sr(t),typeof e!="number")throw new TypeError('"bits" expected number, got type='+typeof e);if(!Number.isSafeInteger(e)||e<0||e>32)throw new Error(`expected integer 0 <= bits <= 32, got ${e}`);let n=0;for(let r=0;r<e;r++,t>>>=1)n=n<<1|t&1;return n>>>0}function Ya(t){return Sr(t),31-Math.clz32(t)}function Ja(t){if(!t||typeof t!="object"||typeof t.length!="number")throw new TypeError('"values" expected array-like, got type='+typeof t);let e=t.length;if(!Ga(e))throw new Error("expected positive power-of-two length, got "+e);let n=Ya(e);for(let r=0;r<e;r++){let s=gi(r,n);if(r<s){let o=t[r];t[r]=t[s],t[s]=o}}return t}var yi=(t,e)=>{Qe(e,{N:"number",roots:"object",dit:"boolean"},{invertButterflies:"boolean",skipStages:"number",brp:"boolean"},"coreOpts");let{N:n,roots:r,dit:s,invertButterflies:o=!1,skipStages:i=0,brp:c=!0}=e;Sr(n,"coreOpts.N");let a=Ya(n);if(!Ga(n))throw new Error("FFT: Polynomial size should be power of two");Sr(i,"coreOpts.skipStages");let l=a===0?0:a-1;if(i>l)throw new Error(`FFT: wrong skipStages: expected 0 <= skipStages <= ${l}`);if(r.length!==n)throw new Error(`FFT: wrong roots length: expected ${n}, got ${r.length}`);let d=s!==o;return u=>{if(u.length!==n)throw new Error("FFT: wrong Polynomial length");s&&c&&Ja(u);for(let f=0,p=1;f<a-i;f++){let m=s?f+1+i:a-f,h=1<<m,g=h>>1,w=n>>m;for(let b=0;b<n;b+=h)for(let y=0,E=p++;y<g;y++){let _=o?s?n-E:E:y*w,S=b+y,x=b+y+g,T=r[_],v=u[x],C=u[S];if(d){let L=t.mul(v,T);u[S]=t.add(C,L),u[x]=t.sub(C,L)}else o?(u[S]=t.add(v,C),u[x]=t.mul(t.sub(v,C),T)):(u[S]=t.add(C,v),u[x]=t.mul(t.sub(C,v),T))}}return!s&&c&&Ja(u),u}};var Od={p:BigInt("0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"),n:BigInt("0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"),h:BigInt(1),a:BigInt("0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc"),b:BigInt("0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b"),Gx:BigInt("0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"),Gy:BigInt("0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5")};var Nd=Ia(Od),Xa=Ba(Nd,Va);var Id=BigInt(0),Rr=BigInt(1),Ud=BigInt(2),Md=BigInt(7),Bd=BigInt(256),Fd=BigInt(113),Za=[],qa=[],ec=[];for(let t=0,e=Rr,n=1,r=0;t<24;t++){[n,r]=[r,(2*n+3*r)%5],Za.push(2*(5*r+n)),qa.push((t+1)*(t+2)/2%64);let s=Id;for(let o=0;o<7;o++)e=(e<<Rr^(e>>Md)*Fd)%Bd,e&Ud&&(s^=Rr<<(Rr<<BigInt(o))-Rr);ec.push(s)}var tc=Ha(ec,!0),Hd=tc[0],$d=tc[1],Kd=(t,e,n)=>t<<n|e>>>32-n,Wd=(t,e,n)=>e<<n|t>>>32-n,jd=(t,e,n)=>e<<n-32|t>>>64-n,Vd=(t,e,n)=>t<<n-32|e>>>64-n,za=(t,e,n)=>n>32?jd(t,e,n):Kd(t,e,n),Qa=(t,e,n)=>n>32?Vd(t,e,n):Wd(t,e,n),Dn=new Uint32Array(10);function Jd(t,e=24){if(!(t instanceof Uint32Array))throw new TypeError('"s" expected Uint32Array(50), got type='+typeof t);if(t.length!==50)throw new RangeError('"s" expected Uint32Array(50), got length='+t.length);if(ue(e,"rounds"),e<1||e>24)throw new Error('"rounds" expected integer 1..24');for(let n=24-e;n<24;n++){for(let o=0;o<10;o++)Dn[o]=t[o]^t[o+10]^t[o+20]^t[o+30]^t[o+40];for(let o=0;o<10;o+=2){let i=(o+8)%10,c=(o+2)%10,a=Dn[c],l=Dn[c+1],d=za(a,l,1)^Dn[i],u=Qa(a,l,1)^Dn[i+1];for(let f=0;f<50;f+=10)t[o+f]^=d,t[o+f+1]^=u}let r=t[2],s=t[3];for(let o=0;o<24;o++){let i=qa[o],c=za(r,s,i),a=Qa(r,s,i),l=Za[o];r=t[l],s=t[l+1],t[l]=c,t[l+1]=a}for(let o=0;o<50;o+=10){let i=t[o],c=t[o+1],a=t[o+2],l=t[o+3];t[o]^=~t[o+2]&t[o+4],t[o+1]^=~t[o+3]&t[o+5],t[o+2]^=~t[o+4]&t[o+6],t[o+3]^=~t[o+5]&t[o+7],t[o+4]^=~t[o+6]&t[o+8],t[o+5]^=~t[o+7]&t[o+9],t[o+6]^=~t[o+8]&i,t[o+7]^=~t[o+9]&c,t[o+8]^=~i&a,t[o+9]^=~c&l}t[0]^=Hd[n],t[1]^=$d[n]}Rt(Dn)}var $s=class t{state;pos=0;posOut=0;finished=!1;state32;destroyed=!1;blockLen;suffix;outputLen;canXOF;enableXOF=!1;rounds;constructor(e,n,r,s=!1,o=24){if(ue(e,"blockLen"),ue(n,"suffix"),ue(o,"rounds"),sa(s,"enableXOF"),this.blockLen=e,this.suffix=n,this.outputLen=r,this.enableXOF=s,this.canXOF=s,this.rounds=o,ue(r,"outputLen"),!(0<e&&e<200))throw new Error('"blockLen" must be 1..199');this.state=new Uint8Array(200),this.state32=mr(this.state)}clone(){return this._cloneInto()}keccak(){xn(this.state32),Jd(this.state32,this.rounds),xn(this.state32),this.posOut=0,this.pos=0}update(e){nt(this),X(e);let{blockLen:n,state:r,state32:s}=this,o=e.length,i=n%4===0&&e.byteOffset%4===0,c=n/4,a=i&&o>=n?mr(e):void 0;for(let l=0;l<o;){if(a!==void 0&&this.pos===0&&l%4===0&&o-l>=n){for(let u=0,f=l/4;u<c;u++)s[u]^=a[f+u];l+=n,this.pos=n,this.keccak();continue}let d=Math.min(n-this.pos,o-l);for(let u=0;u<d;u++)r[this.pos++]^=e[l++];this.pos===n&&this.keccak()}return this}finish(){if(this.finished)return;this.finished=!0;let{state:e,suffix:n,pos:r,blockLen:s}=this;e[r]^=n,(n&128)!==0&&r===s-1&&this.keccak(),e[s-1]^=128,this.keccak()}writeInto(e){nt(this,!1),X(e),this.finish();let n=this.state,{blockLen:r}=this;for(let s=0,o=e.length;s<o;){this.posOut>=r&&this.keccak();let i=Math.min(r-this.posOut,o-s);e.set(n.subarray(this.posOut,this.posOut+i),s),this.posOut+=i,s+=i}return e}xofInto(e){if(!this.enableXOF)throw new Error("XOF is not enabled");return this.writeInto(e)}xof(e){return ue(e),this.xofInto(new Uint8Array(e))}digestInto(e){if(Tn(e,this),this.finished)throw new Error("digest() was already called");this.writeInto(e.length===this.outputLen?e:e.subarray(0,this.outputLen)),this.destroy()}digest(){let e=new Uint8Array(this.outputLen);return this.digestInto(e),e}destroy(){this.destroyed=!0,Rt(this.state)}_cloneInto(e){let{blockLen:n,suffix:r,outputLen:s,rounds:o,enableXOF:i}=this;return e||=new t(n,r,s,i,o),e.blockLen=n,e.state32.set(this.state32),e.pos=this.pos,e.posOut=this.posOut,e.finished=this.finished,e.rounds=o,e.suffix=r,e.outputLen=s,e.enableXOF=i,e.canXOF=this.canXOF,e.destroyed=this.destroyed,e}},nc=(t,e,n,r={})=>gr(()=>new $s(e,t,n),r);var Ks=nc(6,136,32,$t(8));var rc=nc(6,72,64,$t(10));var sc=(t,e,n,r={})=>gr((s={})=>(s=Xo({},s),new $s(e,t,s.dkLen===void 0?n:s.dkLen,!0)),r),oc=sc(31,168,16,$t(11)),kn=sc(31,136,32,$t(12));var Ke=X;var ot=As;function Gd(t,e,n=()=>{}){if(!Array.isArray(t))throw new TypeError(`"${e}" expected array, got type=${typeof t}`);for(let r=0;r<t.length;r++)n(t[r],`${e}[${r}]`);return t}function wi(t,e="object"){if(t===null||typeof t!="object"||Array.isArray(t))throw new TypeError(e==="object"?"expected valid options object":`"${e}" expected object, got type=${typeof t}`);return t}function jt(t,e){if(t=X(t),e=X(e),t.length!==e.length)return!1;let n=0;for(let r=0;r<t.length;r++)n|=t[r]^e[r];return n===0}function it(t){return new Uint8Array(X(t))}function Vt(t,...e){let n=s=>typeof s=="number"?s:s.bytesLen,r=e.reduce((s,o)=>s+n(o),0);return{bytesLen:r,encode:s=>{let o=new Uint8Array(r);for(let i=0,c=0;i<e.length;i++){let a=e[i],l=n(a),d=typeof a=="number"?s[i]:a.encode(s[i]);X(d,l,t),o.set(d,c),typeof a!="number"&&d.fill(0),c+=l}return o},decode:s=>{X(s,r,t);let o=[];for(let i of e){let c=n(i),a=s.subarray(0,c);o.push(typeof i=="number"?a:i.decode(a)),s=s.subarray(c)}return o}}}function Ws(t,e){let n=t,r=e*n.bytesLen;return{bytesLen:r,encode:s=>{let o=Gd(s,"u");if(o.length!==e)throw new RangeError(`vecCoder.encode: wrong length=${o.length}. Expected: ${e}`);let i=new Uint8Array(r);for(let c=0,a=0;c<o.length;c++){let l=n.encode(o[c]);i.set(l,a),l.fill(0),a+=l.length}return i},decode:s=>{X(s,r);let o=[];for(let i=0;i<s.length;i+=n.bytesLen)o.push(n.decode(s.subarray(i,i+n.bytesLen)));return o}}}function z(...t){for(let e of t)if(Array.isArray(e))for(let n of e)n.fill(0);else e.fill(0)}function js(t){if(ue(t,"bits"),t>32)throw new RangeError('"bits" expected <= 32, got '+t);return t===32?4294967295:~(-1<<t)>>>0}var ic=t=>{let{newPoly:e,N:n,Q:r,F:s,ROOT_OF_UNITY:o,brvBits:i,isKyber:c}=t,a=(y,E=r)=>{let _=y%E|0;return(_>=0?_|0:E+_|0)|0},l=(y,E=r)=>{let _=a(y,E)|0;return(_>E>>1?_-E|0:_)|0};function d(){let y=e(n);for(let E=0;E<n;E++){let _=gi(E,i),S=BigInt(o)**BigInt(_)%BigInt(r);y[E]=Number(S)|0}return y}let u=d(),f=y=>{throw new Error("not implemented")},p=c?{add:(y,E)=>{let _=y+E|0;return _>=r?_-r|0:_},sub:(y,E)=>{let _=y-E|0;return _<0?_+r|0:_},mul:(y,E)=>a((y|0)*(E|0))|0,inv:f}:{add:(y,E)=>a((y|0)+(E|0))|0,sub:(y,E)=>a((y|0)-(E|0))|0,mul:(y,E)=>a((y|0)*(E|0))|0,inv:f},m={N:n,roots:u,invertButterflies:!0,skipStages:c?1:0,brp:!1},h=yi(p,{dit:!1,...m}),g=yi(p,{dit:!0,...m}),w={encode:y=>h(y),decode:y=>{g(y);for(let E=0;E<y.length;E++)y[E]=a(s*y[E]);return y}};return{mod:a,smod:l,nttZetas:u,NTT:{encode:y=>w.encode(y),decode:y=>w.decode(y)},bitsCoder:(y,E)=>{for(let x=0,T=0;x<n;x++)T+=y,T>32&&js(T),T%=8;let _=js(y),S=y*(n/8);return{bytesLen:S,encode:x=>{let T=x,v=new Uint8Array(S);for(let C=0,L=0,H=0,V=0;C<T.length;C++)for(L|=(E.encode(T[C])&_)<<H,H+=y;H>=8;H-=8,L>>=8)v[V++]=L&255;return v},decode:x=>{let T=e(n);for(let v=0,C=0,L=0,H=0;v<x.length;v++)for(C|=x[v]<<L,L+=8;L>=y;L-=y,C>>=y)T[H++]=E.decode(C&_);return T}}}}},Yd=t=>(e,n)=>{n||(n=t.blockLen);let r=new Uint8Array(e.length+2);r.set(e);let s=e.length,o=new Uint8Array(n),i=t.create({}),c=0,a=0;return{stats:()=>({calls:c,xofs:a}),get:(l,d)=>(r[s+0]=l,r[s+1]=d,i.destroy(),i=t.create({}).update(r),c++,()=>(a++,i.xofInto(o))),clean:()=>{i.destroy(),z(o,r)}}},ac=Yd(oc);var be=256,we=3329,Xd=3303,zd=17,xe=ic({N:be,Q:we,F:Xd,ROOT_OF_UNITY:zd,newPoly:t=>new Uint16Array(t),brvBits:7,isKyber:!0}),Qd=Object.freeze({512:Object.freeze({N:be,Q:we,K:2,ETA1:3,ETA2:2,du:10,dv:4,RBGstrength:128}),768:Object.freeze({N:be,Q:we,K:3,ETA1:2,ETA2:2,du:10,dv:4,RBGstrength:192}),1024:Object.freeze({N:be,Q:we,K:4,ETA1:2,ETA2:2,du:11,dv:5,RBGstrength:256})}),Zd=t=>{if(t>=12)return{encode:n=>n,decode:n=>n>=we?n-we:n};let e=2**(t-1);return{encode:n=>((n<<t)+we/2)/we,decode:n=>n*we+e>>>t}},qd=t=>xe.bitsCoder(t,t===12?{encode:e=>e,decode:e=>e>=we?e-we:e}:{encode:e=>e,decode:e=>e}),Tr=t=>t===12?qd(12):xe.bitsCoder(t,Zd(t));function Jt(t,e){let n=t,r=e;for(let s=0;s<be;s++){let o=n[s]+r[s];n[s]=o>=we?o-we:o}}function eu(t,e){let n=t,r=e;for(let s=0;s<be;s++){let o=n[s]-r[s];n[s]=o<0?o+we:o}}function tu(t,e,n,r,s){let o=xe.mod(xe.mod(e*r)*s+t*n),i=xe.mod(t*r+e*n);return{c0:o,c1:i}}function Vs(t,e){let n=t,r=e;for(let s=0;s<be/2;s++){let o=xe.nttZetas[64+(s>>1)];s&1&&(o=-o);let{c0:i,c1:c}=tu(n[2*s+0],n[2*s+1],r[2*s+0],r[2*s+1],o);n[2*s+0]=i,n[2*s+1]=c}return n}function bi(t){let e=t,n=new Uint16Array(be);for(let r=0;r<be;){let s=e();if(s.length%3)throw new Error("SampleNTT: unaligned block");for(let o=0;r<be&&o+3<=s.length;o+=3){let i=(s[o+0]>>0|s[o+1]<<8)&4095,c=(s[o+1]>>4|s[o+2]<<4)&4095;i<we&&(n[r++]=i),r<be&&c<we&&(n[r++]=c)}}return n}var nu=(t,e)=>{let n=new Uint16Array(be),r=mr(t);xn(r);let s=0;for(let o=0,i=0,c=0,a=0;o<r.length;o++){let l=r[o];for(let d=0;d<32;d++)c+=l&1,l>>=1,s+=1,s===e?(a=c,c=0):s===2*e&&(n[i++]=xe.mod(a-c),c=0,s=0)}if(xn(r),s)throw new Error(`sampleCBD: leftover bits: ${s}`);return n};function xr(t,e,n,r){return nu(t(r*be/4,e,n),r)}var ru=t=>{let e=t,{K:n,PRF:r,XOF:s,HASH512:o,ETA1:i,ETA2:c,du:a,dv:l}=e,d=Tr(1),u=Tr(l),f=Tr(a),p=Vt("publicKey",Ws(Tr(12),n),32),m=Ws(Tr(12),n),h=Vt("ciphertext",Ws(f,n),u),g=Vt("seed",32,32),w=(b,y,E,_)=>{let S=[];for(let L=0;L<n;L++)S.push(xe.NTT.encode(xr(r,_,L,i)));let x=new Uint16Array(be),T=[];for(let L=0;L<n;L++){let H=xr(r,_,n+L,c),V=new Uint16Array(be);for(let Q=0;Q<n;Q++){let Z=y(L,Q);Jt(V,Vs(Z,S[Q]))}Jt(H,xe.NTT.decode(V)),T.push(H),Jt(x,Vs(b[L],S[L])),z(V)}let v=xr(r,_,2*n,c);Jt(v,xe.NTT.decode(x));let C=d.decode(E);return Jt(C,v),z(b,S,x,v),h.encode([T,C])};return{secretCoder:m,lengths:{secretKey:m.bytesLen,publicKey:p.bytesLen,cipherText:h.bytesLen},keygen:b=>{Ke(b,32,"seed");let y=new Uint8Array(33);y.set(b),y[32]=n;let E=o(y),[_,S]=g.decode(E),x=[],T=[];for(let L=0;L<n;L++)x.push(xe.NTT.encode(xr(r,S,L,i)));let v=s(_);for(let L=0;L<n;L++){let H=xe.NTT.encode(xr(r,S,n+L,i));for(let V=0;V<n;V++){let Q=bi(v.get(V,L));Jt(H,Vs(Q,x[V]))}T.push(H)}v.clean();let C={publicKey:p.encode([T,_]),secretKey:m.encode(x)};return z(_,S,x,T,y,E),C},encrypt:(b,y,E)=>{let[_,S]=p.decode(b),x=s(S),T=w(_,(v,C)=>bi(x.get(v,C)),y,E);return x.clean(),T},prepare:b=>{let[y,E]=p.decode(b),_=s(E),S=[];for(let x=0;x<n;x++)for(let T=0;T<n;T++)S.push(bi(_.get(x,T)));return _.clean(),{encrypt:(x,T)=>w(y.map(v=>v.slice()),(v,C)=>S[v*n+C].slice(),x,T),clean:()=>z(y,S)}},decrypt:(b,y)=>{let[E,_]=h.decode(b),S=m.decode(y),x=new Uint16Array(be);for(let v=0;v<n;v++)Jt(x,Vs(S[v],xe.NTT.encode(E[v])));eu(_,xe.NTT.decode(x));let T=d.encode(_);return z(x,S,E,_),T}}};function su(t){let e=t,n=ru(e),{HASH256:r,HASH512:s,KDF:o}=e,{secretCoder:i,lengths:c}=n,a=Vt("secretKey",c.secretKey,c.publicKey,32,32),l=32,d=64,u=(p,m)=>{let h=p.subarray(0,384*e.K),g=i.encode(i.decode(it(h))),w=jt(g,h);if(z(g),!w)throw new Error(`ML-KEM.${m}: wrong publicKey modulus`)},f=Object.freeze({...c,seed:64,msg:l,msgRand:l,secretKey:a.bytesLen});return Object.freeze({info:Object.freeze({type:"ml-kem"}),lengths:f,keygen:p=>{let m=p===void 0,h=m?ot(d):p,g,w;try{Ke(h,d,"seed");let b=n.keygen(h.subarray(0,32)),y=b.publicKey;g=b.secretKey,w=r(y);let E=a.encode([g,y,w,h.subarray(32)]);return{publicKey:y,secretKey:E}}finally{g!==void 0&&z(g),w!==void 0&&z(w),m&&z(h)}},getPublicKey:p=>{let[m,h,g,w]=a.decode(p);return Uint8Array.from(h)},encapsulate:(p,m)=>{let h=m===void 0,g=h?ot(l):m,w;try{return Ke(p,c.publicKey,"publicKey"),Ke(g,l,"message"),u(p,"encapsulate"),w=s.create().update(g).update(r(p)).digest(),{cipherText:n.encrypt(p,g,w.subarray(32,64)),sharedSecret:w.subarray(0,32)}}finally{w!==void 0&&z(w.subarray(32)),h&&z(g)}},decapsulate:(p,m)=>{Ke(m,a.bytesLen,"secretKey"),Ke(p,c.cipherText,"cipherText");let h=a.bytesLen-96,g=h+32,w=r(m.subarray(h/2,g));if(!jt(w,m.subarray(g,g+32)))throw new Error("invalid secretKey: hash check failed");let[b,y,E,_]=a.decode(m),S=n.decrypt(p,b),x=s.create().update(S).update(E).digest(),T=x.subarray(0,32),v=n.encrypt(y,S,x.subarray(32,64)),C=jt(p,v),L=o.create({dkLen:32}).update(_).update(p).digest();return z(S,v,x.subarray(32),C?L:T),C?T:L},prepare:p=>{Ke(p,c.publicKey,"publicKey"),u(p,"prepare");let m=it(p),h=r(m),g=n.prepare(m);return Object.freeze({publicKey:m,encapsulate:w=>{let b=w===void 0,y=b?ot(l):w,E;try{return Ke(y,l,"message"),E=s.create().update(y).update(h).digest(),{cipherText:g.encrypt(y,E.subarray(32,64)),sharedSecret:E.subarray(0,32)}}finally{E!==void 0&&z(E.subarray(32)),b&&z(y)}},decapsulate:(w,b)=>{Ke(b,a.bytesLen,"secretKey"),Ke(w,c.cipherText,"cipherText");let[y,E,_,S]=a.decode(b);if(!jt(E,m)||!jt(_,h))throw new Error("ML-KEM.decapsulate: secretKey does not match prepared publicKey");let x=n.decrypt(w,y),T=s.create().update(x).update(h).digest(),v=T.subarray(0,32),C=g.encrypt(x,T.subarray(32,64)),L=jt(w,C),H=o.create({dkLen:32}).update(S).update(w).digest();return z(x,C,T.subarray(32),L?H:v),L?v:H},clean:g.clean})}})}function ou(t,e,n){return kn.create({dkLen:t}).update(e).update(new Uint8Array([n])).digest()}var iu={HASH256:Ks,HASH512:rc,KDF:kn,XOF:ac,PRF:ou},au=t=>su({...iu,...t});var cc=au(Qd[768]);var cu=(t,e)=>{let n=wi(t,e);return wi(n.lengths,`${e}.lengths`),Ne(n.keygen,`${e}.keygen`),Ne(n.getPublicKey,`${e}.getPublicKey`),Ne(n.encapsulate,`${e}.encapsulate`),Ne(n.decapsulate,`${e}.decapsulate`),n};function Ln(t,e){let n=ue(t,e);if(n===0)throw new RangeError(`"${e}" expected integer greater than 0, got 0`);return n}function Ar(t,e){let n=Vt(e,...t.map(r=>{if(typeof r.lengths[e]!="number")throw new Error("wrong length: "+e);return Ln(r.lengths[e],e)}));return Ln(n.bytesLen,e),n}function lu(t,e,...n){let r=e,s=n,o=Ar(s,"seed"),i=Ar(s,"publicKey"),c=Ln(t===void 0?o.bytesLen:t,"realSeedLen");function a(d){X(d,c);let u=r(d,o.bytesLen),f=u.buffer===d.buffer?it(u):u,p=[],m=[],h=[],g=[],w=!1;try{for(let b of o.decode(f))p.push(it(b));for(let b=0;b<s.length;b++){let y=s[b].keygen(p[b]);m.push(y.secretKey),h.push(it(y.secretKey)),g.push(y.publicKey)}return w=!0,{secretKey:h,publicKey:g}}finally{z(f,p,m),w||z(h)}}let l=d=>{let u=d===void 0?ot(c):it(d),f;try{let{publicKey:p,secretKey:m}=a(u);try{f={secretKey:u,publicKey:i.encode(p)}}finally{z(p,m)}return f}finally{f||z(u)}};return{info:{lengths:{seed:c,publicKey:i.bytesLen,secretKey:c}},getPublicKey:d=>{let u=l(d);return z(u.secretKey),u.publicKey},keygen:l,expandDecapsulationKey:a,realSeedLen:c}}function du(t,e,n,r,...s){if(t!==void 0&&Ln(t,"realSeedLen"),e!==void 0&&Ln(e,"realMsgLen"),typeof n!="function")throw new TypeError('"expandSeed" expected function, got type='+typeof n);if(typeof r!="function")throw new TypeError('"combiner" expected function, got type='+typeof r);let o=r,i=s;if(i.length===0)throw new RangeError("combineKEMS requires at least one KEM");for(let m=0;m<i.length;m++)cu(i[m],`kems[${m}]`);let c=lu(t,n,...i),a=Ar(i,"cipherText"),l=Ar(i,"publicKey"),d=Ar(i,"msg"),u=Ln(e===void 0?d.bytesLen:e,"realMsgLen"),f=Object.freeze({...c.info.lengths,msg:u,msgRand:d.bytesLen,cipherText:a.bytesLen}),p=(m,h,g)=>{let w=o(m,h,g);try{return it(X(w,u,"sharedSecret"))}catch(b){if(Ht(w)){let y=_=>w.buffer===_.buffer&&w.byteOffset<_.byteOffset+_.byteLength&&_.byteOffset<w.byteOffset+w.byteLength;m.some(y)||h.some(y)||z(w)}throw b}};return Object.freeze({lengths:f,getPublicKey:c.getPublicKey,keygen:c.keygen,encapsulate(m,h=ot(d.bytesLen)){let g=l.decode(m),w=d.decode(h),b=[],y=[];try{for(let _=0;_<i.length;_++){let S=i[_].encapsulate(g[_],w[_]);b.push(S.sharedSecret),y.push(S.cipherText)}let E=a.encode(y);return{sharedSecret:p(g,y,b),cipherText:E}}finally{z(b,y)}},decapsulate(m,h){let g=a.decode(m),{publicKey:w,secretKey:b}=c.expandDecapsulationKey(h),y=[];try{for(let E=0;E<i.length;E++)y.push(i[E].decapsulate(g[E],b[E]));return p(w,g,y)}finally{z(b,y)}}})}function uu(t,e,n,r){let s=t.Point.Fn;if(!s)throw new Error("no Point.Fn");function o(c){let a;for(let u=0,f=e;;u=f,f+=e){if(f>c.length)throw new Error("rejection sampling failed");if(a=s.fromBytes(c.subarray(u,f),!0),s.isValidNot0(a))break}let l=s.toBytes(s.create(a)),d=t.getPublicKey(l,!1);return{secretKey:l,publicKey:d}}let i=(c,a)=>t.getSharedSecret(a,c).subarray(1);return{lengths:{secretKey:e,publicKey:n,seed:r,msg:r,cipherText:n},keygen(c=ot(r)){return X(c,r,"seed"),o(c)},getPublicKey(c){return t.getPublicKey(c,!1)},encapsulate(c,a=ot(r)){X(a,r,"rand");let l;try{l=o(a).secretKey;let d=i(c,l),u=t.getPublicKey(l,!1);return{sharedSecret:d,cipherText:u}}finally{l&&z(l)}},decapsulate:i}}function pu(t,e,n,r){let{secretKey:s,publicKeyUncompressed:o}=n.lengths;if(!s||!o)throw new Error("wrong curve");let i=uu(n,s,o,r),a=64+r;return du(32,32,l=>(X(l,32),kn(l,{dkLen:a})),(l,d,u)=>Ks(Fe(u[0],u[1],d[1],l[1],da(t))),e,i)}var lc=pu("MLKEM768-P256",cc,Xa,128);function vr(t){let e=t instanceof Uint8Array?t:new Uint8Array(t);if(typeof Buffer<"u")return Buffer.from(e).toString("base64");let n="";for(let r=0;r<e.length;r++)n+=String.fromCharCode(e[r]);return btoa(n)}function dc(t){if(typeof Buffer<"u")return new Uint8Array(Buffer.from(t,"base64"));let e=atob(t),n=new Uint8Array(e.length);for(let r=0;r<e.length;r++)n[r]=e.charCodeAt(r);return n}async function uc(t,e){let n=crypto.subtle,r=await n.generateKey({name:"ECDH",namedCurve:"P-256"},!0,["deriveKey"]),s=await n.importKey("jwk",t,{name:"ECDH",namedCurve:"P-256"},!1,[]),o=await n.deriveKey({name:"ECDH",public:s,$public:s},r.privateKey,{name:"AES-GCM",length:256},!1,["encrypt"]),i=crypto.getRandomValues(new Uint8Array(12)),c=new TextEncoder().encode(JSON.stringify(e)),a=await n.encrypt({name:"AES-GCM",iv:i},o,c),d={ephem_pk:await n.exportKey("jwk",r.publicKey),iv:vr(i),ciphertext:vr(a)};return JSON.stringify(d)}function pc(t){let e=lc.encapsulate(t);return{kemCtBase64:vr(e.cipherText),sharedSecret:e.sharedSecret}}async function fc(t){let e=crypto.subtle,n=await e.importKey("raw",t,{name:"HKDF"},!1,["deriveKey"]);return await e.deriveKey({name:"HKDF",hash:"SHA-256",salt:new Uint8Array(0),info:new TextEncoder().encode("obex-pqc-dek-v2")},n,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"])}async function mc(t,e){let n=crypto.getRandomValues(new Uint8Array(12)),r=new TextEncoder().encode(JSON.stringify(e)),s=await crypto.subtle.encrypt({name:"AES-GCM",iv:n},t,r),o={iv:vr(n),ciphertext:vr(s)};return JSON.stringify(o)}var fu=3600*1e3,Gs=new Map,Js=new Map;function hc(t){return Gs.get(t)||null}async function gc(t,e,n){let r=Date.now(),s=Gs.get(e);if(s&&s.expiresAt>r)return s;let o=Js.get(e);if(o)return await o;let i=(async()=>{try{return await mu(t,e,n)}finally{Js.delete(e)}})();return Js.set(e,i),await i}async function mu(t,e,n){let r=Date.now(),s=Math.floor(r/1e3),o=s+3600,i=dc(n),{kemCtBase64:c,sharedSecret:a}=pc(i),l=await fc(a),d=`kem_${fr()}`;try{await t.prepare("INSERT INTO kem_keys (id, profile_id, kem_ct, created_at, expires_at) VALUES (?, ?, ?, ?, ?)").bind(d,e,c,s,o).run()}catch(f){console.error(`[DekManager] Failed to persist kem_key ${d} to D1:`,f)}let u={kemKeyId:d,dek:l,profileId:e,createdAt:r,expiresAt:r+fu};return Gs.set(e,u),u}function yc(t){Gs.delete(t),Js.delete(t)}var _i=new Map;async function hu(t,e){let n=Date.now(),r=_i.get(e);if(r&&r.expiresAt>n)return r.key;try{let s=null;try{s=await t.prepare("SELECT public_key FROM user_log_keys WHERE profile_id = ? AND (is_active IS NULL OR is_active = 1)").bind(e).first()}catch(c){if(String(c?.message||c).includes("no such column: is_active"))s=await t.prepare("SELECT public_key FROM user_log_keys WHERE profile_id = ?").bind(e).first();else throw c}let o=s?.public_key?JSON.parse(s.public_key):null,i=o?300*1e3:15*1e3;return _i.set(e,{key:o,expiresAt:n+i}),o}catch(s){return console.error(`[E2EE] Failed to fetch log public key for profile ${e}:`,s),null}}function Yt(t){_i.delete(t),yc(t)}var Gt=[],wc=50,bc=15e3,Ei=3600,Ys=0,Pr=!1,Ec=Date.now();async function gu(t){let e=Date.now();if(Ys>e)return!0;if(t)try{let n=await P.get(t,"d1:write_quota_tripped");if(n&&n>Math.floor(e/1e3))return Ys=n*1e3,!0}catch{}return!1}async function yu(t){let n=Math.floor(Date.now()/1e3)+Ei;if(Ys=n*1e3,Gt.length=0,Pr=!1,console.warn(`[LogBatcher] D1 write quota limit reached! Silencing log writes for ${Ei}s.`),t)try{await P.set(t,"d1:write_quota_tripped",n,Ei)}catch{}}async function Xs(t){if(Pr=!1,Ec=Date.now(),Gt.length===0)return;let e=caches.default;if(await gu(e)){Gt.length=0;return}let n=Gt.splice(0,wc);if(n.length===0)return;let r=new Oe(t.DB),s=[],o=Array.from(new Set(n.map(a=>a.profile_id))),i=new Map,c=new Map;await Promise.all(o.map(async a=>{let l=await hu(t.DB,a);if(l&&(i.set(a,l),"pqc_pk"in l)){let d=hc(a);d||(d=await gc(t.DB,a,l.pqc_pk)),d&&c.set(a,d)}}));for(let a of n){let l=i.get(a.profile_id);if(l)try{let d={domain:a.domain,client_ip:a.client_ip,geo_country:a.geo_country,answer:a.answer,dest_geoip:a.dest_geoip,dest_country_code:a.dest_country_code,dest_country:a.dest_country,dest_isp:a.dest_isp,ecs:a.ecs,upstream:a.upstream,reason:a.reason};if("pqc_pk"in l){let u=c.get(a.profile_id);if(u){let f=await mc(u.dek,d);a.encrypt_version=2,a.kem_key_id=u.kemKeyId,a.encrypted_payload=f}}else if("kty"in l){let u=await uc(l,d);a.encrypt_version=1,a.kem_key_id=null,a.encrypted_payload=u}a.encrypt_version&&a.encrypt_version>0&&(a.domain="",a.client_ip="",a.geo_country="",a.answer=void 0,a.dest_geoip=void 0,a.dest_country_code=null,a.dest_country=null,a.dest_isp=null,a.ecs=void 0,a.upstream=void 0,a.reason=void 0)}catch(d){console.error(`[LogBatcher] Encryption failed for profile ${a.profile_id}:`,d)}else a.encrypt_version=0,a.kem_key_id=null;s.push(r.createInsertStatement(a))}try{await t.DB.batch(s)}catch(a){let l=String(a?.message||a);l.includes("exceeded D1's free tier daily row write limit")||l.includes("row write limit")||l.includes("daily write limit")?await yu(e):console.warn(`[LogBatcher] Batch write failed (${s.length} stmts):`,l)}Gt.length>0&&_c(t)}function _c(t){Pr||(Pr=!0,new Promise(e=>setTimeout(e,bc)).then(()=>Xs(t)).catch(e=>{Pr=!1,console.error("[LogBatcher] Deferred flush error:",e)}))}function Cr(t,e,n,r){if(e&&Number(e.log_retention_days)===0)return;let s=(t.action||"PASS").toUpperCase();if(e?.skip_log_on_pass&&s==="PASS"||Ys>Date.now())return;t.id||(t.id=fr()),Gt.push(t);let o=Date.now();Gt.length>=wc||o-Ec>=bc?r.waitUntil(Xs(n)):_c(n)}async function Sc(t,e,n,r,s,o,i,c,a){let l=t.headers.get("CF-Connecting-IP")||"127.0.0.1",d,u=i||"";if(s==="REDIRECT"&&i)if(c==="CNAME"&&(e.type==="A"||e.type==="AAAA")&&a)try{let m=Ut(i,e.type),h={name:i,type:e.type,raw:m},g=await a(t,h,n,r,"PASS");if(g.answer&&g.answer.length>0){let w=Ce(g.answer),b=[{type:"CNAME",value:i,ttl:60}];for(let y of w)(y.type===e.type||y.type==="CNAME")&&b.push({name:y.name,type:y.type,value:y.data,ttl:y.ttl});d=Oo(e.raw,b,0)}else d=Ee(e.raw,c,i)}catch(m){console.error("CNAME resolution failed:",m),d=Ee(e.raw,c,i)}else d=Ee(e.raw,c||e.type,i);else{let m=r.block_mode||"NULL_IP";if(m==="NXDOMAIN")d=Ee(e.raw,e.type,"",3600,3),u="NXDOMAIN";else if(m==="NODATA")d=Ee(e.raw,e.type,"",3600,0),u="NODATA";else if(m==="CUSTOM_IP"){let h=e.type==="AAAA"?r.custom_block_ipv6||"::":r.custom_block_ipv4||"0.0.0.0";d=Ee(e.raw,e.type,h),u=h}else{let h=e.type==="AAAA"?"::":"0.0.0.0";d=Ee(e.raw,e.type,h),u=h}}let f=Date.now()-n.startTime,p=t.cf?.country||t.headers.get("CF-IPCountry")||"UN";return n.ctx.waitUntil((async()=>{try{Cr({profile_id:n.profileId,access_point_id:n.accessPointId,timestamp:Math.floor(Date.now()/1e3),client_ip:l,geo_country:p,domain:e.name,record_type:e.type,action:s,reason:o,answer:u,latency:f},r,n.env,n.ctx)}catch{}})()),{answer:d,ttl:3600,action:s,reason:o,latency:f}}ge();var Xt=new Map,Rc=336*60*60*1e3;async function Tc(t){if(!hs(t))return null;let e=`geoip:${t}`,n=Date.now(),r=Xt.get(e);if(r){if(n<r.expiresAt)return r.data;Xt.delete(e)}let s=null;if(typeof caches<"u"&&caches.default&&(s=caches.default),s)try{let i=await P.get(s,e);if(i)return Xt.set(e,{data:i,expiresAt:n+Rc}),i}catch(i){console.warn("Cloudflare Cache API read error, falling back to memory/network:",i)}let o=async i=>{if(Xt.size>=1e5){let c=Xt.keys().next().value;c!==void 0&&Xt.delete(c)}if(Xt.set(e,{data:i,expiresAt:n+Rc}),s)try{await P.set(s,e,i,86400*14)}catch(c){console.warn("Cloudflare Cache API write error:",c)}};try{let i=await fetch(`http://ip-api.com/json/${t}?fields=status,country,countryCode,regionName,city,isp,org,as`,{cf:{cacheTtlByStatus:{"200-299":1209600,"400-499":5,"500-599":0},cacheEverything:!0}});if(i.ok){let c=await i.json();if(c.status==="success"){let a={country:c.country,country_code:c.countryCode,region:c.regionName,city:c.city,isp:c.isp,org:c.org,as:c.as};return await o(a),a}}}catch{}try{let i=await fetch(`https://ipwho.is/${t}`);if(i.ok){let c=await i.json();if(c.success){let a={country:c.country,country_code:c.country_code,region:c.region,city:c.city,isp:c.connection?.isp,org:c.connection?.org,as:c.connection?.asn?`AS${c.connection.asn} ${c.connection?.org||""}`.trim():void 0};return await o(a),a}}}catch(i){console.error("GeoIP Fetch Error:",i)}return null}function xc(t,e,n,r,s,o,i,c,a,l,d){let u=t.headers.get("CF-Connecting-IP")||"127.0.0.1",f=t.cf?.country||t.headers.get("CF-IPCountry")||"UN";n.ctx.waitUntil((async()=>{try{let p=i.find(y=>y.type==="A"||y.type==="AAAA")?.data,m="",h=null,g=null,w=null;if(p){let y=await Tc(p);y&&(m=JSON.stringify(y),h=y.country_code?y.country_code.toUpperCase():null,g=y.country||null,w=y.isp||null)}let b=Date.now()-n.startTime;Cr({profile_id:n.profileId,access_point_id:n.accessPointId,timestamp:Math.floor(Date.now()/1e3),client_ip:u,geo_country:f,domain:e.name,record_type:e.type,action:s,reason:o,answer:i.map(y=>y.data).join(", "),dest_geoip:m,dest_country_code:h,dest_country:g,dest_isp:w,upstream:l,latency:b,ecs:d},r,n.env,n.ctx),c.length>0&&fn.set(`${n.profileId}:${e.name}:${e.type}`,{answer:c,ttl:a,action:s,reason:o,expiresAt:Date.now()+a*1e3})}catch{}})())}function Ac(t,e,n,r,s,o,i,c,a){let l=0,d,u=o instanceof Error?o.message:String(o),f,p;if(o instanceof _n)l=o.status,d=o.statusText||void 0,f=o.responseBodySnippet||void 0,p=o.cfRay;else if(o&&typeof o=="object"&&"cause"in o&&o.cause){let y=o.cause,E=typeof y=="object"&&y&&"message"in y?String(y.message):String(y);u+=` (Cause: ${E})`}let m=l>0?`Upstream HTTP ${l}${d?` ${d}`:""}`:`Upstream Error: ${u}`,h=t.headers.get("CF-Connecting-IP")||"127.0.0.1",g=t.cf?.country||t.headers.get("CF-IPCountry")||"UN";n.ctx.waitUntil((async()=>{try{Cr({profile_id:n.profileId,access_point_id:n.accessPointId,timestamp:Math.floor(Date.now()/1e3),client_ip:h,geo_country:g,domain:e.name,record_type:e.type,action:"FAIL",reason:m,answer:"",dest_geoip:"",dest_country_code:null,dest_country:null,dest_isp:null,upstream:s,latency:Date.now()-n.startTime,ecs:i},r,n.env,n.ctx)}catch{}})());let w=c||s,b=a||"POST";return{answer:new Uint8Array,ttl:0,action:"FAIL",reason:m,latency:Date.now()-n.startTime,diagnostics:{upstream_url:s.startsWith("sdns://")?`${s} (${w})`:w,method:b,status:l,status_text:d,error_detail:u,response_body:f,cf_ray:p}}}var Ze={async resolve(t,e,n,r,s,o){let i=r.upstream[0]||"https://security.cloudflare-dns.com/dns-query";if(!ze(i))return{answer:new Uint8Array,ttl:0,action:"FAIL",reason:"Unsafe upstream URL",diagnostics:{upstream_url:i,method:"BLOCKED",status:0},latency:Date.now()-n.startTime};let{queryRaw:c,ecs:a}=ea(t,e,r),l;try{l=_t(i);let d=await St(l,c),u=Ce(d.answer),f=await ta(e,u,d.answer,n,r,t,Ze.resolve,o),p=f.answer,m=f.parsedAnswers,h=f.effectiveReason,g=m.length>0?Math.max(10,Math.min(...m.map(w=>w.ttl))):60;return xc(t,e,n,r,s,h,m,p,g,i,a),{answer:p,ttl:g,action:s,reason:h,latency:Date.now()-n.startTime,timings:{upstream_fetch:d.latency},diagnostics:{upstream_url:i.startsWith("sdns://")?`${i} (${d.diagTarget})`:d.diagTarget,method:d.diagMethod,status:200,status_text:"OK"}}}catch(d){return Ac(t,e,n,r,i,d,a,l?.diagTarget,l?.diagMethod)}},async block(t,e,n,r,s,o,i,c){return Sc(t,e,n,r,s,o,i,c,Ze.resolve)}};var On=class{static isMatch(e,n){let r=e.toLowerCase(),s=n.toLowerCase();return r===s||r.endsWith(`.${s}`)}static findMatch(e,n){for(let r of n)if(this.isMatch(e,r.pattern))return r;return null}};var vc={async match(t,e,n,r,s,o,i){let c=e.name.toLowerCase(),a=s.filter(p=>p.type==="ALLOW");if(On.findMatch(e.name,a))return i("local_rules"),Ze.resolve(t,e,n,r,"PASS","Whitelist");let l=s.filter(p=>p.type==="REDIRECT"),d=On.findMatch(e.name,l);if(d){let p,m=e.type;if(e.type==="A"?(p=d.v_a,!p&&d.v_cname&&(p=d.v_cname,m="CNAME")):e.type==="AAAA"?(p=d.v_aaaa,!p&&d.v_cname&&(p=d.v_cname,m="CNAME")):e.type==="TXT"?p=d.v_txt:e.type==="CNAME"&&(p=d.v_cname),p)return i("local_rules"),await Ze.block(t,e,n,r,"REDIRECT",`Rule: ${d.pattern}`,p,m)}let u=s.filter(p=>p.type==="BLOCK"),f=On.findMatch(e.name,u);if(f)return i("local_rules"),Ze.block(t,e,n,r,"BLOCK",`Blacklist: ${f.pattern}`);if(i("local_rules"),o){let p=c;for(;p;){if(o.test(p))return i("bloom_check"),Ze.block(t,e,n,r,"BLOCK",`External List: ${p}`);let m=p.indexOf(".");if(m===-1)break;p=p.substring(m+1)}i("bloom_check")}return null}};var de={clearCache:ns.clear,async process(t,e,n){let r={},s=n.startTime,o=d=>{let u=Date.now();r[d]=(r[d]||0)+(u-s),s=u};if(e.name.toLowerCase()==="obex"&&e.type==="TXT")return{answer:Ee(e.raw,"TXT",n.profileId||"obex"),ttl:60,action:"PASS",reason:"Internal Verification",latency:Date.now()-n.startTime,timings:{total:Date.now()-n.startTime}};let i=fn.get(`${n.profileId}:${e.name}:${e.type}`);if(i&&Date.now()<i.expiresAt&&i.answer instanceof Uint8Array){let d=new Uint8Array(i.answer);d.length>=2&&e.raw.length>=2&&(d[0]=e.raw[0],d[1]=e.raw[1]);let u=Date.now()-n.startTime;return{answer:d,ttl:Math.ceil((i.expiresAt-Date.now())/1e3),action:i.action,reason:i.reason,latency:u,timings:{dns_cache_mem:u}}}let c=await zi.load(n,o);if(!c)return{answer:new Uint8Array,ttl:0,action:"FAIL",reason:"Profile Not Found"};let a=await vc.match(t,e,n,c.settings,c.rules,c.bloom,o);if(a)return{...a,timings:{...r,...a.timings}};if(c.settings.default_policy==="BLOCK"){let d=await Ze.block(t,e,n,c.settings,"BLOCK","Default Policy");return{...d,timings:{...r,...d.timings}}}let l=await Ze.resolve(t,e,n,c.settings,"PASS");return{...l,timings:{...r,...l.timings}}}};function wu(t){if(!t||typeof t!="object")return null;let e=0;for(let n of Object.keys(t)){let r=n.match(/^KEK_[vV](\d+)$/);if(r){let s=t[n];if(s!=null&&s!==""){let o=parseInt(r[1],10);!isNaN(o)&&o>e&&(e=o)}}}return e>0?`v${e}`:null}function zs(t,e){if(!e)return null;let n=e[`KEK_${t}`]||e[`KEK_${t.toUpperCase()}`];return n&&typeof n=="string"&&n.trim()!==""?n:(t==="v0"||t==="default")&&e.JWT_SECRET&&typeof e.JWT_SECRET=="string"&&e.JWT_SECRET.trim()!==""?e.JWT_SECRET:null}function Nn(t){let e="",n=t.byteLength;for(let r=0;r<n;r++)e+=String.fromCharCode(t[r]);return btoa(e)}function In(t){let e=atob(t),n=e.length,r=new Uint8Array(n);for(let s=0;s<n;s++)r[s]=e.charCodeAt(s);return r}async function Qs(t){let n=new TextEncoder().encode(t.trim()),r=await crypto.subtle.digest("SHA-256",n);return await crypto.subtle.importKey("raw",r,{name:"AES-GCM"},!1,["encrypt","decrypt"])}async function Pc(t){return await crypto.subtle.importKey("raw",t,{name:"AES-GCM"},!1,["encrypt","decrypt"])}async function Pt(t,e){let n=wu(e);if(!n)return null;let r=zs(n,e);if(!r||typeof r!="string"||r.trim()==="")throw new Error(`KEK version ${n} is missing or invalid in environment variables`);let s=await Qs(r),o=new Uint8Array(32);crypto.getRandomValues(o);let i=await Pc(o),c=new Uint8Array(12);crypto.getRandomValues(c);let l=new TextEncoder().encode(t),d=await crypto.subtle.encrypt({name:"AES-GCM",iv:c},i,l),u={ciphertext:Nn(new Uint8Array(d)),iv:Nn(c)},f=new Uint8Array(12);crypto.getRandomValues(f);let p=await crypto.subtle.encrypt({name:"AES-GCM",iv:f},s,o),m={ciphertext:Nn(new Uint8Array(p)),iv:Nn(f),kek_version:n};return{dataEncrypted:JSON.stringify(u),dekEncrypted:JSON.stringify(m)}}async function Si(t,e,n){let r,s;try{r=JSON.parse(t),s=JSON.parse(e)}catch(i){throw new Error(`Failed to parse envelope payload: ${i instanceof Error?i.message:String(i)}`)}let o=async i=>{let c=zs(i,n);if(!c||typeof c!="string"||c.trim()==="")throw new Error(`Required KEK version ${i} is missing or invalid in environment variables`);let a=await Qs(c),l=In(s.ciphertext),d=In(s.iv),u=await crypto.subtle.decrypt({name:"AES-GCM",iv:d},a,l),f=new Uint8Array(u),p=await Pc(f),m=In(r.ciphertext),h=In(r.iv),g=await crypto.subtle.decrypt({name:"AES-GCM",iv:h},p,m);return new TextDecoder().decode(g)};try{return await o(s.kek_version)}catch(i){if(s.kek_version!=="v0"&&n?.JWT_SECRET&&typeof n.JWT_SECRET=="string"&&n.JWT_SECRET.trim()!=="")try{return await o("v0")}catch{throw i}throw i}}async function Ri(t,e){if(!e)return null;let n;try{n=JSON.parse(t)}catch{return null}let r=n.kek_version,s=parseInt(r.replace(/^v/,""),10);if(isNaN(s))return null;let i=`v${s+1}`,c=zs(i,e);if(!c||typeof c!="string"||c.trim()==="")return null;let a=zs(r,e);if(!a||typeof a!="string"||a.trim()==="")throw new Error(`Current KEK version ${r} required for rotation is missing or invalid in environment`);let l=await Qs(a),d=In(n.ciphertext),u=In(n.iv),f=await crypto.subtle.decrypt({name:"AES-GCM",iv:u},l,d),p=new Uint8Array(f),m=await Qs(c),h=new Uint8Array(12);crypto.getRandomValues(h);let g=await crypto.subtle.encrypt({name:"AES-GCM",iv:h},m,p),w={ciphertext:Nn(new Uint8Array(g)),iv:Nn(h),kek_version:i};return JSON.stringify(w)}var Zs=class{constructor(e,n){this.db=e;this.env=n}db;env;async processUserSecrets(e){if(!e)return null;let n={},r=!1,s=e.totp_secret;if(e.totp_secret_encrypted&&e.totp_secret_dek)try{s=await Si(e.totp_secret_encrypted,e.totp_secret_dek,this.env);let i=await Ri(e.totp_secret_dek,this.env);i&&(n.totp_secret_dek=i,r=!0)}catch(i){let c=i instanceof Error?i.stack||i.message:String(i);console.error(`[Envelope Encryption] Failed to decrypt/rotate totp_secret for user ${e.id}:`,c)}else if(e.totp_secret)try{let i=await Pt(e.totp_secret,this.env);i&&(n.totp_secret_encrypted=i.dataEncrypted,n.totp_secret_dek=i.dekEncrypted,n.totp_secret=null,r=!0)}catch(i){console.error(`[Envelope Encryption] Migration failed for totp_secret of user ${e.id}:`,i)}let o=e.totp_recovery_keys;if(e.totp_recovery_keys_encrypted&&e.totp_recovery_keys_dek)try{o=await Si(e.totp_recovery_keys_encrypted,e.totp_recovery_keys_dek,this.env);let i=await Ri(e.totp_recovery_keys_dek,this.env);i&&(n.totp_recovery_keys_dek=i,r=!0)}catch(i){let c=i instanceof Error?i.stack||i.message:String(i);console.error(`[Envelope Encryption] Failed to decrypt/rotate totp_recovery_keys for user ${e.id}:`,c)}else if(e.totp_recovery_keys)try{let i=await Pt(e.totp_recovery_keys,this.env);i&&(n.totp_recovery_keys_encrypted=i.dataEncrypted,n.totp_recovery_keys_dek=i.dekEncrypted,n.totp_recovery_keys=null,r=!0)}catch(i){console.error(`[Envelope Encryption] Migration failed for totp_recovery_keys of user ${e.id}:`,i)}if(r)try{let i=[],c=[];for(let[a,l]of Object.entries(n))i.push(`${a} = ?`),c.push(l);c.push(e.id),await this.db.prepare(`UPDATE users SET ${i.join(", ")} WHERE id = ?`).bind(...c).run(),Object.assign(e,n)}catch(i){console.error(`[Envelope Encryption] Failed to save rotated/migrated secrets for user ${e.id}:`,i)}return{...e,totp_secret:s,totp_recovery_keys:o}}};var qs=class{constructor(e,n){this.db=e;this.secretProcessor=n}db;secretProcessor;async getById(e){let n=await this.db.prepare("SELECT * FROM users WHERE id = ?").bind(e).first();return await this.secretProcessor.processUserSecrets(n)}async getByUsername(e){try{let n=await this.db.prepare("SELECT * FROM users WHERE username = ?").bind(e).first();return await this.secretProcessor.processUserSecrets(n)}catch(n){if((n instanceof Error?n.message:String(n)).includes("no such table"))return null;throw n}}async listAll(){let{results:e}=await this.db.prepare(`
293
+ `,a=[e,r,s];t&&(c+=" AND UPPER(COALESCE(dest_country_code, json_extract(dest_geoip, '$.country_code'))) = ?",a.push(t.toUpperCase())),o&&(c+=" AND access_point_id = ?",a.push(o)),c+=` GROUP BY name ORDER BY count DESC LIMIT ${i}`;let{results:l}=await this.db.prepare(c).bind(...a).all();return l.map(d=>({name:d.name||"Unknown",count:d.count}))}};var Cs=class{constructor(e,t){this.db=e;this.traffic=new xs(e),this.domains=new As(e),this.clients=new vs(e),this.destinations=new Ps(e)}db;traffic;domains;clients;destinations;async getSummary(e,t,r,s,o){return this.traffic.getSummary(e,t,r,s,o)}async getTrend(e,t,r,s,o){return this.traffic.getTrend(e,t,r,s,o)}async getTopAllowed(e,t,r,s){return this.domains.getTopAllowed(e,t,r,s)}async getTopBlocked(e,t,r,s){return this.domains.getTopBlocked(e,t,r,s)}async getClients(e,t,r,s){return this.clients.getClients(e,t,r,s)}async getDestinations(e,t,r,s,o=250){return this.destinations.getDestinations(e,t,r,s,o)}async getISPByCountry(e,t,r,s,o,i=250){return this.destinations.getISPByCountry(e,t,r,s,o,i)}async getAnalytics(e,t,r,s,o){let[i,c,a,l,d,u]=await Promise.all([this.getSummary(e,t,r,void 0,o),this.getTrend(e,t,r,s,o),this.getTopAllowed(e,t,r,o),this.getTopBlocked(e,t,r,o),this.getClients(e,t,r,o),this.getDestinations(e,t,r,o)]);return{summary:i,trend:c,top_allowed:a,top_blocked:l,clients:d,destinations:u}}};var Ie=class{constructor(e){this.db=e;this.core=new Ss(e),this.aggregation=new Rs(e),this.retention=new Ts(e),this.analytics=new Cs(e,this.aggregation),this.kemKeys=new Pn(e)}db;core;aggregation;retention;analytics;kemKeys;createInsertStatement(e){return this.core.createInsertStatement(e)}async insert(e){return this.core.insert(e)}async getLogs(e,t){return this.core.getLogs(e,t)}async getLog(e,t,r){return this.core.getLog(e,t,r)}async deleteByOwner(e){return this.core.deleteByOwner(e)}async cleanup(e,t,r=1e3){return this.core.cleanup(e,t,r)}async cleanupGlobal(e=30,t=1e3,r=2e4){return this.retention.cleanupGlobal(e,t,r)}async getLatestRollupHour(e){return this.aggregation.getLatestRollupHour(e)}async getLatestClientRollupHour(e){return this.aggregation.getLatestClientRollupHour(e)}async getLatestDestinationRollupHour(e){return this.aggregation.getLatestDestinationRollupHour(e)}async aggregateHourlyRollups(e,t,r=2){return this.aggregation.aggregateHourlyRollups(e,t,r)}async getSummary(e,t,r,s,o){return this.analytics.getSummary(e,t,r,s,o)}async getTrend(e,t,r,s,o){return this.analytics.getTrend(e,t,r,s,o)}async getTopAllowed(e,t,r,s){return this.analytics.getTopAllowed(e,t,r,s)}async getTopBlocked(e,t,r,s){return this.analytics.getTopBlocked(e,t,r,s)}async getClients(e,t,r,s){return this.analytics.getClients(e,t,r,s)}async getDestinations(e,t,r,s,o=250){return this.analytics.getDestinations(e,t,r,s,o)}async getISPByCountry(e,t,r,s,o,i=250){return this.analytics.getISPByCountry(e,t,r,s,o,i)}async getAnalytics(e,t,r,s,o){return this.analytics.getAnalytics(e,t,r,s,o)}};ge();function Gt(n){return n instanceof Uint8Array||ArrayBuffer.isView(n)&&n.constructor.name==="Uint8Array"&&"BYTES_PER_ELEMENT"in n&&n.BYTES_PER_ELEMENT===1}var Ds=n=>n?`"${n}" `:"";function ue(n,e=""){if(typeof n!="number")throw new TypeError(Ds(e)+"expected number, got "+typeof n);if(!Number.isSafeInteger(n)||n<0)throw new RangeError(Ds(e)+"expected integer >= 0, got "+n);return n}function pa(n,e=""){if(typeof n!="boolean")throw new TypeError(Ds(e)+"expected boolean, got type="+typeof n);return n}function z(n,e,t=""){if(Gt(n)&&(e===void 0||n.length===e))return n;e!==void 0&&ue(e,"length");let r=Gt(n),s=e!==void 0?` of length ${e}`:"",o=r?`length=${n.length}`:`type=${typeof n}`,i=Ds(t)+"expected Uint8Array"+s+", got "+o;throw r?new RangeError(i):new TypeError(i)}function Cn(n){if(typeof n!="function"||typeof n.create!="function")throw new TypeError("expected hash wrapped by utils.createHasher");if(ue(n.outputLen),ue(n.blockLen),n.outputLen<1||n.blockLen<1)throw new Error("hash blockLen / outputLen must be >= 1")}var dd=(n,e)=>{if(n===null||typeof n!="object"||Array.isArray(n))throw new TypeError((e==="object"?"":`"${e}" `)+"expected object, got type="+typeof n)},da=(n,e)=>{dd(n,e);let t=Object.getPrototypeOf(n);if(t!==Object.prototype&&t!==null)throw new TypeError(`"${e}" expected plain object`);if(Object.hasOwn(n,"__proto__"))throw new TypeError(`"${e}.__proto__" is not allowed`)};function ct(n,e=!0){if(n.destroyed)throw new Error("hash was destroyed");if(e&&n.finished)throw new Error("digest() was already called")}function Dn(n,e){z(n,void 0,"output");let t=e.outputLen;if(!(n.length>=t))throw new RangeError('"output" expected length >= '+t)}function Sr(n){return new Uint32Array(n.buffer,n.byteOffset,Math.floor(n.byteLength/4))}function At(...n){for(let e=0;e<n.length;e++)n[e].fill(0)}function ks(n){return new DataView(n.buffer,n.byteOffset,n.byteLength)}function $e(n,e){return n<<32-e|n>>>e}var fa=new Uint8Array(new Uint32Array([287454020]).buffer)[0]===68;function ud(n){return n<<24&4278190080|n<<8&16711680|n>>>8&65280|n>>>24&255}function pd(n){for(let e=0;e<n.length;e++)n[e]=ud(n[e]);return n}var kn=fa?n=>n:pd,ma=typeof Uint8Array.from([]).toHex=="function"&&typeof Uint8Array.fromHex=="function",fd=Array.from({length:256},(n,e)=>e.toString(16).padStart(2,"0"));function Rr(n){if(z(n),ma)return n.toHex();let e="";for(let t=0;t<n.length;t++)e+=fd[n[t]];return e}function ua(n){return n>=48&&n<=57?n-48:n>=65&&n<=70?n-55:n>=97&&n<=102?n-87:void 0}function qo(n){if(typeof n!="string")throw new TypeError("hex string expected, got "+typeof n);if(ma)try{return Uint8Array.fromHex(n)}catch(s){throw s instanceof SyntaxError?new RangeError(s.message):s}let e=n.length,t=e/2;if(e%2)throw new RangeError("hex string expected, got unpadded hex of length "+e);let r=new Uint8Array(t);for(let s=0,o=0;s<t;s++,o+=2){let i=ua(n.charCodeAt(o)),c=ua(n.charCodeAt(o+1));if(i===void 0||c===void 0){let a=n[o]+n[o+1];throw new RangeError('hex string expected, got non-hex character "'+a+'" at index '+o)}r[s]=i*16+c}return r}function ei(...n){let e=0;for(let r=0;r<n.length;r++){let s=n[r];z(s),e+=s.length}let t=new Uint8Array(e);for(let r=0,s=0;r<n.length;r++){let o=n[r];t.set(o,s),s+=o.length}return t}function ti(n,e,t="opts"){return da(n,"defaults"),e!==void 0&&da(e,t),Object.assign(Object.create(null),n,e)}function Tr(n,e={}){if(typeof n!="function")throw new TypeError('"hashCons" expected function, got type='+typeof n);e=ti({},e,"info");let t=(s,o)=>n(o).update(s).digest(),r=n(void 0);return t.outputLen=r.outputLen,t.blockLen=r.blockLen,t.canXOF=r.canXOF,t.create=s=>n(s),Object.assign(t,e),Object.freeze(t)}function Ls(n=32){ue(n,"bytesLength");let e=typeof globalThis=="object"?globalThis.crypto:null;if(typeof e?.getRandomValues!="function")throw new Error("crypto.getRandomValues must be defined");if(n>65536)throw new RangeError(`"bytesLength" expected <= 65536, got ${n}`);return e.getRandomValues(new Uint8Array(n))}var Jt=n=>({oid:Uint8Array.from([6,9,96,134,72,1,101,3,4,2,n])});function xr(n,e,t=()=>{}){if(!Array.isArray(n))throw new TypeError(`"${e}" expected array, got type=${typeof n}`);for(let r=0;r<n.length;r++)t(n[r],`${e}[${r}]`);return n}var fe=(n,e,t)=>z(n,e,t),ni=ue;function ga(n,e=""){if(typeof n!="string"){let t=e&&`"${e}" `;throw new TypeError(t+"expected string, got type="+typeof n)}return n}function vt(n,e="object"){if(n===null||typeof n!="object"||Array.isArray(n))throw new TypeError(e==="object"?"expected valid options object":`"${e}" expected object, got type=${typeof n}`);return n}function Ue(n,e){if(typeof n!="function")throw new TypeError(`"${e}" is invalid: expected function, got ${typeof n}`);return n}var ri=Rr,Ke=(...n)=>ei(...n),Ns=n=>qo(n),Ln=Gt,Is=n=>Ls(n),Os=BigInt(0),ha=BigInt(1),md=n=>n?`"${n}" `:"";function We(n,e=""){if(typeof n!="boolean")throw new TypeError(md(e)+"expected boolean, got type="+typeof n);return n}function Us(n){if(typeof n=="bigint"){if(!Pt(n))throw new RangeError("positive bigint expected, got "+n)}else ni(n);return n}function Yt(n,e=""){if(typeof n!="number"){let t=e&&`"${e}" `;throw new TypeError(t+"expected number, got type="+typeof n)}if(!Number.isSafeInteger(n)){let t=e&&`"${e}" `;throw new RangeError(t+"expected safe integer, got "+n)}}function Ar(n){let e=Us(n).toString(16);return e.length&1?"0"+e:e}function ya(n){if(typeof n!="string")throw new TypeError("hex string expected, got "+typeof n);return n===""?Os:BigInt("0x"+n)}function je(n){return ya(Rr(n))}function Ms(n){return ya(Rr(hd(z(n)).reverse()))}function vr(n,e){if(ue(e),e===0)throw new Error("zero output length is invalid");n=Us(n);let t=e*2,r=n.toString(16);if(r.length>t)throw new RangeError("number is too large");return qo(r.padStart(t,"0"))}function si(n,e){return vr(n,e).reverse()}function hd(n){return Uint8Array.from(fe(n))}function wa(n){if(typeof n!="string")throw new TypeError("ascii string expected, got "+typeof n);return Uint8Array.from(n,(e,t)=>{let r=e.charCodeAt(0);if(e.length!==1||r>127)throw new RangeError(`string contains non-ASCII character "${n[t]}" with code ${r} at position ${t}`);return r})}function Pt(n){return typeof n=="bigint"&&Os<=n}function oi(n,e,t){return Pt(n)&&Pt(e)&&Pt(t)&&e<=n&&n<t}function ii(n,e,t,r){if(!oi(e,t,r))throw new RangeError("expected valid "+n+": "+t+" <= n < "+r+", got "+e)}function On(n){if(n<Os)throw new Error("expected non-negative bigint, got "+n);return n===Os?0:n.toString(2).length}var Pr=n=>(Yt(n,"n"),(ha<<BigInt(n))-ha);function ba(n,e,t){if(ue(n,"hashLen"),ue(e,"qByteLen"),typeof t!="function")throw new TypeError("hmacFn must be a function");let r=g=>new Uint8Array(g),s=Uint8Array.of(),o=Uint8Array.of(0),i=Uint8Array.of(1),c=1e3,a=r(n),l=r(n),d=0,u=()=>{a.fill(1),l.fill(0),d=0},f=(...g)=>t(l,Ke(a,...g)),p=(g=s)=>{l=f(o,g),a=f(),g.length!==0&&(l=f(i,g),a=f())},m=()=>{if(d++>=c)throw new Error("drbg: tried max amount of iterations");let g=0,b=[];for(;g<e;){a=f();let w=a.slice();b.push(w),g+=a.length}return Ke(...b)};return(g,b)=>{u(),p(g);let w;for(;(w=b(m()))===void 0;)p();return u(),w}}function et(n,e={},t={},r="object"){vt(n,r),vt(e,"fields"),vt(t,"optFields");function s(i,c,a){let l=r==="object"?`param "${String(i)}"`:`"${r}.${String(i)}"`,d=n[i];if(!Object.hasOwn(n,i)&&(a?d!==void 0:c!=="function"))throw new TypeError(`${l} is invalid: expected own property`);if(a&&d===void 0)return;let u=typeof d;if(u!==c||d===null)throw new TypeError(`${l} is invalid: expected ${c}, got ${u}`)}let o=(i,c)=>Object.entries(i).forEach(([a,l])=>s(a,l,c));o(e,!1),o(t,!0)}var ye=BigInt(0),ee=BigInt(1),Ct=BigInt(2),Ra=BigInt(3),ai=BigInt(4),Ta=BigInt(5),gd=BigInt(7),xa=BigInt(8),yd=BigInt(9),wd=BigInt(15),Aa=BigInt(16),bd=BigInt("0x10000000000000000");function Pe(n,e){if(e<=ye)throw new Error("mod: expected positive modulus, got "+e);let t=n%e;return t>=ye?t:e+t}function va(n,e,t){if(t<=ee)throw new Error("pow: expected modulus > 1, got "+t);if(typeof e!="bigint")throw new TypeError("invalid exponent: expected bigint, got "+typeof e);if(e<ye)throw new Error("invalid exponent, negatives unsupported");if(e===ye)return ee;if(e===ee)return n;let r=n%t;if(r<ye&&(r+=t),e<bd){let c=ee;for(;e>ye;)e&ee&&(c=c*r%t),r=r*r%t,e>>=ee;return c}let s=[];for(;e>ye;)s.push(Number(e&wd)),e>>=ai;let o=new Array(16);o[0]=ee,o[1]=r;for(let c=2;c<16;c++)o[c]=o[c-1]*r%t;let i=o[s[s.length-1]];for(let c=s.length-2;c>=0;c--){i=i*i%t,i=i*i%t,i=i*i%t,i=i*i%t;let a=s[c];a!==0&&(i=i*o[a]%t)}return i}function Ea(n,e){if(n===ye)throw new Error("invert: expected non-zero number");if(e<=ee)throw new Error("invert: expected modulus > 1, got "+e);let t=Pe(n,e),r=e,s=ye,o=ee;for(;t!==ye;){let c=r/t,a=r-t*c,l=s-o*c;r=t,t=a,s=o,o=l}if(r!==ee)throw new Error("invert: does not exist");return Pe(s,e)}function Pa(n,e){if(e<=ee)throw new Error("invertCt: expected prime modulus > 1, got "+e);let t=Pe(n,e);if(t===ye)throw new Error("invertCt: expected non-zero number");let r=va(t,e-Ct,e);if(Pe(t*r,e)!==ee)throw new Error("invertCt: does not exist");return r}function ci(n,e,t){let r=n;if(!r.eql(r.sqr(e),t))throw new Error("Cannot find square root")}function li(n,e){if((n&ee)===ye)throw new Error(e+": expected odd modulus, got "+n)}function Ca(n,e){let t=n,r=(t.ORDER+ee)/ai,s=t.pow(e,r);return ci(t,s,e),s}function Ed(n,e){let t=n,r=(t.ORDER-Ta)/xa,s=t.mul(e,Ct),o=t.pow(s,r),i=t.mul(e,o),c=t.mul(t.mul(i,Ct),o),a=t.mul(i,t.sub(c,t.ONE));return ci(t,a,e),a}function _d(n){let e=Fs(n),t=Da(n),r=t(e,e.neg(e.ONE)),s=t(e,r),o=t(e,e.neg(r)),i=(n+gd)/Aa;return((c,a)=>{let l=c,d=l.pow(a,i),u=l.mul(d,r),f=l.mul(d,s),p=l.mul(d,o),m=l.eql(l.sqr(u),a),h=l.eql(l.sqr(f),a);d=l.cmov(d,u,m),u=l.cmov(p,f,h);let g=l.eql(l.sqr(u),a),b=l.cmov(d,u,g);return ci(l,b,a),b})}function Da(n){if(n<Ra)throw new Error("sqrt is not defined for small field");li(n,"tonelliShanks");let e=n-ee,t=0;for(;e%Ct===ye;)e/=Ct,t++;let r=Ct,s=Fs(n);for(;_a(s,r)===1;)if(r++>1e3)throw new Error("Cannot find square root: probably non-prime P");if(t===1)return Ca;let o=s.pow(r,e),i=(e+ee)/Ct;return function(a,l){let d=a;if(d.is0(l))return l;if(_a(d,l)!==1)throw new Error("Cannot find square root");let u=t,f=d.mul(d.ONE,o),p=d.pow(l,e),m=d.pow(l,i);for(;!d.eql(p,d.ONE);){if(d.is0(p))throw new Error("Cannot find square root: probably non-prime P");let h=1,g=d.sqr(p);for(;!d.eql(g,d.ONE);)if(h++,g=d.sqr(g),h===u)throw new Error("Cannot find square root");let b=ee<<BigInt(u-h-1),w=d.pow(f,b);u=h,f=d.sqr(w),p=d.mul(p,f),m=d.mul(m,w)}return m}}function Sd(n){return li(n,"Fp.sqrt"),n%ai===Ra?Ca:n%xa===Ta?Ed:n%Aa===yd?_d(n):Da(n)}var Rd=["create","isValid","is0","neg","inv","sqrt","sqr","eql","add","sub","mul","pow","div","addN","subN","mulN","sqrN"];function Nn(n){if(vt(n,"field"),typeof n.ORDER!="bigint")throw new TypeError('param "ORDER" is invalid: expected bigint, got '+typeof n.ORDER);Yt(n.BYTES,"BYTES"),Yt(n.BITS,"BITS");for(let e of Rd)Ue(n[e],"field."+e);if(n.BYTES<1||n.BITS<1)throw new Error("invalid field: expected BYTES/BITS > 0");if(n.ORDER<=ee)throw new Error("invalid field: expected ORDER > 1, got "+n.ORDER);return n}function di(n,e,t=!1){Nn(n),xr(e,"nums"),We(t,"passZero");let r=n,s=new Array(e.length).fill(t?r.ZERO:void 0),o=e.reduce((c,a,l)=>r.is0(a)?c:(s[l]=c,r.mul(c,a)),r.ONE),i=r.inv(o);return e.reduceRight((c,a,l)=>r.is0(a)?c:(s[l]=r.mul(c,s[l]),r.mul(c,a)),i),s}function _a(n,e){Nn(n);let t=n;li(t.ORDER,"FpLegendre");let r=(t.ORDER-ee)/Ct,s=t.pow(e,r),o=t.eql(s,t.ONE),i=t.eql(s,t.ZERO),c=t.eql(s,t.neg(t.ONE));if(!o&&!i&&!c)throw new Error("invalid Legendre symbol result");return o?1:i?0:-1}function Td(n,e){if(e!==void 0&&ni(e),n<=ye)throw new Error("invalid n length: expected positive n, got "+n);if(e!==void 0&&e<1)throw new Error("invalid n length: expected positive bit length, got "+e);let t=On(n);if(e!==void 0&&e<t)throw new Error(`invalid n length: expected nBitLength (${e}) >= bitLen(n) (${t})`);let r=e!==void 0?e:t,s=Math.ceil(r/8);return{nBitLength:r,nByteLength:s}}var Sa=new WeakMap,Bs=class{ORDER;BITS;BYTES;isLE;ZERO=ye;ONE=ee;_lengths;_mod;constructor(e,t={}){if(e<=ee)throw new Error("invalid field: expected ORDER > 1, got "+e);let r;this.isLE=!1,t!=null&&typeof t=="object"&&(typeof t.BITS=="number"&&(r=t.BITS),typeof t.sqrt=="function"&&Object.defineProperty(this,"sqrt",{value:t.sqrt,enumerable:!0}),typeof t.isLE=="boolean"&&(this.isLE=t.isLE),t.allowedLengths&&(this._lengths=Object.freeze(t.allowedLengths.slice())),typeof t.modFromBytes=="boolean"&&(this._mod=t.modFromBytes));let{nBitLength:s,nByteLength:o}=Td(e,r);if(o>2048)throw new Error("invalid field: expected ORDER of <= 2048 bytes");this.ORDER=e,this.BITS=s,this.BYTES=o,Object.freeze(this)}create(e){return Pe(e,this.ORDER)}isValid(e){if(typeof e!="bigint")throw new TypeError("invalid field element: expected bigint, got "+typeof e);return ye<=e&&e<this.ORDER}is0(e){return e===ye}isValidNot0(e){return!this.is0(e)&&this.isValid(e)}isOdd(e){return(e&ee)===ee}neg(e){return Pe(-e,this.ORDER)}eql(e,t){return e===t}sqr(e){return Pe(e*e,this.ORDER)}add(e,t){return Pe(e+t,this.ORDER)}sub(e,t){return Pe(e-t,this.ORDER)}mul(e,t){return Pe(e*t,this.ORDER)}pow(e,t){return va(e,t,this.ORDER)}div(e,t){return Pe(e*Ea(t,this.ORDER),this.ORDER)}sqrN(e){return e*e}addN(e,t){return e+t}subN(e,t){return e-t}mulN(e,t){return e*t}inv(e){return Ea(e,this.ORDER)}sqrt(e){let t=Sa.get(this);return t||Sa.set(this,t=Sd(this.ORDER)),t(this,e)}toBytes(e){return this.isLE?si(e,this.BYTES):vr(e,this.BYTES)}fromBytes(e,t=!1){fe(e);let{_lengths:r,BYTES:s,isLE:o,ORDER:i,_mod:c}=this;if(r){if(e.length<1||!r.includes(e.length)||e.length>s)throw new Error("Field.fromBytes: expected "+r+" bytes, got "+e.length);let l=new Uint8Array(s);l.set(e,o?0:l.length-e.length),e=l}if(e.length!==s)throw new Error("Field.fromBytes: expected "+s+" bytes, got "+e.length);let a=o?Ms(e):je(e);if(c&&(a=Pe(a,i)),!t&&!this.isValid(a))throw new Error("invalid field element: outside of range 0..ORDER");return a}invertBatch(e){return di(this,e,!0)}cmov(e,t,r){return We(r,"condition"),r?t:e}};function Fs(n,e={}){return Object.freeze(Bs.prototype),new Bs(n,e)}function ka(n){if(typeof n!="bigint")throw new Error("field order must be bigint");if(n<=ee)throw new Error("field order must be greater than 1");let e=On(n-ee);return Math.ceil(e/8)}function Hs(n){let e=ka(n);return e+Math.ceil(e/2)}function ui(n,e,t=!1){fe(n);let r=n.length,s=ka(e),o=Math.max(Hs(e),16);if(r<o||r>1024)throw new Error("expected "+o+"-1024 bytes of input, got "+r);let i=t?Ms(n):je(n),c=Pe(i,e-ee)+ee;return t?si(c,s):vr(c,s)}var mi=BigInt(0),Cr=BigInt(1),xd=BigInt(4),pi=16,La=128,Ad=5,Oa=2**31;function In(n){let e=n;if(typeof e!="function")throw new TypeError('"Point" expected constructor, got type='+typeof n);Ue(e.fromAffine,"Point.fromAffine"),Ue(e.fromBytes,"Point.fromBytes"),Ue(e.fromHex,"Point.fromHex"),vt(e.BASE,"Point.BASE"),vt(e.ZERO,"Point.ZERO"),Nn(e.Fp),Nn(e.Fn)}function Ia(n,e){In(n),Ua(e,n);let t=di(n.Fp,e.map(r=>r.Z));return e.map((r,s)=>n.fromAffine(r.toAffine(t[s])))}function vd(n,e,t=1){if(!Number.isSafeInteger(n)||n<t||n>e)throw new Error("invalid window size, expected ["+t+".."+e+"], got W="+n)}function Pd(n,e){let t=n*(4*e+128);if(t>Oa)throw new Error("invalid window size: table would need ~"+Math.ceil(t/2**20)+" MiB, max "+Oa/2**20+" MiB")}function hi(n,e){if(n!==void 0){Ue(n,"randomBytes");try{let t=n(e);if(!Ln(t)||t.length!==e)return}catch{return}return n}}function Ua(n,e){xr(n,"points"),n.forEach((t,r)=>{if(!(t instanceof e))throw new Error("invalid point at index "+r)})}function Cd(n,e,t){if(!Array.isArray(n))throw new Error("array of scalars expected");n.forEach((r,s)=>{if(!(t===void 0?e.isValid(r):Pt(r)&&r<t))throw new Error("invalid scalar at index "+s)})}var Ma=new WeakMap;function fi(n){return Ma.get(n)||1}function Dd(n,e){let t=n.double(),r=[n];for(let s=1;s<e;s++)r.push(r[s-1].add(t));return r}function kd(n,e){let t=2**e,r=t/2,s=BigInt(t-1),o=[];for(;n>mi;){let i=0;n&Cr&&(i=Number(n&s),i>=r&&(i-=t),n-=BigInt(i)),o.push(i),n>>=Cr}return o}function Ld(n,e,t){let r=2**e,s=r/2,o=BigInt(r-1),i=BigInt(e),c=[];for(let a=0;a<t;a++){let l=Number(n&o);n>>=i,l>s&&(l-=r,n+=Cr),c.push(l)}if(n!==mi)throw new Error("invalid wnaf");return c}function Od(n,e,t){let r=0;for(let o of t)r=Math.max(r,o.length);let s=n;for(let o=r-1;o>=0;o--){o!==r-1&&(s=s.double());for(let i=0;i<t.length;i++){let c=t[i][o];if(c){let a=e[i][Math.abs(c)-1>>1];s=s.add(c<0?a.negate():a)}}}return s}var $s=class{Point;BASE;ZERO;randomBytes;wnafPrecomputes=new WeakMap;baseCanBeBlinded;bits;constructor(e,t){In(e),this.randomBytes=hi(t,pi),this.Point=e,this.BASE=e.BASE,this.ZERO=e.ZERO,this.bits=e.Fn.BITS}buildWnafTable(e,t,r){let s=Math.ceil(r/t)+1,o=2**(t-1),i=[],c=e;for(let a=0;a<s;a++){let l=c;for(let d=0;d<o;d++)i.push(l),l=l.add(c);c=i[i.length-1].double()}return{W:t,bits:r,windows:s,comp:i}}wnafCachedCT(e,t){let{W:r,windows:s,comp:o}=e,i=2**(r-1),c=Ld(t,r,s),a=this.ZERO,l=this.BASE;for(let d=0;d<s;d++){let u=c[d],f=d*i,p=Math.abs(u)-1,m=o[f];for(let g=1;g<i;g++)m=g===p?o[f+g]:m;let h=m.negate();u===0?l=l.add(o[f]):a=a.add(u<0?h:m)}return{p:a,f:l}}getWnafPrecomputes(e,t,r,s){let o=this.wnafPrecomputes.get(t),i=o?.find(c=>c.W===e&&c.bits===r);return i||(i=this.buildWnafTable(t,e,r),typeof s=="function"&&(i={...i,comp:s(i.comp)}),o||(o=[],this.wnafPrecomputes.set(t,o)),o.push(i)),i}assertPoint(e){if(!(e instanceof this.Point))throw new TypeError('"point" expected Point instance, got type='+typeof e)}validateMulInput(e,t){if(this.assertPoint(e),!oi(t,Cr,this.Point.Fn.ORDER))throw new Error("invalid scalar")}runCT(e,t,r,s){let o=fi(e);return o===1?this.fixedWindowCT(e,t,r):this.wnafCachedCT(this.getWnafPrecomputes(o,e,r,s),t)}mulCT(e,t,r){return this.validateMulInput(e,t),this.runCT(e,t,this.bits,r)}mulCTBlinded(e,t,r){if(this.validateMulInput(e,t),this.randomBytes===void 0)throw new Error("randomBytes is required for scalar blinding");let s=this.Point.Fn.BITS+La,o=this.randomBytes(pi);if(!Ln(o)||o.length!==pi)throw new Error("randomBytes returned invalid byte array");o[0]=o[0]&63|128;let i=t+je(o)*this.Point.Fn.ORDER;return this.runCT(e,i,s,r)}fixedWindowCT(e,t,r){let s=Ad,o=1<<s,i=Pr(s),c=new Array(o);c[0]=this.ZERO;for(let d=1;d<o;d++)c[d]=c[d-1].add(e);let a=Math.ceil(r/s),l=this.ZERO;for(let d=a-1;d>=0;d--){if(d!==a-1)for(let p=0;p<s;p++)l=l.double();let u=Number(t>>BigInt(d*s)&i),f=c[0];for(let p=1;p<o;p++)f=p===u?c[p]:f;l=l.add(f)}return{p:l,f:l}}shouldBlind(e,t){return this.randomBytes===void 0?!1:t===Cr?!0:e!==this.BASE?!1:(this.baseCanBeBlinded===void 0&&(this.baseCanBeBlinded=this.mulUnsafe(this.BASE,this.Point.Fn.ORDER).is0()),this.baseCanBeBlinded)}mulSecret(e,t,r,s){return this.shouldBlind(e,r)?this.mulCTBlinded(e,t,s):this.mulCT(e,t,s)}mulUnsafe(e,t,r){if(this.assertPoint(e),!Pt(t))throw new Error("invalid scalar");let s=fi(e);if(s===1||t>=this.Point.Fn.ORDER)return Ks(this.Point,[e],[t],!0);let o=this.getWnafPrecomputes(s,e,this.bits,r);return this.wnafCachedCT(o,t).p}setWindowSize(e,t){this.assertPoint(e),vd(t,this.bits);let r=Math.ceil((this.bits+La)/t)+1;Pd(r*2**(t-1),this.Point.Fp.BYTES),Ma.set(e,t),this.wnafPrecomputes.delete(e)}hasWindowSize(e){return fi(e)!==1}};function Ks(n,e,t,r=!1){if(In(n),Ua(e,n),We(r,"allowOversized"),Cd(t,n.Fn,r?n.Fn.ORDER**xd:void 0),e.length!==t.length)throw new Error("arrays of points and scalars must have equal length");let s=e.map(i=>Dd(i,4)),o=t.map(i=>kd(i,4));return Od(n.ZERO,s,o)}function Na(n,e,t){if(e){if(e.ORDER!==n)throw new Error("Field.ORDER must match order: Fp == p, Fn == n");return Nn(e),e}else return Fs(n,{isLE:t})}function Ba(n,e,t={},r){if(n!=="weierstrass"&&n!=="edwards")throw new Error('expected curve type "weierstrass" or "edwards"');if(r===void 0&&(r=n==="edwards"),!e||typeof e!="object")throw new Error(`expected valid ${n} CURVE object`);et(t);for(let a of["p","n","h"]){let l=e[a];if(!(Pt(l)&&l!==mi))throw new Error(`CURVE.${a} must be positive bigint`)}let s=Na(e.p,t.Fp,r),o=Na(e.n,t.Fn,r),c=["Gx","Gy","a",n==="weierstrass"?"b":"d"];for(let a of c)if(!s.isValid(e[a]))throw new Error(`CURVE.${a} must be valid field element of CURVE.Fp`);return e=Object.freeze(Object.assign({},e)),{CURVE:e,Fp:s,Fn:o}}function Fa(n,e){return function(r){let s=n(r);return{secretKey:s,publicKey:e(s)}}}var Ws=class{oHash;iHash;blockLen;outputLen;canXOF=!1;finished=!1;destroyed=!1;constructor(e,t){if(Cn(e),z(t,void 0,"key"),this.iHash=e.create(),typeof this.iHash.update!="function")throw new Error("expected Hash instance");this.blockLen=this.iHash.blockLen,this.outputLen=this.iHash.outputLen;let r=this.blockLen,s=new Uint8Array(r);s.set(t.length>r?e.create().update(t).digest():t);for(let o=0;o<s.length;o++)s[o]^=54;this.iHash.update(s),this.oHash=e.create();for(let o=0;o<s.length;o++)s[o]^=106;this.oHash.update(s),At(s)}update(e){return ct(this),this.iHash.update(e),this}digestInto(e){ct(this),Dn(e,this),this.finished=!0;let t=e.subarray(0,this.outputLen);this.iHash.digestInto(t),this.oHash.update(t),this.oHash.digestInto(t),this.destroy()}digest(){let e=new Uint8Array(this.oHash.outputLen);return this.digestInto(e),e}_cloneInto(e){e||=Object.create(Object.getPrototypeOf(this),{});let{oHash:t,iHash:r,finished:s,destroyed:o,blockLen:i,outputLen:c,canXOF:a}=this;return e=e,e.finished=s,e.destroyed=o,e.blockLen=i,e.outputLen=c,e.canXOF=a,e.oHash=t._cloneInto(e.oHash),e.iHash=r._cloneInto(e.iHash),e}clone(){return this._cloneInto()}destroy(){this.destroyed=!0,this.oHash.destroy(),this.iHash.destroy()}},Ha=(()=>{let n=((e,t,r)=>new Ws(e,t).update(r).digest());return n.create=(e,t)=>new Ws(e,t),n})();var Nd=BigInt(0),gi=class extends Error{constructor(e=""){super(e)}},lt={Err:gi,_tlv:{encode:(n,e)=>{let{Err:t}=lt;if(Yt(n,"tag"),n<0||n>255)throw new t("tlv.encode: wrong tag");if(ga(e,"data"),e.length&1)throw new t("tlv.encode: unpadded data");let r=e.length/2,s=Ar(r);if(s.length/2&128)throw new t("tlv.encode: long form length too big");let o=r>127?Ar(s.length/2|128):"";return Ar(n)+o+s+e},decode(n,e){let{Err:t}=lt;e=fe(e,void 0,"DER data");let r=0;if(n<0||n>255)throw new t("tlv.decode: wrong tag");if(e.length<2||e[r++]!==n)throw new t("tlv.decode: wrong tlv");let s=e[r++],o=!!(s&128),i=0;if(!o)i=s;else{let a=s&127;if(!a)throw new t("tlv.decode(long): indefinite length not supported");if(a>4)throw new t("tlv.decode(long): byte length is too big");let l=e.subarray(r,r+a);if(l.length!==a)throw new t("tlv.decode: length bytes not complete");if(l[0]===0)throw new t("tlv.decode(long): zero leftmost byte");for(let d of l)i=i<<8|d;if(r+=a,i<128)throw new t("tlv.decode(long): not minimal encoding")}let c=e.subarray(r,r+i);if(c.length!==i)throw new t("tlv.decode: wrong value length");return{v:c,l:e.subarray(r+i)}}},_int:{encode(n){let{Err:e}=lt;if(Us(n),n<Nd)throw new e("integer: negative integers are not allowed");let t=Ar(n);if(Number.parseInt(t[0],16)&8&&(t="00"+t),t.length&1)throw new e("unexpected DER parsing assertion: unpadded hex");return t},decode(n){let{Err:e}=lt;if(n.length<1)throw new e("invalid signature integer: empty");if(n[0]&128)throw new e("invalid signature integer: negative");if(n.length>1&&n[0]===0&&!(n[1]&128))throw new e("invalid signature integer: unnecessary leading zero");return je(n)}},toSig(n,e){let{Err:t,_int:r,_tlv:s}=lt;if(e!==void 0&&(Yt(e,"maxScalarBytes"),e<1))throw new t("invalid signature: maxScalarBytes must be positive");let o=fe(n,void 0,"signature"),{v:i,l:c}=s.decode(48,o);if(c.length)throw new t("invalid signature: left bytes after parsing");let{v:a,l}=s.decode(2,i),{v:d,l:u}=s.decode(2,l);if(u.length)throw new t("invalid signature: left bytes after parsing");if(e!==void 0&&(a.length>e||d.length>e))throw new t("invalid signature: integer too large");return{r:r.decode(a),s:r.decode(d)}},hexFromSig(n){let{_tlv:e,_int:t}=lt;et(n,{r:"bigint",s:"bigint"},{},"sig");let r=e.encode(2,t.encode(n.r)),s=e.encode(2,t.encode(n.s)),o=r+s;return e.encode(48,o)}},js=(Object.freeze(lt._tlv),Object.freeze(lt._int),Object.freeze(lt));var $a=(n,e)=>(n+(n>=0?e:-e)/Ka)/e;function Id(n,e,t){ii("scalar",n,dt,t);let[[r,s],[o,i]]=e,c=$a(i*n,t),a=$a(-s*n,t),l=n-c*r-a*o,d=-c*s-a*i,u=l<dt,f=d<dt;u&&(l=-l),f&&(d=-d);let p=Pr(Math.ceil(On(t)/2))+zt;if(l<dt||l>=p||d<dt||d>=p)throw new Error("splitScalar (endomorphism): failed for k");return{k1neg:u,k1:l,k2neg:f,k2:d}}function bi(n){if(!["compact","recovered","der"].includes(n))throw new Error('Signature format must be "compact", "recovered", or "der"');return n}function yi(n,e){et(n);let t={};for(let r of Object.keys(e))t[r]=n[r]===void 0?e[r]:n[r];return We(t.lowS,"lowS"),We(t.prehash,"prehash"),t.format!==void 0&&bi(t.format),t}var dt=BigInt(0),zt=BigInt(1),Ka=BigInt(2),wi=BigInt(3),Ud=BigInt(4);function Wa(n,e={}){let t=Ba("weierstrass",n,e),r=t.Fp,s=t.Fn,o=t.CURVE,{h:i,n:c}=o;et(e,{},{allowInfinityPoint:"boolean",clearCofactor:"function",isTorsionFree:"function",fromBytes:"function",toBytes:"function",endo:"object",randomBytes:"function"});let{endo:a,allowInfinityPoint:l,clearCofactor:d,isTorsionFree:u,fromBytes:f,toBytes:p}=e,m=e.randomBytes===void 0?Is:e.randomBytes;if(a&&(!r.is0(o.a)||typeof a.beta!="bigint"||!Array.isArray(a.basises)))throw new Error('invalid endo: expected "beta": bigint and "basises": array');let h=a?{beta:a.beta,basises:a.basises.map(k=>[...k])}:void 0,g=Va(r,s);function b(){if(!r.isOdd)throw new Error("compression is not supported: Field does not have .isOdd()")}function w(k,R,A){if(R.is0()){if(!l)throw new Error("bad point: ZERO");return Uint8Array.of(0)}let{x:D,y:N}=R.toAffine(),U=r.toBytes(D);if(We(A,"isCompressed"),A){b();let M=!r.isOdd(N);return Ke(ja(M),U)}else return Ke(Uint8Array.of(4),U,r.toBytes(N))}function y(k){fe(k,void 0,"Point");let{publicKey:R,publicKeyUncompressed:A}=g,D=k.length,N=k[0],U=k.subarray(1);if(l&&D===1&&N===0)return{x:r.ZERO,y:r.ZERO};if(D===R&&(N===2||N===3)){let M=r.fromBytes(U);if(!r.isValid(M))throw new Error("bad point: is not on curve, wrong x");let $=T(M),B;try{B=r.sqrt($)}catch(W){let G=W instanceof Error?": "+W.message:"";throw new Error("bad point: is not on curve, sqrt error"+G)}b();let F=r.isOdd(B);return(N&1)===1!==F&&(B=r.neg(B)),{x:M,y:B}}else if(D===A&&N===4){let M=r.BYTES,$=r.fromBytes(U.subarray(0,M)),B=r.fromBytes(U.subarray(M,M*2));if(!v($,B))throw new Error("bad point: is not on curve");return{x:$,y:B}}else throw new Error(`bad point: got length ${D}, expected compressed=${R} or uncompressed=${A}`)}let E=p===void 0?w:p,_=f===void 0?y:f,S=r.mul(o.b,wi),x=r.is0(o.a)?k=>r.ZERO:k=>r.mul(o.a,k);function T(k){let R=r.sqr(k),A=r.mul(R,k);return r.add(r.add(A,r.mul(k,o.a)),o.b)}function v(k,R){let A=r.sqr(R),D=T(k);return r.eql(A,D)}if(!v(o.Gx,o.Gy))throw new Error("bad curve params: generator point");let C=r.mul(r.pow(o.a,wi),Ud),L=r.mul(r.sqr(o.b),BigInt(27));if(r.is0(r.add(C,L)))throw new Error("bad curve params: a or b");function H(k,R,A=!1){if(!r.isValid(R)||A&&r.is0(R))throw new Error(`bad point coordinate ${k}`);return typeof R=="object"&&R!==null?r.create(R):R}function V(k){if(!(k instanceof K))throw new Error("Weierstrass Point expected")}function Q(k){if(!h||!h.basises)throw new Error("no endo");return Id(k,h.basises,s.ORDER)}function Z(k,R,A,D){if(!s.isValid(D))throw new RangeError("invalid scalar: out of range");if(h){let{k1neg:N,k1:U,k2neg:M,k2:$}=Q(D),B=new K(r.mul(A.X,h.beta),A.Y,A.Z);k.push(N?A.negate():A,M?B.negate():B),R.push(U,$)}else k.push(A),R.push(D)}let _e=new WeakSet;class K{static BASE=new K(o.Gx,o.Gy,r.ONE);static ZERO=new K(r.ZERO,r.ONE,r.ZERO);static Fp=r;static Fn=s;X;Y;Z;constructor(R,A,D){this.X=H("x",R),this.Y=H("y",A,!0),this.Z=H("z",D),Object.freeze(this)}static CURVE(){return o}static fromAffine(R){let{x:A,y:D}=R||{};if(!R||!r.isValid(A)||!r.isValid(D))throw new Error("invalid affine point");if(R instanceof K)throw new Error("projective point not allowed");return r.is0(A)&&r.is0(D)?K.ZERO:new K(A,D,r.ONE)}static fromBytes(R){let A=K.fromAffine(_(fe(R,void 0,"point")));return A.assertValidity(),A}static fromHex(R){return K.fromBytes(Ns(R))}get x(){return this.toAffine().x}get y(){return this.toAffine().y}precompute(R=6,A=!0){return ie.setWindowSize(this,R),A||this.multiply(wi),this}assertValidity(){let R=this;if(R.is0()){if(l&&r.is0(R.X)&&r.eql(R.Y,r.ONE)&&r.is0(R.Z))return;throw new Error("bad point: ZERO")}if(_e.has(R))return;let{x:A,y:D}=R.toAffine();if(!r.isValid(A)||!r.isValid(D))throw new Error("bad point: x or y not field elements");if(!v(A,D))throw new Error("bad point: equation left != right");if(!R.isTorsionFree())throw new Error("bad point: not in prime-order subgroup");_e.add(R)}hasEvenY(){let{y:R}=this.toAffine();if(!r.isOdd)throw new Error("Field doesn't support isOdd");return!r.isOdd(R)}equals(R){V(R);let{X:A,Y:D,Z:N}=this,{X:U,Y:M,Z:$}=R,B=r.eql(r.mul(A,$),r.mul(U,N)),F=r.eql(r.mul(D,$),r.mul(M,N));return B&&F}negate(){return new K(this.X,r.neg(this.Y),this.Z)}double(){let{X:R,Y:A,Z:D}=this,N=r.ZERO,U=r.ZERO,M=r.ZERO,$=r.mul(R,R),B=r.mul(A,A),F=r.mul(D,D),I=r.mul(R,A);return I=r.add(I,I),M=r.mul(R,D),M=r.add(M,M),N=x(M),U=r.mul(S,F),U=r.add(N,U),N=r.sub(B,U),U=r.add(B,U),U=r.mul(N,U),N=r.mul(I,N),M=r.mul(S,M),F=x(F),I=r.sub($,F),I=x(I),I=r.add(I,M),M=r.add($,$),$=r.add(M,$),$=r.add($,F),$=r.mul($,I),U=r.add(U,$),F=r.mul(A,D),F=r.add(F,F),$=r.mul(F,I),N=r.sub(N,$),M=r.mul(F,B),M=r.add(M,M),M=r.add(M,M),new K(N,U,M)}add(R){V(R);let{X:A,Y:D,Z:N}=this,{X:U,Y:M,Z:$}=R,B=r.ZERO,F=r.ZERO,I=r.ZERO,W=r.mul(A,U),G=r.mul(D,M),te=r.mul(N,$),De=r.add(A,D),se=r.add(U,M);De=r.mul(De,se),se=r.add(W,G),De=r.sub(De,se),se=r.add(A,N);let ce=r.add(U,$);return se=r.mul(se,ce),ce=r.add(W,te),se=r.sub(se,ce),ce=r.add(D,N),B=r.add(M,$),ce=r.mul(ce,B),B=r.add(G,te),ce=r.sub(ce,B),I=x(se),B=r.mul(S,te),I=r.add(B,I),B=r.sub(G,I),I=r.add(G,I),F=r.mul(B,I),G=r.add(W,W),G=r.add(G,W),te=x(te),se=r.mul(S,se),G=r.add(G,te),te=r.sub(W,te),te=x(te),se=r.add(se,te),W=r.mul(G,se),F=r.add(F,W),W=r.mul(ce,se),B=r.mul(De,B),B=r.sub(B,W),W=r.mul(De,G),I=r.mul(ce,I),I=r.add(I,W),new K(B,F,I)}subtract(R){return V(R),this.add(R.negate())}is0(){return this.equals(K.ZERO)}multiply(R){if(!s.isValidNot0(R))throw new RangeError("invalid scalar: out of range");let{p:A,f:D}=ie.mulSecret(this,R,i,Se);return Se([A,D])[0]}multiplyUnsafe(R){let A=this,D=R;if(!s.isValid(D))throw new RangeError("invalid scalar: out of range");if(D===dt||A.is0())return K.ZERO;if(D===zt)return A;if(ie.hasWindowSize(this))return ie.mulUnsafe(A,D,Se);let N=[],U=[];return Z(N,U,A,D),Ks(K,N,U)}mulAddUnsafe(R,A,D){V(A);let N=[],U=[];return Z(N,U,this,R),Z(N,U,A,D),Ks(K,N,U)}toAffine(R){let A=this,D=R;if(D!=null&&!r.isValid(D))throw new RangeError('"invertedZ" expected valid field element');let{X:N,Y:U,Z:M}=A;if(r.eql(M,r.ONE))return{x:N,y:U};let $=A.is0();D==null&&(D=$?r.ONE:r.inv(M));let B=r.mul(N,D),F=r.mul(U,D),I=r.mul(M,D);if($)return{x:r.ZERO,y:r.ZERO};if(!r.eql(I,r.ONE))throw new Error("invZ was invalid");return{x:B,y:F}}isTorsionFree(){return i===zt?!0:u?u(K,this):ie.mulUnsafe(this,c).is0()}clearCofactor(){return i===zt?this:d?d(K,this):this.multiplyUnsafe(i)}isSmallOrder(){return i===zt?this.is0():this.clearCofactor().is0()}toBytes(R=!0){return We(R,"isCompressed"),this.assertValidity(),E(K,this,R)}toHex(R=!0){return ri(this.toBytes(R))}toString(){return`<Point ${this.is0()?"ZERO":this.toHex()}>`}}let Se=k=>Ia(K,k),ie=new $s(K,m);return ie.bits>=6&&K.BASE.precompute(6),Object.freeze(K.prototype),Object.freeze(K),K}function ja(n){return Uint8Array.of(n?2:3)}function Va(n,e){return{secretKey:e.BYTES,publicKey:1+n.BYTES,publicKeyUncompressed:1+2*n.BYTES,publicKeyHasPrefix:!0,signature:2*e.BYTES}}function Md(n,e={}){In(n);let{Fn:t}=n,r=e.randomBytes===void 0?Is:e.randomBytes,s=Object.assign(Va(n.Fp,t),{seed:Math.max(Hs(t.ORDER),16)});function o(p){try{let m=t.fromBytes(p);return t.isValidNot0(m)}catch{return!1}}function i(p,m){let{publicKey:h,publicKeyUncompressed:g}=s;try{let b=p.length;return m===!0&&b!==h||m===!1&&b!==g?!1:!n.fromBytes(p).is0()}catch{return!1}}function c(p){return p=p===void 0?r(s.seed):p,ui(fe(p,s.seed,"seed"),t.ORDER)}function a(p,m=!0){return n.BASE.multiply(t.fromBytes(p)).toBytes(m)}function l(p){let{secretKey:m,publicKey:h,publicKeyUncompressed:g}=s,b=t._lengths;if(!Ln(p))return;let w=fe(p,void 0,"key").length,y=w===h||w===g,E=w===m||!!b?.includes(w);if(!(y&&E))return y}function d(p,m,h=!0){if(l(p)===!0)throw new Error("first arg must be private key");if(l(m)===!1)throw new Error("second arg must be public key");let g=t.fromBytes(p),b=n.fromBytes(m);if(b.is0())throw new Error("invalid public key: point at infinity");return b.multiply(g).toBytes(h)}let u={isValidSecretKey:o,isValidPublicKey:i,randomSecretKey:c},f=Fa(c,a);return Object.freeze(u),Object.freeze(s),Object.freeze({getPublicKey:a,getSharedSecret:d,keygen:f,Point:n,utils:u,lengths:s})}function Ga(n,e,t={}){In(n);let r=e;Cn(r),et(t,{},{hmac:"function",lowS:"boolean",randomBytes:"function",bits2int:"function",bits2int_modN:"function"});let s=Object.assign({},t),o=s.randomBytes===void 0?Is:s.randomBytes,i=s.hmac===void 0?(k,R)=>Ha(r,k,R):s.hmac,{Fp:c,Fn:a}=n,{ORDER:l,BITS:d}=a,u=Hs(l),f=hi(o,u),{keygen:p,getPublicKey:m,getSharedSecret:h,utils:g,lengths:b}=Md(n,s),w={prehash:!0,lowS:typeof s.lowS=="boolean"?s.lowS:!0,format:"compact",extraEntropy:!1},y=l*Ka+zt<c.ORDER;function E(k){let R=l>>zt;return k>R}function _(k,R){if(!a.isValidNot0(R))throw new Error(`invalid signature ${k}: out of range 1..Point.Fn.ORDER`);return R}function S(){if(!c.isOdd)throw new Error("Field doesn't support isOdd")}function x(k,R,A){return S(),(k===A?0:2)|Number(c.isOdd(R))}function T(){if(y)throw new Error('"recovered" sig type is not supported for cofactor >2 curves')}function v(k,R){bi(R);let A=b.signature,D=R==="compact"?A:R==="recovered"?A+1:void 0;return fe(k,D)}class C{r;s;recovery;constructor(R,A,D){if(this.r=_("r",R),this.s=_("s",A),D!=null){if(T(),![0,1,2,3].includes(D))throw new Error("invalid recovery id");this.recovery=D}Object.freeze(this)}static fromBytes(R,A=w.format){v(R,A);let D;if(A==="der"){if(R.length>2*a.BYTES+16)throw new js.Err("invalid signature: DER signature too long");let{r:$,s:B}=js.toSig(fe(R),a.BYTES+1);return new C($,B)}A==="recovered"&&(D=R[0],A="compact",R=R.subarray(1));let N=b.signature/2,U=R.subarray(0,N),M=R.subarray(N,N*2);return new C(a.fromBytes(U),a.fromBytes(M),D)}static fromHex(R,A){return this.fromBytes(Ns(R),A)}assertRecovery(){let{recovery:R}=this;if(R==null)throw new Error("invalid recovery id: must be present");return R}addRecoveryBit(R){return new C(this.r,this.s,R)}recoverPublicKey(R){let{r:A,s:D}=this,N=this.assertRecovery(),U=N===2||N===3?A+l:A;if(!c.isValid(U))throw new Error("invalid recovery id: sig.r+curve.n != R.x");let M=c.toBytes(U),$=n.fromBytes(Ke(ja((N&1)===0),M)),B=a.inv(U),F=H(fe(R,void 0,"msgHash")),I=a.create(-F*B),W=a.create(D*B),G=n.BASE.mulAddUnsafe(I,$,W);if(G.is0())throw new Error("invalid recovery: point at infinify");return G.assertValidity(),G}hasHighS(){return E(this.s)}toBytes(R=w.format){if(bi(R),R==="der")return Ns(js.hexFromSig(this));let{r:A,s:D}=this,N=a.toBytes(A),U=a.toBytes(D);return R==="recovered"?(T(),Ke(Uint8Array.of(this.assertRecovery()),N,U)):Ke(N,U)}toHex(R){return ri(this.toBytes(R))}}Object.freeze(C.prototype),Object.freeze(C);let L=s.bits2int===void 0?function(R){if(R.length>8192)throw new Error("input is too large");let A=je(R),D=R.length*8-d;return D>0?A>>BigInt(D):A}:s.bits2int,H=s.bits2int_modN===void 0?function(R){return a.create(L(R))}:s.bits2int_modN,V=Pr(d);function Q(k){return ii("num < 2^"+d,k,dt,V),a.toBytes(k)}function Z(k,R){return fe(k,void 0,"message"),R?fe(r(k),void 0,"prehashed message"):k}function _e(k,R,A){let{lowS:D,prehash:N,extraEntropy:U}=yi(A,w);k=Z(k,N);let M=H(k),$=a.fromBytes(R);if(!a.isValidNot0($))throw new Error("invalid private key");let B=[Q($),Q(M)];if(U!=null&&U!==!1){let G=U===!0?o(b.secretKey):U;B.push(fe(G,void 0,"extraEntropy"))}let F=Ke(...B),I=M;function W(G){let te=L(G);if(!a.isValidNot0(te))return;let De=n.BASE.multiply(te).toAffine(),se=a.create(De.x);if(se===dt)return;let ce;if(f!==void 0){let er=je(ui(f(u),l)),Ml=a.inv(a.mul(er,te)),Bl=a.mul(er,I),Fl=a.mul(er,$);ce=a.create(Ml*a.create(Bl+Fl*se))}else{let er=Pa(te,l);ce=a.create(er*a.create(I+se*$))}if(ce===dt)return;let Ao=x(De.x,De.y,se),Ki=ce;return D&&E(ce)&&(Ki=a.neg(ce),Ao^=1),new C(se,Ki,y?void 0:Ao)}return{seed:F,k2sig:W}}function K(k,R,A={}){let{seed:D,k2sig:N}=_e(k,R,A);return ba(r.outputLen,a.BYTES,i)(D,N).toBytes(A.format)}function Se(k,R,A,D={}){let{lowS:N,prehash:U,format:M}=yi(D,w);if(A=fe(A,void 0,"publicKey"),R=Z(R,U),!Ln(k)){let $=k instanceof C?", use sig.toBytes()":"";throw new Error("verify expects Uint8Array signature"+$)}v(k,M);try{let $=C.fromBytes(k,M),B=n.fromBytes(A);if(B.is0()||N&&$.hasHighS())return!1;let{r:F,s:I}=$,W=H(R),G=a.inv(I),te=a.create(W*G),De=a.create(F*G),se=n.BASE.mulAddUnsafe(te,B,De);if(se.is0())return!1;let ce=se.toAffine();return!(a.create(ce.x)!==F||M==="recovered"&&$.recovery!==x(ce.x,ce.y,F))}catch{return!1}}function ie(k,R,A={}){let{prehash:D}=yi(A,w);return R=Z(R,D),C.fromBytes(k,"recovered").recoverPublicKey(R).toBytes()}return Object.freeze({keygen:p,getPublicKey:m,getSharedSecret:h,utils:g,lengths:b,Point:n,sign:K,verify:Se,recoverPublicKey:ie,Signature:C,hash:r})}var Vs=BigInt(4294967295),Ja=BigInt(32);function Bd(n,e=!1){return e?{h:Number(n&Vs),l:Number(n>>Ja&Vs)}:{h:Number(n>>Ja&Vs)|0,l:Number(n&Vs)|0}}function Ya(n,e=!1){let t=n.length,r=new Uint32Array(t),s=new Uint32Array(t);for(let o=0;o<t;o++){let{h:i,l:c}=Bd(n[o],e);[r[o],s[o]]=[i,c]}return[r,s]}var Fd=n=>n/2**32|0,Hd=n=>n>>>0;function za(n,e,t,r){let s=Fd(t),o=Hd(t);n.setUint32(e,r?o:s,r),n.setUint32(e+4,r?s:o,r)}function Xa(n,e,t){return n&e^~n&t}function Qa(n,e,t){return n&e^n&t^e&t}var Gs=class{blockLen;outputLen;canXOF=!1;padOffset;isLE;buffer;view;finished=!1;length=0;pos=0;destroyed=!1;constructor(e,t,r,s){this.blockLen=e,this.outputLen=t,this.padOffset=r,this.isLE=s,this.buffer=new Uint8Array(e),this.view=ks(this.buffer)}update(e){ct(this),z(e);let{view:t,buffer:r,blockLen:s}=this,o=e.length,i=!1;for(let c=0;c<o;){let a=Math.min(s-this.pos,o-c);if(a===s){let l=ks(e);for(;s<=o-c;c+=s)this.process(l,c);i=!0;continue}r.set(c===0&&a===o?e:e.subarray(c,c+a),this.pos),this.pos+=a,c+=a,this.pos===s&&(this.process(t,0),this.pos=0,i=!0)}return this.length+=e.length,i&&this.roundClean(),this}digestInto(e){ct(this),Dn(e,this),this.finished=!0;let{buffer:t,view:r,blockLen:s,isLE:o}=this,{pos:i}=this;t[i++]=128,t.fill(0,i),this.padOffset>s-i&&(this.process(r,0),t.fill(0)),za(r,s-8,this.length*8,o),this.process(r,0),this.roundClean();let c=e===t?r:ks(e),a=this.outputLen,l=a/4,d=this.get();if(a%4||l>d.length)throw new Error("invalid outputLen");for(let u=0;u<l;u++)c.setUint32(4*u,d[u],o)}digest(){let{buffer:e,outputLen:t}=this;this.digestInto(e);let r=e.slice(0,t);return this.destroy(),r}_cloneIntoMeta(e){let{buffer:t,length:r,finished:s,destroyed:o,pos:i}=this;return e.destroyed=o,e.finished=s,e.length=r,e.pos=i,i&&e.buffer.set(t),e}clone(){return this._cloneInto()}},Za=Uint32Array.from([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]);var $d=Uint32Array.from([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),Dt=new Uint32Array(64),Ei=class extends Gs{A=0;B=0;C=0;D=0;E=0;F=0;G=0;H=0;constructor(e,t){super(64,e,8,!1),this.A=t[0]|0,this.B=t[1]|0,this.C=t[2]|0,this.D=t[3]|0,this.E=t[4]|0,this.F=t[5]|0,this.G=t[6]|0,this.H=t[7]|0}get(){let{A:e,B:t,C:r,D:s,E:o,F:i,G:c,H:a}=this;return[e,t,r,s,o,i,c,a]}set(e,t,r,s,o,i,c,a){this.A=e|0,this.B=t|0,this.C=r|0,this.D=s|0,this.E=o|0,this.F=i|0,this.G=c|0,this.H=a|0}_cloneInto(e){return(e||=new this.constructor).set(...this.get()),this._cloneIntoMeta(e)}process(e,t){for(let u=0;u<16;u++,t+=4)Dt[u]=e.getUint32(t,!1);for(let u=16;u<64;u++){let f=Dt[u-15],p=Dt[u-2],m=$e(f,7)^$e(f,18)^f>>>3,h=$e(p,17)^$e(p,19)^p>>>10;Dt[u]=h+Dt[u-7]+m+Dt[u-16]|0}let{A:r,B:s,C:o,D:i,E:c,F:a,G:l,H:d}=this;for(let u=0;u<64;u++){let f=$e(c,6)^$e(c,11)^$e(c,25),p=d+f+Xa(c,a,l)+$d[u]+Dt[u]|0,h=($e(r,2)^$e(r,13)^$e(r,22))+Qa(r,s,o)|0;d=l,l=a,a=c,c=i+p|0,i=o,o=s,s=r,r=p+h|0}r=r+this.A|0,s=s+this.B|0,o=o+this.C|0,i=i+this.D|0,c=c+this.E|0,a=a+this.F|0,l=l+this.G|0,d=d+this.H|0,this.set(r,s,o,i,c,a,l,d)}roundClean(){At(Dt)}destroy(){this.destroyed=!0,this.set(0,0,0,0,0,0,0,0),At(this.buffer)}},_i=class extends Ei{constructor(){super(32,Za)}};var qa=Tr(()=>new _i,Jt(1));function Dr(n,e="n"){if(typeof n!="number")throw new TypeError(`wrong u32 integer "${e}": expected number, got type=${typeof n}`);if(!Number.isSafeInteger(n)||n<0||n>4294967295)throw new RangeError(`wrong u32 integer "${e}": expected 0..4294967295, got ${n}`);return n}function tc(n){return Dr(n,"x"),(n&n-1)===0&&n!==0}function Si(n,e){if(Dr(n),typeof e!="number")throw new TypeError('"bits" expected number, got type='+typeof e);if(!Number.isSafeInteger(e)||e<0||e>32)throw new Error(`expected integer 0 <= bits <= 32, got ${e}`);let t=0;for(let r=0;r<e;r++,n>>>=1)t=t<<1|n&1;return t>>>0}function nc(n){return Dr(n),31-Math.clz32(n)}function ec(n){if(!n||typeof n!="object"||typeof n.length!="number")throw new TypeError('"values" expected array-like, got type='+typeof n);let e=n.length;if(!tc(e))throw new Error("expected positive power-of-two length, got "+e);let t=nc(e);for(let r=0;r<e;r++){let s=Si(r,t);if(r<s){let o=n[r];n[r]=n[s],n[s]=o}}return n}var Ri=(n,e)=>{et(e,{N:"number",roots:"object",dit:"boolean"},{invertButterflies:"boolean",skipStages:"number",brp:"boolean"},"coreOpts");let{N:t,roots:r,dit:s,invertButterflies:o=!1,skipStages:i=0,brp:c=!0}=e;Dr(t,"coreOpts.N");let a=nc(t);if(!tc(t))throw new Error("FFT: Polynomial size should be power of two");Dr(i,"coreOpts.skipStages");let l=a===0?0:a-1;if(i>l)throw new Error(`FFT: wrong skipStages: expected 0 <= skipStages <= ${l}`);if(r.length!==t)throw new Error(`FFT: wrong roots length: expected ${t}, got ${r.length}`);let d=s!==o;return u=>{if(u.length!==t)throw new Error("FFT: wrong Polynomial length");s&&c&&ec(u);for(let f=0,p=1;f<a-i;f++){let m=s?f+1+i:a-f,h=1<<m,g=h>>1,b=t>>m;for(let w=0;w<t;w+=h)for(let y=0,E=p++;y<g;y++){let _=o?s?t-E:E:y*b,S=w+y,x=w+y+g,T=r[_],v=u[x],C=u[S];if(d){let L=n.mul(v,T);u[S]=n.add(C,L),u[x]=n.sub(C,L)}else o?(u[S]=n.add(v,C),u[x]=n.mul(n.sub(v,C),T)):(u[S]=n.add(C,v),u[x]=n.mul(n.sub(C,v),T))}}return!s&&c&&ec(u),u}};var Kd={p:BigInt("0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"),n:BigInt("0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"),h:BigInt(1),a:BigInt("0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc"),b:BigInt("0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b"),Gx:BigInt("0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"),Gy:BigInt("0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5")};var Wd=Wa(Kd),rc=Ga(Wd,qa);var jd=BigInt(0),kr=BigInt(1),Vd=BigInt(2),Gd=BigInt(7),Jd=BigInt(256),Yd=BigInt(113),ic=[],ac=[],cc=[];for(let n=0,e=kr,t=1,r=0;n<24;n++){[t,r]=[r,(2*t+3*r)%5],ic.push(2*(5*r+t)),ac.push((n+1)*(n+2)/2%64);let s=jd;for(let o=0;o<7;o++)e=(e<<kr^(e>>Gd)*Yd)%Jd,e&Vd&&(s^=kr<<(kr<<BigInt(o))-kr);cc.push(s)}var lc=Ya(cc,!0),zd=lc[0],Xd=lc[1],Qd=(n,e,t)=>n<<t|e>>>32-t,Zd=(n,e,t)=>e<<t|n>>>32-t,qd=(n,e,t)=>e<<t-32|n>>>64-t,eu=(n,e,t)=>n<<t-32|e>>>64-t,sc=(n,e,t)=>t>32?qd(n,e,t):Qd(n,e,t),oc=(n,e,t)=>t>32?eu(n,e,t):Zd(n,e,t),Un=new Uint32Array(10);function tu(n,e=24){if(!(n instanceof Uint32Array))throw new TypeError('"s" expected Uint32Array(50), got type='+typeof n);if(n.length!==50)throw new RangeError('"s" expected Uint32Array(50), got length='+n.length);if(ue(e,"rounds"),e<1||e>24)throw new Error('"rounds" expected integer 1..24');for(let t=24-e;t<24;t++){for(let o=0;o<10;o++)Un[o]=n[o]^n[o+10]^n[o+20]^n[o+30]^n[o+40];for(let o=0;o<10;o+=2){let i=(o+8)%10,c=(o+2)%10,a=Un[c],l=Un[c+1],d=sc(a,l,1)^Un[i],u=oc(a,l,1)^Un[i+1];for(let f=0;f<50;f+=10)n[o+f]^=d,n[o+f+1]^=u}let r=n[2],s=n[3];for(let o=0;o<24;o++){let i=ac[o],c=sc(r,s,i),a=oc(r,s,i),l=ic[o];r=n[l],s=n[l+1],n[l]=c,n[l+1]=a}for(let o=0;o<50;o+=10){let i=n[o],c=n[o+1],a=n[o+2],l=n[o+3];n[o]^=~n[o+2]&n[o+4],n[o+1]^=~n[o+3]&n[o+5],n[o+2]^=~n[o+4]&n[o+6],n[o+3]^=~n[o+5]&n[o+7],n[o+4]^=~n[o+6]&n[o+8],n[o+5]^=~n[o+7]&n[o+9],n[o+6]^=~n[o+8]&i,n[o+7]^=~n[o+9]&c,n[o+8]^=~i&a,n[o+9]^=~c&l}n[0]^=zd[t],n[1]^=Xd[t]}At(Un)}var Js=class n{state;pos=0;posOut=0;finished=!1;state32;destroyed=!1;blockLen;suffix;outputLen;canXOF;enableXOF=!1;rounds;constructor(e,t,r,s=!1,o=24){if(ue(e,"blockLen"),ue(t,"suffix"),ue(o,"rounds"),pa(s,"enableXOF"),this.blockLen=e,this.suffix=t,this.outputLen=r,this.enableXOF=s,this.canXOF=s,this.rounds=o,ue(r,"outputLen"),!(0<e&&e<200))throw new Error('"blockLen" must be 1..199');this.state=new Uint8Array(200),this.state32=Sr(this.state)}clone(){return this._cloneInto()}keccak(){kn(this.state32),tu(this.state32,this.rounds),kn(this.state32),this.posOut=0,this.pos=0}update(e){ct(this),z(e);let{blockLen:t,state:r,state32:s}=this,o=e.length,i=t%4===0&&e.byteOffset%4===0,c=t/4,a=i&&o>=t?Sr(e):void 0;for(let l=0;l<o;){if(a!==void 0&&this.pos===0&&l%4===0&&o-l>=t){for(let u=0,f=l/4;u<c;u++)s[u]^=a[f+u];l+=t,this.pos=t,this.keccak();continue}let d=Math.min(t-this.pos,o-l);for(let u=0;u<d;u++)r[this.pos++]^=e[l++];this.pos===t&&this.keccak()}return this}finish(){if(this.finished)return;this.finished=!0;let{state:e,suffix:t,pos:r,blockLen:s}=this;e[r]^=t,(t&128)!==0&&r===s-1&&this.keccak(),e[s-1]^=128,this.keccak()}writeInto(e){ct(this,!1),z(e),this.finish();let t=this.state,{blockLen:r}=this;for(let s=0,o=e.length;s<o;){this.posOut>=r&&this.keccak();let i=Math.min(r-this.posOut,o-s);e.set(t.subarray(this.posOut,this.posOut+i),s),this.posOut+=i,s+=i}return e}xofInto(e){if(!this.enableXOF)throw new Error("XOF is not enabled");return this.writeInto(e)}xof(e){return ue(e),this.xofInto(new Uint8Array(e))}digestInto(e){if(Dn(e,this),this.finished)throw new Error("digest() was already called");this.writeInto(e.length===this.outputLen?e:e.subarray(0,this.outputLen)),this.destroy()}digest(){let e=new Uint8Array(this.outputLen);return this.digestInto(e),e}destroy(){this.destroyed=!0,At(this.state)}_cloneInto(e){let{blockLen:t,suffix:r,outputLen:s,rounds:o,enableXOF:i}=this;return e||=new n(t,r,s,i,o),e.blockLen=t,e.state32.set(this.state32),e.pos=this.pos,e.posOut=this.posOut,e.finished=this.finished,e.rounds=o,e.suffix=r,e.outputLen=s,e.enableXOF=i,e.canXOF=this.canXOF,e.destroyed=this.destroyed,e}},dc=(n,e,t,r={})=>Tr(()=>new Js(e,n,t),r);var Ys=dc(6,136,32,Jt(8));var uc=dc(6,72,64,Jt(10));var pc=(n,e,t,r={})=>Tr((s={})=>(s=ti({},s),new Js(e,n,s.dkLen===void 0?t:s.dkLen,!0)),r),fc=pc(31,168,16,Jt(11)),Mn=pc(31,136,32,Jt(12));var Ve=z;var ut=Ls;function nu(n,e,t=()=>{}){if(!Array.isArray(n))throw new TypeError(`"${e}" expected array, got type=${typeof n}`);for(let r=0;r<n.length;r++)t(n[r],`${e}[${r}]`);return n}function Ti(n,e="object"){if(n===null||typeof n!="object"||Array.isArray(n))throw new TypeError(e==="object"?"expected valid options object":`"${e}" expected object, got type=${typeof n}`);return n}function Xt(n,e){if(n=z(n),e=z(e),n.length!==e.length)return!1;let t=0;for(let r=0;r<n.length;r++)t|=n[r]^e[r];return t===0}function pt(n){return new Uint8Array(z(n))}function Qt(n,...e){let t=s=>typeof s=="number"?s:s.bytesLen,r=e.reduce((s,o)=>s+t(o),0);return{bytesLen:r,encode:s=>{let o=new Uint8Array(r);for(let i=0,c=0;i<e.length;i++){let a=e[i],l=t(a),d=typeof a=="number"?s[i]:a.encode(s[i]);z(d,l,n),o.set(d,c),typeof a!="number"&&d.fill(0),c+=l}return o},decode:s=>{z(s,r,n);let o=[];for(let i of e){let c=t(i),a=s.subarray(0,c);o.push(typeof i=="number"?a:i.decode(a)),s=s.subarray(c)}return o}}}function zs(n,e){let t=n,r=e*t.bytesLen;return{bytesLen:r,encode:s=>{let o=nu(s,"u");if(o.length!==e)throw new RangeError(`vecCoder.encode: wrong length=${o.length}. Expected: ${e}`);let i=new Uint8Array(r);for(let c=0,a=0;c<o.length;c++){let l=t.encode(o[c]);i.set(l,a),l.fill(0),a+=l.length}return i},decode:s=>{z(s,r);let o=[];for(let i=0;i<s.length;i+=t.bytesLen)o.push(t.decode(s.subarray(i,i+t.bytesLen)));return o}}}function X(...n){for(let e of n)if(Array.isArray(e))for(let t of e)t.fill(0);else e.fill(0)}function Xs(n){if(ue(n,"bits"),n>32)throw new RangeError('"bits" expected <= 32, got '+n);return n===32?4294967295:~(-1<<n)>>>0}var mc=n=>{let{newPoly:e,N:t,Q:r,F:s,ROOT_OF_UNITY:o,brvBits:i,isKyber:c}=n,a=(y,E=r)=>{let _=y%E|0;return(_>=0?_|0:E+_|0)|0},l=(y,E=r)=>{let _=a(y,E)|0;return(_>E>>1?_-E|0:_)|0};function d(){let y=e(t);for(let E=0;E<t;E++){let _=Si(E,i),S=BigInt(o)**BigInt(_)%BigInt(r);y[E]=Number(S)|0}return y}let u=d(),f=y=>{throw new Error("not implemented")},p=c?{add:(y,E)=>{let _=y+E|0;return _>=r?_-r|0:_},sub:(y,E)=>{let _=y-E|0;return _<0?_+r|0:_},mul:(y,E)=>a((y|0)*(E|0))|0,inv:f}:{add:(y,E)=>a((y|0)+(E|0))|0,sub:(y,E)=>a((y|0)-(E|0))|0,mul:(y,E)=>a((y|0)*(E|0))|0,inv:f},m={N:t,roots:u,invertButterflies:!0,skipStages:c?1:0,brp:!1},h=Ri(p,{dit:!1,...m}),g=Ri(p,{dit:!0,...m}),b={encode:y=>h(y),decode:y=>{g(y);for(let E=0;E<y.length;E++)y[E]=a(s*y[E]);return y}};return{mod:a,smod:l,nttZetas:u,NTT:{encode:y=>b.encode(y),decode:y=>b.decode(y)},bitsCoder:(y,E)=>{for(let x=0,T=0;x<t;x++)T+=y,T>32&&Xs(T),T%=8;let _=Xs(y),S=y*(t/8);return{bytesLen:S,encode:x=>{let T=x,v=new Uint8Array(S);for(let C=0,L=0,H=0,V=0;C<T.length;C++)for(L|=(E.encode(T[C])&_)<<H,H+=y;H>=8;H-=8,L>>=8)v[V++]=L&255;return v},decode:x=>{let T=e(t);for(let v=0,C=0,L=0,H=0;v<x.length;v++)for(C|=x[v]<<L,L+=8;L>=y;L-=y,C>>=y)T[H++]=E.decode(C&_);return T}}}}},ru=n=>(e,t)=>{t||(t=n.blockLen);let r=new Uint8Array(e.length+2);r.set(e);let s=e.length,o=new Uint8Array(t),i=n.create({}),c=0,a=0;return{stats:()=>({calls:c,xofs:a}),get:(l,d)=>(r[s+0]=l,r[s+1]=d,i.destroy(),i=n.create({}).update(r),c++,()=>(a++,i.xofInto(o))),clean:()=>{i.destroy(),X(o,r)}}},hc=ru(fc);var be=256,we=3329,su=3303,ou=17,Ae=mc({N:be,Q:we,F:su,ROOT_OF_UNITY:ou,newPoly:n=>new Uint16Array(n),brvBits:7,isKyber:!0}),iu=Object.freeze({512:Object.freeze({N:be,Q:we,K:2,ETA1:3,ETA2:2,du:10,dv:4,RBGstrength:128}),768:Object.freeze({N:be,Q:we,K:3,ETA1:2,ETA2:2,du:10,dv:4,RBGstrength:192}),1024:Object.freeze({N:be,Q:we,K:4,ETA1:2,ETA2:2,du:11,dv:5,RBGstrength:256})}),au=n=>{if(n>=12)return{encode:t=>t,decode:t=>t>=we?t-we:t};let e=2**(n-1);return{encode:t=>((t<<n)+we/2)/we,decode:t=>t*we+e>>>n}},cu=n=>Ae.bitsCoder(n,n===12?{encode:e=>e,decode:e=>e>=we?e-we:e}:{encode:e=>e,decode:e=>e}),Lr=n=>n===12?cu(12):Ae.bitsCoder(n,au(n));function Zt(n,e){let t=n,r=e;for(let s=0;s<be;s++){let o=t[s]+r[s];t[s]=o>=we?o-we:o}}function lu(n,e){let t=n,r=e;for(let s=0;s<be;s++){let o=t[s]-r[s];t[s]=o<0?o+we:o}}function du(n,e,t,r,s){let o=Ae.mod(Ae.mod(e*r)*s+n*t),i=Ae.mod(n*r+e*t);return{c0:o,c1:i}}function Qs(n,e){let t=n,r=e;for(let s=0;s<be/2;s++){let o=Ae.nttZetas[64+(s>>1)];s&1&&(o=-o);let{c0:i,c1:c}=du(t[2*s+0],t[2*s+1],r[2*s+0],r[2*s+1],o);t[2*s+0]=i,t[2*s+1]=c}return t}function xi(n){let e=n,t=new Uint16Array(be);for(let r=0;r<be;){let s=e();if(s.length%3)throw new Error("SampleNTT: unaligned block");for(let o=0;r<be&&o+3<=s.length;o+=3){let i=(s[o+0]>>0|s[o+1]<<8)&4095,c=(s[o+1]>>4|s[o+2]<<4)&4095;i<we&&(t[r++]=i),r<be&&c<we&&(t[r++]=c)}}return t}var uu=(n,e)=>{let t=new Uint16Array(be),r=Sr(n);kn(r);let s=0;for(let o=0,i=0,c=0,a=0;o<r.length;o++){let l=r[o];for(let d=0;d<32;d++)c+=l&1,l>>=1,s+=1,s===e?(a=c,c=0):s===2*e&&(t[i++]=Ae.mod(a-c),c=0,s=0)}if(kn(r),s)throw new Error(`sampleCBD: leftover bits: ${s}`);return t};function Or(n,e,t,r){return uu(n(r*be/4,e,t),r)}var pu=n=>{let e=n,{K:t,PRF:r,XOF:s,HASH512:o,ETA1:i,ETA2:c,du:a,dv:l}=e,d=Lr(1),u=Lr(l),f=Lr(a),p=Qt("publicKey",zs(Lr(12),t),32),m=zs(Lr(12),t),h=Qt("ciphertext",zs(f,t),u),g=Qt("seed",32,32),b=(w,y,E,_)=>{let S=[];for(let L=0;L<t;L++)S.push(Ae.NTT.encode(Or(r,_,L,i)));let x=new Uint16Array(be),T=[];for(let L=0;L<t;L++){let H=Or(r,_,t+L,c),V=new Uint16Array(be);for(let Q=0;Q<t;Q++){let Z=y(L,Q);Zt(V,Qs(Z,S[Q]))}Zt(H,Ae.NTT.decode(V)),T.push(H),Zt(x,Qs(w[L],S[L])),X(V)}let v=Or(r,_,2*t,c);Zt(v,Ae.NTT.decode(x));let C=d.decode(E);return Zt(C,v),X(w,S,x,v),h.encode([T,C])};return{secretCoder:m,lengths:{secretKey:m.bytesLen,publicKey:p.bytesLen,cipherText:h.bytesLen},keygen:w=>{Ve(w,32,"seed");let y=new Uint8Array(33);y.set(w),y[32]=t;let E=o(y),[_,S]=g.decode(E),x=[],T=[];for(let L=0;L<t;L++)x.push(Ae.NTT.encode(Or(r,S,L,i)));let v=s(_);for(let L=0;L<t;L++){let H=Ae.NTT.encode(Or(r,S,t+L,i));for(let V=0;V<t;V++){let Q=xi(v.get(V,L));Zt(H,Qs(Q,x[V]))}T.push(H)}v.clean();let C={publicKey:p.encode([T,_]),secretKey:m.encode(x)};return X(_,S,x,T,y,E),C},encrypt:(w,y,E)=>{let[_,S]=p.decode(w),x=s(S),T=b(_,(v,C)=>xi(x.get(v,C)),y,E);return x.clean(),T},prepare:w=>{let[y,E]=p.decode(w),_=s(E),S=[];for(let x=0;x<t;x++)for(let T=0;T<t;T++)S.push(xi(_.get(x,T)));return _.clean(),{encrypt:(x,T)=>b(y.map(v=>v.slice()),(v,C)=>S[v*t+C].slice(),x,T),clean:()=>X(y,S)}},decrypt:(w,y)=>{let[E,_]=h.decode(w),S=m.decode(y),x=new Uint16Array(be);for(let v=0;v<t;v++)Zt(x,Qs(S[v],Ae.NTT.encode(E[v])));lu(_,Ae.NTT.decode(x));let T=d.encode(_);return X(x,S,E,_),T}}};function fu(n){let e=n,t=pu(e),{HASH256:r,HASH512:s,KDF:o}=e,{secretCoder:i,lengths:c}=t,a=Qt("secretKey",c.secretKey,c.publicKey,32,32),l=32,d=64,u=(p,m)=>{let h=p.subarray(0,384*e.K),g=i.encode(i.decode(pt(h))),b=Xt(g,h);if(X(g),!b)throw new Error(`ML-KEM.${m}: wrong publicKey modulus`)},f=Object.freeze({...c,seed:64,msg:l,msgRand:l,secretKey:a.bytesLen});return Object.freeze({info:Object.freeze({type:"ml-kem"}),lengths:f,keygen:p=>{let m=p===void 0,h=m?ut(d):p,g,b;try{Ve(h,d,"seed");let w=t.keygen(h.subarray(0,32)),y=w.publicKey;g=w.secretKey,b=r(y);let E=a.encode([g,y,b,h.subarray(32)]);return{publicKey:y,secretKey:E}}finally{g!==void 0&&X(g),b!==void 0&&X(b),m&&X(h)}},getPublicKey:p=>{let[m,h,g,b]=a.decode(p);return Uint8Array.from(h)},encapsulate:(p,m)=>{let h=m===void 0,g=h?ut(l):m,b;try{return Ve(p,c.publicKey,"publicKey"),Ve(g,l,"message"),u(p,"encapsulate"),b=s.create().update(g).update(r(p)).digest(),{cipherText:t.encrypt(p,g,b.subarray(32,64)),sharedSecret:b.subarray(0,32)}}finally{b!==void 0&&X(b.subarray(32)),h&&X(g)}},decapsulate:(p,m)=>{Ve(m,a.bytesLen,"secretKey"),Ve(p,c.cipherText,"cipherText");let h=a.bytesLen-96,g=h+32,b=r(m.subarray(h/2,g));if(!Xt(b,m.subarray(g,g+32)))throw new Error("invalid secretKey: hash check failed");let[w,y,E,_]=a.decode(m),S=t.decrypt(p,w),x=s.create().update(S).update(E).digest(),T=x.subarray(0,32),v=t.encrypt(y,S,x.subarray(32,64)),C=Xt(p,v),L=o.create({dkLen:32}).update(_).update(p).digest();return X(S,v,x.subarray(32),C?L:T),C?T:L},prepare:p=>{Ve(p,c.publicKey,"publicKey"),u(p,"prepare");let m=pt(p),h=r(m),g=t.prepare(m);return Object.freeze({publicKey:m,encapsulate:b=>{let w=b===void 0,y=w?ut(l):b,E;try{return Ve(y,l,"message"),E=s.create().update(y).update(h).digest(),{cipherText:g.encrypt(y,E.subarray(32,64)),sharedSecret:E.subarray(0,32)}}finally{E!==void 0&&X(E.subarray(32)),w&&X(y)}},decapsulate:(b,w)=>{Ve(w,a.bytesLen,"secretKey"),Ve(b,c.cipherText,"cipherText");let[y,E,_,S]=a.decode(w);if(!Xt(E,m)||!Xt(_,h))throw new Error("ML-KEM.decapsulate: secretKey does not match prepared publicKey");let x=t.decrypt(b,y),T=s.create().update(x).update(h).digest(),v=T.subarray(0,32),C=g.encrypt(x,T.subarray(32,64)),L=Xt(b,C),H=o.create({dkLen:32}).update(S).update(b).digest();return X(x,C,T.subarray(32),L?H:v),L?v:H},clean:g.clean})}})}function mu(n,e,t){return Mn.create({dkLen:n}).update(e).update(new Uint8Array([t])).digest()}var hu={HASH256:Ys,HASH512:uc,KDF:Mn,XOF:hc,PRF:mu},gu=n=>fu({...hu,...n});var gc=gu(iu[768]);var yu=(n,e)=>{let t=Ti(n,e);return Ti(t.lengths,`${e}.lengths`),Ue(t.keygen,`${e}.keygen`),Ue(t.getPublicKey,`${e}.getPublicKey`),Ue(t.encapsulate,`${e}.encapsulate`),Ue(t.decapsulate,`${e}.decapsulate`),t};function Bn(n,e){let t=ue(n,e);if(t===0)throw new RangeError(`"${e}" expected integer greater than 0, got 0`);return t}function Nr(n,e){let t=Qt(e,...n.map(r=>{if(typeof r.lengths[e]!="number")throw new Error("wrong length: "+e);return Bn(r.lengths[e],e)}));return Bn(t.bytesLen,e),t}function wu(n,e,...t){let r=e,s=t,o=Nr(s,"seed"),i=Nr(s,"publicKey"),c=Bn(n===void 0?o.bytesLen:n,"realSeedLen");function a(d){z(d,c);let u=r(d,o.bytesLen),f=u.buffer===d.buffer?pt(u):u,p=[],m=[],h=[],g=[],b=!1;try{for(let w of o.decode(f))p.push(pt(w));for(let w=0;w<s.length;w++){let y=s[w].keygen(p[w]);m.push(y.secretKey),h.push(pt(y.secretKey)),g.push(y.publicKey)}return b=!0,{secretKey:h,publicKey:g}}finally{X(f,p,m),b||X(h)}}let l=d=>{let u=d===void 0?ut(c):pt(d),f;try{let{publicKey:p,secretKey:m}=a(u);try{f={secretKey:u,publicKey:i.encode(p)}}finally{X(p,m)}return f}finally{f||X(u)}};return{info:{lengths:{seed:c,publicKey:i.bytesLen,secretKey:c}},getPublicKey:d=>{let u=l(d);return X(u.secretKey),u.publicKey},keygen:l,expandDecapsulationKey:a,realSeedLen:c}}function bu(n,e,t,r,...s){if(n!==void 0&&Bn(n,"realSeedLen"),e!==void 0&&Bn(e,"realMsgLen"),typeof t!="function")throw new TypeError('"expandSeed" expected function, got type='+typeof t);if(typeof r!="function")throw new TypeError('"combiner" expected function, got type='+typeof r);let o=r,i=s;if(i.length===0)throw new RangeError("combineKEMS requires at least one KEM");for(let m=0;m<i.length;m++)yu(i[m],`kems[${m}]`);let c=wu(n,t,...i),a=Nr(i,"cipherText"),l=Nr(i,"publicKey"),d=Nr(i,"msg"),u=Bn(e===void 0?d.bytesLen:e,"realMsgLen"),f=Object.freeze({...c.info.lengths,msg:u,msgRand:d.bytesLen,cipherText:a.bytesLen}),p=(m,h,g)=>{let b=o(m,h,g);try{return pt(z(b,u,"sharedSecret"))}catch(w){if(Gt(b)){let y=_=>b.buffer===_.buffer&&b.byteOffset<_.byteOffset+_.byteLength&&_.byteOffset<b.byteOffset+b.byteLength;m.some(y)||h.some(y)||X(b)}throw w}};return Object.freeze({lengths:f,getPublicKey:c.getPublicKey,keygen:c.keygen,encapsulate(m,h=ut(d.bytesLen)){let g=l.decode(m),b=d.decode(h),w=[],y=[];try{for(let _=0;_<i.length;_++){let S=i[_].encapsulate(g[_],b[_]);w.push(S.sharedSecret),y.push(S.cipherText)}let E=a.encode(y);return{sharedSecret:p(g,y,w),cipherText:E}}finally{X(w,y)}},decapsulate(m,h){let g=a.decode(m),{publicKey:b,secretKey:w}=c.expandDecapsulationKey(h),y=[];try{for(let E=0;E<i.length;E++)y.push(i[E].decapsulate(g[E],w[E]));return p(b,g,y)}finally{X(w,y)}}})}function Eu(n,e,t,r){let s=n.Point.Fn;if(!s)throw new Error("no Point.Fn");function o(c){let a;for(let u=0,f=e;;u=f,f+=e){if(f>c.length)throw new Error("rejection sampling failed");if(a=s.fromBytes(c.subarray(u,f),!0),s.isValidNot0(a))break}let l=s.toBytes(s.create(a)),d=n.getPublicKey(l,!1);return{secretKey:l,publicKey:d}}let i=(c,a)=>n.getSharedSecret(a,c).subarray(1);return{lengths:{secretKey:e,publicKey:t,seed:r,msg:r,cipherText:t},keygen(c=ut(r)){return z(c,r,"seed"),o(c)},getPublicKey(c){return n.getPublicKey(c,!1)},encapsulate(c,a=ut(r)){z(a,r,"rand");let l;try{l=o(a).secretKey;let d=i(c,l),u=n.getPublicKey(l,!1);return{sharedSecret:d,cipherText:u}}finally{l&&X(l)}},decapsulate:i}}function _u(n,e,t,r){let{secretKey:s,publicKeyUncompressed:o}=t.lengths;if(!s||!o)throw new Error("wrong curve");let i=Eu(t,s,o,r),a=64+r;return bu(32,32,l=>(z(l,32),Mn(l,{dkLen:a})),(l,d,u)=>Ys(Ke(u[0],u[1],d[1],l[1],wa(n))),e,i)}var yc=_u("MLKEM768-P256",gc,rc,128);function Ir(n){let e=n instanceof Uint8Array?n:new Uint8Array(n);if(typeof Buffer<"u")return Buffer.from(e).toString("base64");let t="";for(let r=0;r<e.length;r++)t+=String.fromCharCode(e[r]);return btoa(t)}function wc(n){if(typeof Buffer<"u")return new Uint8Array(Buffer.from(n,"base64"));let e=atob(n),t=new Uint8Array(e.length);for(let r=0;r<e.length;r++)t[r]=e.charCodeAt(r);return t}async function bc(n,e){let t=crypto.subtle,r=await t.generateKey({name:"ECDH",namedCurve:"P-256"},!0,["deriveKey"]),s=await t.importKey("jwk",n,{name:"ECDH",namedCurve:"P-256"},!1,[]),o=await t.deriveKey({name:"ECDH",public:s,$public:s},r.privateKey,{name:"AES-GCM",length:256},!1,["encrypt"]),i=crypto.getRandomValues(new Uint8Array(12)),c=new TextEncoder().encode(JSON.stringify(e)),a=await t.encrypt({name:"AES-GCM",iv:i},o,c),d={ephem_pk:await t.exportKey("jwk",r.publicKey),iv:Ir(i),ciphertext:Ir(a)};return JSON.stringify(d)}function Ec(n){let e=yc.encapsulate(n);return{kemCtBase64:Ir(e.cipherText),sharedSecret:e.sharedSecret}}async function _c(n){let e=crypto.subtle,t=await e.importKey("raw",n,{name:"HKDF"},!1,["deriveKey"]);return await e.deriveKey({name:"HKDF",hash:"SHA-256",salt:new Uint8Array(0),info:new TextEncoder().encode("obex-pqc-dek-v2")},t,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"])}async function Sc(n,e){let t=crypto.getRandomValues(new Uint8Array(12)),r=new TextEncoder().encode(JSON.stringify(e)),s=await crypto.subtle.encrypt({name:"AES-GCM",iv:t},n,r),o={iv:Ir(t),ciphertext:Ir(s)};return JSON.stringify(o)}var Su=3600*1e3,qs=new Map,Zs=new Map;function Rc(n){return qs.get(n)||null}async function Tc(n,e,t){let r=Date.now(),s=qs.get(e);if(s&&s.expiresAt>r)return s;let o=Zs.get(e);if(o)return await o;let i=(async()=>{try{return await Ru(n,e,t)}finally{Zs.delete(e)}})();return Zs.set(e,i),await i}async function Ru(n,e,t){let r=Date.now(),s=Math.floor(r/1e3),o=s+3600,i=wc(t),{kemCtBase64:c,sharedSecret:a}=Ec(i),l=await _c(a),d=`kem_${_r()}`;try{await n.prepare("INSERT INTO kem_keys (id, profile_id, kem_ct, created_at, expires_at) VALUES (?, ?, ?, ?, ?)").bind(d,e,c,s,o).run()}catch(f){console.error(`[DekManager] Failed to persist kem_key ${d} to D1:`,f)}let u={kemKeyId:d,dek:l,profileId:e,createdAt:r,expiresAt:r+Su};return qs.set(e,u),u}function xc(n){qs.delete(n),Zs.delete(n)}var vi=new Map;async function Tu(n,e){let t=Date.now(),r=vi.get(e);if(r&&r.expiresAt>t)return r.key;try{let s=null;try{s=await n.prepare("SELECT public_key FROM user_log_keys WHERE profile_id = ? AND (is_active IS NULL OR is_active = 1)").bind(e).first()}catch(c){if(String(c?.message||c).includes("no such column: is_active"))s=await n.prepare("SELECT public_key FROM user_log_keys WHERE profile_id = ?").bind(e).first();else throw c}let o=s?.public_key?JSON.parse(s.public_key):null,i=o?300*1e3:15*1e3;return vi.set(e,{key:o,expiresAt:t+i}),o}catch(s){return console.error(`[E2EE] Failed to fetch log public key for profile ${e}:`,s),null}}function en(n){vi.delete(n),xc(n)}var qt=[],Ac=50,vc=15e3,Ai=3600,eo=0,Ur=!1,Pc=Date.now();async function xu(n){let e=Date.now();if(eo>e)return!0;if(n)try{let t=await P.get(n,"d1:write_quota_tripped");if(t&&t>Math.floor(e/1e3))return eo=t*1e3,!0}catch{}return!1}async function Au(n){let t=Math.floor(Date.now()/1e3)+Ai;if(eo=t*1e3,qt.length=0,Ur=!1,console.warn(`[LogBatcher] D1 write quota limit reached! Silencing log writes for ${Ai}s.`),n)try{await P.set(n,"d1:write_quota_tripped",t,Ai)}catch{}}async function to(n){if(Ur=!1,Pc=Date.now(),qt.length===0)return;let e=caches.default;if(await xu(e)){qt.length=0;return}let t=qt.splice(0,Ac);if(t.length===0)return;let r=new Ie(n.DB),s=[],o=Array.from(new Set(t.map(a=>a.profile_id))),i=new Map,c=new Map;await Promise.all(o.map(async a=>{let l=await Tu(n.DB,a);if(l&&(i.set(a,l),"pqc_pk"in l)){let d=Rc(a);d||(d=await Tc(n.DB,a,l.pqc_pk)),d&&c.set(a,d)}}));for(let a of t){let l=i.get(a.profile_id);if(l)try{let d={domain:a.domain,client_ip:a.client_ip,geo_country:a.geo_country,answer:a.answer,dest_geoip:a.dest_geoip,dest_country_code:a.dest_country_code,dest_country:a.dest_country,dest_isp:a.dest_isp,ecs:a.ecs,upstream:a.upstream,reason:a.reason};if("pqc_pk"in l){let u=c.get(a.profile_id);if(u){let f=await Sc(u.dek,d);a.encrypt_version=2,a.kem_key_id=u.kemKeyId,a.encrypted_payload=f}}else if("kty"in l){let u=await bc(l,d);a.encrypt_version=1,a.kem_key_id=null,a.encrypted_payload=u}a.encrypt_version&&a.encrypt_version>0&&(a.domain="",a.client_ip="",a.geo_country="",a.answer=void 0,a.dest_geoip=void 0,a.dest_country_code=null,a.dest_country=null,a.dest_isp=null,a.ecs=void 0,a.upstream=void 0,a.reason=void 0)}catch(d){console.error(`[LogBatcher] Encryption failed for profile ${a.profile_id}:`,d)}else a.encrypt_version=0,a.kem_key_id=null;s.push(r.createInsertStatement(a))}try{await n.DB.batch(s)}catch(a){let l=String(a?.message||a);l.includes("exceeded D1's free tier daily row write limit")||l.includes("row write limit")||l.includes("daily write limit")?await Au(e):console.warn(`[LogBatcher] Batch write failed (${s.length} stmts):`,l)}qt.length>0&&Cc(n)}function Cc(n){Ur||(Ur=!0,new Promise(e=>setTimeout(e,vc)).then(()=>to(n)).catch(e=>{Ur=!1,console.error("[LogBatcher] Deferred flush error:",e)}))}function Mr(n,e,t,r){if(e&&Number(e.log_retention_days)===0)return;let s=(n.action||"PASS").toUpperCase();if(e?.skip_log_on_pass&&s==="PASS"||eo>Date.now())return;n.id||(n.id=_r()),qt.push(n);let o=Date.now();qt.length>=Ac||o-Pc>=vc?r.waitUntil(to(t)):Cc(t)}async function Dc(n,e,t,r,s,o,i,c,a){let l=n.headers.get("CF-Connecting-IP")||"127.0.0.1",d,u=i||"";if(s==="REDIRECT"&&i)if(c==="CNAME"&&(e.type==="A"||e.type==="AAAA")&&a)try{let p=Ht(i,e.type),m={name:i,type:e.type,raw:p},h=await a(n,m,t,r,"PASS");if(h.answer&&h.answer.length>0){let g=ke(h.answer),b=[{type:"CNAME",value:i,ttl:60}];for(let w of g)(w.type===e.type||w.type==="CNAME")&&b.push({name:w.name,type:w.type,value:w.data,ttl:w.ttl});d=Fo(e.raw,b,0)}else d=Ee(e.raw,c,i)}catch(p){console.error("CNAME resolution failed:",p),d=Ee(e.raw,c,i)}else d=Ee(e.raw,c||e.type,i);else{let p=r.block_mode||"NULL_IP";if(p==="NXDOMAIN")d=Ee(e.raw,e.type,"",3600,3),u="NXDOMAIN";else if(p==="NODATA")d=Ee(e.raw,e.type,"",3600,0),u="NODATA";else if(p==="CUSTOM_IP"){let m=e.type==="AAAA"?r.custom_block_ipv6||"::":r.custom_block_ipv4||"0.0.0.0";d=Ee(e.raw,e.type,m),u=m}else{let m=e.type==="AAAA"?"::":"0.0.0.0";d=Ee(e.raw,e.type,m),u=m}}let f=Date.now()-t.startTime;return t.ctx.waitUntil((async()=>{try{let p=await Vt(n,l);Mr({profile_id:t.profileId,access_point_id:t.accessPointId,timestamp:Math.floor(Date.now()/1e3),client_ip:l,geo_country:p,domain:e.name,record_type:e.type,action:s,reason:o,answer:u,latency:f},r,t.env,t.ctx)}catch{}})()),{answer:d,ttl:3600,action:s,reason:o,latency:f}}function kc(n,e,t,r,s,o,i,c,a,l,d){let u=n.headers.get("CF-Connecting-IP")||"127.0.0.1";t.ctx.waitUntil((async()=>{try{let f=Vt(n,u),p=i.find(E=>E.type==="A"||E.type==="AAAA")?.data,m="",h=null,g=null,b=null;if(p){let E=await Er(p);E&&(m=JSON.stringify(E),h=E.country_code?E.country_code.toUpperCase():null,g=E.country||null,b=E.isp||null)}let w=await f,y=Date.now()-t.startTime;Mr({profile_id:t.profileId,access_point_id:t.accessPointId,timestamp:Math.floor(Date.now()/1e3),client_ip:u,geo_country:w,domain:e.name,record_type:e.type,action:s,reason:o,answer:i.map(E=>E.data).join(", "),dest_geoip:m,dest_country_code:h,dest_country:g,dest_isp:b,upstream:l,latency:y,ecs:d},r,t.env,t.ctx),c.length>0&&bn.set(`${t.profileId}:${e.name}:${e.type}`,{answer:c,ttl:a,action:s,reason:o,expiresAt:Date.now()+a*1e3})}catch{}})())}function Lc(n,e,t,r,s,o,i,c,a){let l=0,d,u=o instanceof Error?o.message:String(o),f,p;if(o instanceof vn)l=o.status,d=o.statusText||void 0,f=o.responseBodySnippet||void 0,p=o.cfRay;else if(o&&typeof o=="object"&&"cause"in o&&o.cause){let w=o.cause,y=typeof w=="object"&&w&&"message"in w?String(w.message):String(w);u+=` (Cause: ${y})`}let m=l>0?`Upstream HTTP ${l}${d?` ${d}`:""}`:`Upstream Error: ${u}`,h=n.headers.get("CF-Connecting-IP")||"127.0.0.1";t.ctx.waitUntil((async()=>{try{let w=await Vt(n,h);Mr({profile_id:t.profileId,access_point_id:t.accessPointId,timestamp:Math.floor(Date.now()/1e3),client_ip:h,geo_country:w,domain:e.name,record_type:e.type,action:"FAIL",reason:m,answer:"",dest_geoip:"",dest_country_code:null,dest_country:null,dest_isp:null,upstream:s,latency:Date.now()-t.startTime,ecs:i},r,t.env,t.ctx)}catch{}})());let g=c||s,b=a||"POST";return{answer:new Uint8Array,ttl:0,action:"FAIL",reason:m,latency:Date.now()-t.startTime,diagnostics:{upstream_url:s.startsWith("sdns://")?`${s} (${g})`:g,method:b,status:l,status_text:d,error_detail:u,response_body:f,cf_ray:p}}}var tt={async resolve(n,e,t,r,s,o){let i=r.upstream[0]||"https://security.cloudflare-dns.com/dns-query";if(!at(i))return{answer:new Uint8Array,ttl:0,action:"FAIL",reason:"Unsafe upstream URL",diagnostics:{upstream_url:i,method:"BLOCKED",status:0},latency:Date.now()-t.startTime};let{queryRaw:c,ecs:a}=aa(n,e,r),l;try{l=Tt(i);let d=await xt(l,c),u=ke(d.answer),f=await ca(e,u,d.answer,t,r,n,tt.resolve,o),p=f.answer,m=f.parsedAnswers,h=f.effectiveReason,g=m.length>0?Math.max(10,Math.min(...m.map(b=>b.ttl))):60;return kc(n,e,t,r,s,h,m,p,g,i,a),{answer:p,ttl:g,action:s,reason:h,latency:Date.now()-t.startTime,timings:{upstream_fetch:d.latency},diagnostics:{upstream_url:i.startsWith("sdns://")?`${i} (${d.diagTarget})`:d.diagTarget,method:d.diagMethod,status:200,status_text:"OK"}}}catch(d){return Lc(n,e,t,r,i,d,a,l?.diagTarget,l?.diagMethod)}},async block(n,e,t,r,s,o,i,c){return Dc(n,e,t,r,s,o,i,c,tt.resolve)}};var Fn=class{static isMatch(e,t){let r=e.toLowerCase(),s=t.toLowerCase();return r===s||r.endsWith(`.${s}`)}static findMatch(e,t){for(let r of t)if(this.isMatch(e,r.pattern))return r;return null}};var Oc={async match(n,e,t,r,s,o,i){let c=e.name.toLowerCase(),a=s.filter(p=>p.type==="ALLOW");if(Fn.findMatch(e.name,a))return i("local_rules"),tt.resolve(n,e,t,r,"PASS","Whitelist");let l=s.filter(p=>p.type==="REDIRECT"),d=Fn.findMatch(e.name,l);if(d){let p,m=e.type;if(e.type==="A"?(p=d.v_a,!p&&d.v_cname&&(p=d.v_cname,m="CNAME")):e.type==="AAAA"?(p=d.v_aaaa,!p&&d.v_cname&&(p=d.v_cname,m="CNAME")):e.type==="TXT"?p=d.v_txt:e.type==="CNAME"&&(p=d.v_cname),p)return i("local_rules"),await tt.block(n,e,t,r,"REDIRECT",`Rule: ${d.pattern}`,p,m)}let u=s.filter(p=>p.type==="BLOCK"),f=Fn.findMatch(e.name,u);if(f)return i("local_rules"),tt.block(n,e,t,r,"BLOCK",`Blacklist: ${f.pattern}`);if(i("local_rules"),o){let p=c;for(;p;){if(o.test(p))return i("bloom_check"),tt.block(n,e,t,r,"BLOCK",`External List: ${p}`);let m=p.indexOf(".");if(m===-1)break;p=p.substring(m+1)}i("bloom_check")}return null}};var de={clearCache:ds.clear,async process(n,e,t){let r={},s=t.startTime,o=d=>{let u=Date.now();r[d]=(r[d]||0)+(u-s),s=u};if(e.name.toLowerCase()==="obex"&&e.type==="TXT")return{answer:Ee(e.raw,"TXT",t.profileId||"obex"),ttl:60,action:"PASS",reason:"Internal Verification",latency:Date.now()-t.startTime,timings:{total:Date.now()-t.startTime}};let i=bn.get(`${t.profileId}:${e.name}:${e.type}`);if(i&&Date.now()<i.expiresAt&&i.answer instanceof Uint8Array){let d=new Uint8Array(i.answer);d.length>=2&&e.raw.length>=2&&(d[0]=e.raw[0],d[1]=e.raw[1]);let u=Date.now()-t.startTime;return{answer:d,ttl:Math.ceil((i.expiresAt-Date.now())/1e3),action:i.action,reason:i.reason,latency:u,timings:{dns_cache_mem:u}}}let c=await na.load(t,o);if(!c)return{answer:new Uint8Array,ttl:0,action:"FAIL",reason:"Profile Not Found"};let a=await Oc.match(n,e,t,c.settings,c.rules,c.bloom,o);if(a)return{...a,timings:{...r,...a.timings}};if(c.settings.default_policy==="BLOCK"){let d=await tt.block(n,e,t,c.settings,"BLOCK","Default Policy");return{...d,timings:{...r,...d.timings}}}let l=await tt.resolve(n,e,t,c.settings,"PASS");return{...l,timings:{...r,...l.timings}}}};function vu(n){if(!n||typeof n!="object")return null;let e=0;for(let t of Object.keys(n)){let r=t.match(/^KEK_[vV](\d+)$/);if(r){let s=n[t];if(s!=null&&s!==""){let o=parseInt(r[1],10);!isNaN(o)&&o>e&&(e=o)}}}return e>0?`v${e}`:null}function no(n,e){if(!e)return null;let t=e[`KEK_${n}`]||e[`KEK_${n.toUpperCase()}`];return t&&typeof t=="string"&&t.trim()!==""?t:(n==="v0"||n==="default")&&e.JWT_SECRET&&typeof e.JWT_SECRET=="string"&&e.JWT_SECRET.trim()!==""?e.JWT_SECRET:null}function Hn(n){let e="",t=n.byteLength;for(let r=0;r<t;r++)e+=String.fromCharCode(n[r]);return btoa(e)}function $n(n){let e=atob(n),t=e.length,r=new Uint8Array(t);for(let s=0;s<t;s++)r[s]=e.charCodeAt(s);return r}async function ro(n){let t=new TextEncoder().encode(n.trim()),r=await crypto.subtle.digest("SHA-256",t);return await crypto.subtle.importKey("raw",r,{name:"AES-GCM"},!1,["encrypt","decrypt"])}async function Nc(n){return await crypto.subtle.importKey("raw",n,{name:"AES-GCM"},!1,["encrypt","decrypt"])}async function kt(n,e){let t=vu(e);if(!t)return null;let r=no(t,e);if(!r||typeof r!="string"||r.trim()==="")throw new Error(`KEK version ${t} is missing or invalid in environment variables`);let s=await ro(r),o=new Uint8Array(32);crypto.getRandomValues(o);let i=await Nc(o),c=new Uint8Array(12);crypto.getRandomValues(c);let l=new TextEncoder().encode(n),d=await crypto.subtle.encrypt({name:"AES-GCM",iv:c},i,l),u={ciphertext:Hn(new Uint8Array(d)),iv:Hn(c)},f=new Uint8Array(12);crypto.getRandomValues(f);let p=await crypto.subtle.encrypt({name:"AES-GCM",iv:f},s,o),m={ciphertext:Hn(new Uint8Array(p)),iv:Hn(f),kek_version:t};return{dataEncrypted:JSON.stringify(u),dekEncrypted:JSON.stringify(m)}}async function Pi(n,e,t){let r,s;try{r=JSON.parse(n),s=JSON.parse(e)}catch(i){throw new Error(`Failed to parse envelope payload: ${i instanceof Error?i.message:String(i)}`)}let o=async i=>{let c=no(i,t);if(!c||typeof c!="string"||c.trim()==="")throw new Error(`Required KEK version ${i} is missing or invalid in environment variables`);let a=await ro(c),l=$n(s.ciphertext),d=$n(s.iv),u=await crypto.subtle.decrypt({name:"AES-GCM",iv:d},a,l),f=new Uint8Array(u),p=await Nc(f),m=$n(r.ciphertext),h=$n(r.iv),g=await crypto.subtle.decrypt({name:"AES-GCM",iv:h},p,m);return new TextDecoder().decode(g)};try{return await o(s.kek_version)}catch(i){if(s.kek_version!=="v0"&&t?.JWT_SECRET&&typeof t.JWT_SECRET=="string"&&t.JWT_SECRET.trim()!=="")try{return await o("v0")}catch{throw i}throw i}}async function Ci(n,e){if(!e)return null;let t;try{t=JSON.parse(n)}catch{return null}let r=t.kek_version,s=parseInt(r.replace(/^v/,""),10);if(isNaN(s))return null;let i=`v${s+1}`,c=no(i,e);if(!c||typeof c!="string"||c.trim()==="")return null;let a=no(r,e);if(!a||typeof a!="string"||a.trim()==="")throw new Error(`Current KEK version ${r} required for rotation is missing or invalid in environment`);let l=await ro(a),d=$n(t.ciphertext),u=$n(t.iv),f=await crypto.subtle.decrypt({name:"AES-GCM",iv:u},l,d),p=new Uint8Array(f),m=await ro(c),h=new Uint8Array(12);crypto.getRandomValues(h);let g=await crypto.subtle.encrypt({name:"AES-GCM",iv:h},m,p),b={ciphertext:Hn(new Uint8Array(g)),iv:Hn(h),kek_version:i};return JSON.stringify(b)}var so=class{constructor(e,t){this.db=e;this.env=t}db;env;async processUserSecrets(e){if(!e)return null;let t={},r=!1,s=e.totp_secret;if(e.totp_secret_encrypted&&e.totp_secret_dek)try{s=await Pi(e.totp_secret_encrypted,e.totp_secret_dek,this.env);let i=await Ci(e.totp_secret_dek,this.env);i&&(t.totp_secret_dek=i,r=!0)}catch(i){let c=i instanceof Error?i.stack||i.message:String(i);console.error(`[Envelope Encryption] Failed to decrypt/rotate totp_secret for user ${e.id}:`,c)}else if(e.totp_secret)try{let i=await kt(e.totp_secret,this.env);i&&(t.totp_secret_encrypted=i.dataEncrypted,t.totp_secret_dek=i.dekEncrypted,t.totp_secret=null,r=!0)}catch(i){console.error(`[Envelope Encryption] Migration failed for totp_secret of user ${e.id}:`,i)}let o=e.totp_recovery_keys;if(e.totp_recovery_keys_encrypted&&e.totp_recovery_keys_dek)try{o=await Pi(e.totp_recovery_keys_encrypted,e.totp_recovery_keys_dek,this.env);let i=await Ci(e.totp_recovery_keys_dek,this.env);i&&(t.totp_recovery_keys_dek=i,r=!0)}catch(i){let c=i instanceof Error?i.stack||i.message:String(i);console.error(`[Envelope Encryption] Failed to decrypt/rotate totp_recovery_keys for user ${e.id}:`,c)}else if(e.totp_recovery_keys)try{let i=await kt(e.totp_recovery_keys,this.env);i&&(t.totp_recovery_keys_encrypted=i.dataEncrypted,t.totp_recovery_keys_dek=i.dekEncrypted,t.totp_recovery_keys=null,r=!0)}catch(i){console.error(`[Envelope Encryption] Migration failed for totp_recovery_keys of user ${e.id}:`,i)}if(r)try{let i=[],c=[];for(let[a,l]of Object.entries(t))i.push(`${a} = ?`),c.push(l);c.push(e.id),await this.db.prepare(`UPDATE users SET ${i.join(", ")} WHERE id = ?`).bind(...c).run(),Object.assign(e,t)}catch(i){console.error(`[Envelope Encryption] Failed to save rotated/migrated secrets for user ${e.id}:`,i)}return{...e,totp_secret:s,totp_recovery_keys:o}}};var oo=class{constructor(e,t){this.db=e;this.secretProcessor=t}db;secretProcessor;async getById(e){let t=await this.db.prepare("SELECT * FROM users WHERE id = ?").bind(e).first();return await this.secretProcessor.processUserSecrets(t)}async getByUsername(e){try{let t=await this.db.prepare("SELECT * FROM users WHERE username = ?").bind(e).first();return await this.secretProcessor.processUserSecrets(t)}catch(t){if((t instanceof Error?t.message:String(t)).includes("no such table"))return null;throw t}}async listAll(){let{results:e}=await this.db.prepare(`
294
294
  SELECT
295
295
  u.id,
296
296
  u.username,
@@ -303,7 +303,7 @@ SQL: ${this.sql}`),n}}},xo=class{constructor(e){this.rawDb=e}rawDb;prepare(e){re
303
303
  u.last_active_at as last_resolve_at
304
304
  FROM users u
305
305
  ORDER BY u.created_at DESC
306
- `).all();return e}async create(e){let n=Math.floor(Date.now()/1e3);return(await this.db.prepare("INSERT INTO users (id, username, hashed_password, role, created_at, timezone, locale, password_version) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").bind(e.id,e.username,e.passwordHash,e.role,n,e.timezone||null,e.locale||"en-US",e.passwordVersion??2).run()).success}async updateUsername(e,n){return(await this.db.prepare("UPDATE users SET username = ? WHERE id = ?").bind(n,e).run()).success}async updateTimezone(e,n){return(await this.db.prepare("UPDATE users SET timezone = ? WHERE id = ?").bind(n,e).run()).success}async updateLocale(e,n){return(await this.db.prepare("UPDATE users SET locale = ? WHERE id = ?").bind(n||"en-US",e).run()).success}async delete(e){return(await this.db.prepare("DELETE FROM users WHERE id = ?").bind(e).run()).success}async isEmpty(){try{return(await this.db.prepare("SELECT COUNT(*) as count FROM users").first("count")??0)===0}catch(e){return console.error("[UserModel] isEmpty: query failed, failing closed (assuming users exist):",e),!1}}};var eo=class{constructor(e){this.db=e}db;async updatePassword(e,n,r=2){return(await this.db.prepare("UPDATE users SET hashed_password = ?, password_version = ? WHERE id = ?").bind(n,r,e).run()).success}async updatePinHash(e,n){return(await this.db.prepare("UPDATE users SET pin_hash = ? WHERE id = ?").bind(n,e).run()).success}async updateSessionLockTimeout(e,n){return(await this.db.prepare("UPDATE users SET session_lock_timeout = ? WHERE id = ?").bind(n,e).run()).success}};var to=class{constructor(e,n){this.db=e;this.env=n}db;env;async updateTOTP(e,n,r){let s=JSON.stringify(r),o=await Pt(n,this.env),i=await Pt(s,this.env);return o&&i?(await this.db.prepare("UPDATE users SET totp_secret = NULL, totp_secret_encrypted = ?, totp_secret_dek = ?, totp_enabled = 1, totp_skip_password = 0, totp_recovery_keys = NULL, totp_recovery_keys_encrypted = ?, totp_recovery_keys_dek = ? WHERE id = ?").bind(o.dataEncrypted,o.dekEncrypted,i.dataEncrypted,i.dekEncrypted,e).run()).success:(await this.db.prepare("UPDATE users SET totp_secret = ?, totp_secret_encrypted = NULL, totp_secret_dek = NULL, totp_enabled = 1, totp_skip_password = 0, totp_recovery_keys = ?, totp_recovery_keys_encrypted = NULL, totp_recovery_keys_dek = NULL WHERE id = ?").bind(n,s,e).run()).success}async removeTOTP(e,n=!1){return n?(await this.db.prepare("UPDATE users SET totp_secret = NULL, totp_secret_encrypted = NULL, totp_secret_dek = NULL, totp_enabled = 0 WHERE id = ?").bind(e).run()).success:(await this.db.prepare("UPDATE users SET totp_secret = NULL, totp_secret_encrypted = NULL, totp_secret_dek = NULL, totp_enabled = 0, totp_skip_password = 0, totp_recovery_keys = NULL, totp_recovery_keys_encrypted = NULL, totp_recovery_keys_dek = NULL WHERE id = ?").bind(e).run()).success}async updateRecoveryKeys(e,n){let r=JSON.stringify(n),s=await Pt(r,this.env);return s?(await this.db.prepare("UPDATE users SET totp_recovery_keys = NULL, totp_recovery_keys_encrypted = ?, totp_recovery_keys_dek = ? WHERE id = ?").bind(s.dataEncrypted,s.dekEncrypted,e).run()).success:(await this.db.prepare("UPDATE users SET totp_recovery_keys = ?, totp_recovery_keys_encrypted = NULL, totp_recovery_keys_dek = NULL WHERE id = ?").bind(r,e).run()).success}async updateTOTPSettings(e,n){return(await this.db.prepare("UPDATE users SET totp_skip_password = ? WHERE id = ?").bind(n?1:0,e).run()).success}async consumeRecoveryKey(e,n,r){let s=r.filter((c,a)=>a!==n),o=JSON.stringify(s),i=await Pt(o,this.env);return i?(await this.db.prepare("UPDATE users SET totp_recovery_keys = NULL, totp_recovery_keys_encrypted = ?, totp_recovery_keys_dek = ? WHERE id = ?").bind(i.dataEncrypted,i.dekEncrypted,e).run()).success:(await this.db.prepare("UPDATE users SET totp_recovery_keys = ?, totp_recovery_keys_encrypted = NULL, totp_recovery_keys_dek = NULL WHERE id = ?").bind(o,e).run()).success}};var no=class{constructor(e){this.db=e}db;async updateLastActiveByProfile(e,n){return(await this.db.prepare("UPDATE users SET last_active_at = ? WHERE id = (SELECT owner_id FROM profiles WHERE id = ?)").bind(n,e).run()).success}async applyInactivityPolicy(e){let n=e-2592e3,r=e-2160*3600,s=this.db.prepare(`
306
+ `).all();return e}async create(e){let t=Math.floor(Date.now()/1e3);return(await this.db.prepare("INSERT INTO users (id, username, hashed_password, role, created_at, timezone, locale, password_version) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").bind(e.id,e.username,e.passwordHash,e.role,t,e.timezone||null,e.locale||"en-US",e.passwordVersion??2).run()).success}async updateUsername(e,t){return(await this.db.prepare("UPDATE users SET username = ? WHERE id = ?").bind(t,e).run()).success}async updateTimezone(e,t){return(await this.db.prepare("UPDATE users SET timezone = ? WHERE id = ?").bind(t,e).run()).success}async updateLocale(e,t){return(await this.db.prepare("UPDATE users SET locale = ? WHERE id = ?").bind(t||"en-US",e).run()).success}async delete(e){return(await this.db.prepare("DELETE FROM users WHERE id = ?").bind(e).run()).success}async isEmpty(){try{return(await this.db.prepare("SELECT COUNT(*) as count FROM users").first("count")??0)===0}catch(e){return console.error("[UserModel] isEmpty: query failed, failing closed (assuming users exist):",e),!1}}};var io=class{constructor(e){this.db=e}db;async updatePassword(e,t,r=2){return(await this.db.prepare("UPDATE users SET hashed_password = ?, password_version = ? WHERE id = ?").bind(t,r,e).run()).success}async updatePinHash(e,t){return(await this.db.prepare("UPDATE users SET pin_hash = ? WHERE id = ?").bind(t,e).run()).success}async updateSessionLockTimeout(e,t){return(await this.db.prepare("UPDATE users SET session_lock_timeout = ? WHERE id = ?").bind(t,e).run()).success}};var ao=class{constructor(e,t){this.db=e;this.env=t}db;env;async updateTOTP(e,t,r){let s=JSON.stringify(r),o=await kt(t,this.env),i=await kt(s,this.env);return o&&i?(await this.db.prepare("UPDATE users SET totp_secret = NULL, totp_secret_encrypted = ?, totp_secret_dek = ?, totp_enabled = 1, totp_skip_password = 0, totp_recovery_keys = NULL, totp_recovery_keys_encrypted = ?, totp_recovery_keys_dek = ? WHERE id = ?").bind(o.dataEncrypted,o.dekEncrypted,i.dataEncrypted,i.dekEncrypted,e).run()).success:(await this.db.prepare("UPDATE users SET totp_secret = ?, totp_secret_encrypted = NULL, totp_secret_dek = NULL, totp_enabled = 1, totp_skip_password = 0, totp_recovery_keys = ?, totp_recovery_keys_encrypted = NULL, totp_recovery_keys_dek = NULL WHERE id = ?").bind(t,s,e).run()).success}async removeTOTP(e,t=!1){return t?(await this.db.prepare("UPDATE users SET totp_secret = NULL, totp_secret_encrypted = NULL, totp_secret_dek = NULL, totp_enabled = 0 WHERE id = ?").bind(e).run()).success:(await this.db.prepare("UPDATE users SET totp_secret = NULL, totp_secret_encrypted = NULL, totp_secret_dek = NULL, totp_enabled = 0, totp_skip_password = 0, totp_recovery_keys = NULL, totp_recovery_keys_encrypted = NULL, totp_recovery_keys_dek = NULL WHERE id = ?").bind(e).run()).success}async updateRecoveryKeys(e,t){let r=JSON.stringify(t),s=await kt(r,this.env);return s?(await this.db.prepare("UPDATE users SET totp_recovery_keys = NULL, totp_recovery_keys_encrypted = ?, totp_recovery_keys_dek = ? WHERE id = ?").bind(s.dataEncrypted,s.dekEncrypted,e).run()).success:(await this.db.prepare("UPDATE users SET totp_recovery_keys = ?, totp_recovery_keys_encrypted = NULL, totp_recovery_keys_dek = NULL WHERE id = ?").bind(r,e).run()).success}async updateTOTPSettings(e,t){return(await this.db.prepare("UPDATE users SET totp_skip_password = ? WHERE id = ?").bind(t?1:0,e).run()).success}async consumeRecoveryKey(e,t,r){let s=r.filter((c,a)=>a!==t),o=JSON.stringify(s),i=await kt(o,this.env);return i?(await this.db.prepare("UPDATE users SET totp_recovery_keys = NULL, totp_recovery_keys_encrypted = ?, totp_recovery_keys_dek = ? WHERE id = ?").bind(i.dataEncrypted,i.dekEncrypted,e).run()).success:(await this.db.prepare("UPDATE users SET totp_recovery_keys = ?, totp_recovery_keys_encrypted = NULL, totp_recovery_keys_dek = NULL WHERE id = ?").bind(o,e).run()).success}};var co=class{constructor(e){this.db=e}db;async updateLastActiveByProfile(e,t){return(await this.db.prepare("UPDATE users SET last_active_at = ? WHERE id = (SELECT owner_id FROM profiles WHERE id = ?)").bind(t,e).run()).success}async applyInactivityPolicy(e){let t=e-2592e3,r=e-2160*3600,s=this.db.prepare(`
307
307
  DELETE FROM logs
308
308
  WHERE profile_id IN (
309
309
  SELECT id FROM profiles
@@ -313,14 +313,14 @@ SQL: ${this.sql}`),n}}},xo=class{constructor(e){this.rawDb=e}rawDb;prepare(e){re
313
313
  AND (last_active_at < ? OR (last_active_at IS NULL AND created_at < ?))
314
314
  )
315
315
  )
316
- `).bind(n,n),o=this.db.prepare(`
316
+ `).bind(t,t),o=this.db.prepare(`
317
317
  DELETE FROM profiles
318
318
  WHERE owner_id IN (
319
319
  SELECT id FROM users
320
320
  WHERE role = 'user'
321
321
  AND (last_active_at < ? OR (last_active_at IS NULL AND created_at < ?))
322
322
  )
323
- `).bind(n,n),i=this.db.prepare(`
323
+ `).bind(t,t),i=this.db.prepare(`
324
324
  DELETE FROM users
325
325
  WHERE role = 'user'
326
326
  AND (
@@ -328,31 +328,31 @@ SQL: ${this.sql}`),n}}},xo=class{constructor(e){this.rawDb=e}rawDb;prepare(e){re
328
328
  FROM user_activity_log
329
329
  WHERE user_id = users.id
330
330
  ) < ?
331
- `).bind(r),c=await this.db.batch([s,o,i]);return{clearedProfiles:c[1].meta.changes||0,deletedUsers:c[2].meta.changes||0}}};var Y=class{secrets;core;security;mfa;lifecycle;constructor(e,n){this.secrets=new Zs(e,n),this.core=new qs(e,this.secrets),this.security=new eo(e),this.mfa=new to(e,n),this.lifecycle=new no(e)}async getById(e){return this.core.getById(e)}async getByUsername(e){return this.core.getByUsername(e)}async listAll(){return this.core.listAll()}async create(e){return this.core.create(e)}async updateUsername(e,n){return this.core.updateUsername(e,n)}async updateTimezone(e,n){return this.core.updateTimezone(e,n)}async updateLocale(e,n){return this.core.updateLocale(e,n)}async delete(e){return this.core.delete(e)}async isEmpty(){return this.core.isEmpty()}async updatePassword(e,n,r=2){return this.security.updatePassword(e,n,r)}async updatePinHash(e,n){return this.security.updatePinHash(e,n)}async updateSessionLockTimeout(e,n){return this.security.updateSessionLockTimeout(e,n)}async updateTOTP(e,n,r){return this.mfa.updateTOTP(e,n,r)}async removeTOTP(e,n=!1){return this.mfa.removeTOTP(e,n)}async updateRecoveryKeys(e,n){return this.mfa.updateRecoveryKeys(e,n)}async updateTOTPSettings(e,n){return this.mfa.updateTOTPSettings(e,n)}async consumeRecoveryKey(e,n,r){return this.mfa.consumeRecoveryKey(e,n,r)}async updateLastActiveByProfile(e,n){return this.lifecycle.updateLastActiveByProfile(e,n)}async applyInactivityPolicy(e){return this.lifecycle.applyInactivityPolicy(e)}};ge();async function bu(t){try{if(t.method==="GET"){let n=new URL(t.url).searchParams.get("dns");if(!n)return null;let r=n.replace(/-/g,"+").replace(/_/g,"/");for(;r.length%4;)r+="=";let s=atob(r),o=new Uint8Array(s.length);for(let i=0;i<s.length;i++)o[i]=s.charCodeAt(i);return o}else if(t.method==="POST"){let e=await t.clone().arrayBuffer();return new Uint8Array(e)}}catch{return null}return null}async function Un(t,e,n){let r=caches.default,s=Date.now(),o=rr.get(t);if(o&&s-o.ts<3e5)return o.data;let i=`doh_key_v1:${t}`;try{let c=await P.get(r,i);if(c)return rr.set(t,{data:c,ts:s}),c}catch{}try{let a=await new q(e.DB).findByKey(t);if(a)return rr.set(t,{data:a,ts:s}),n.waitUntil(P.set(r,i,a,3600)),a}catch(c){if(console.warn(`[DoH] D1 profile lookup failed for key ${t}:`,c.message||c),o?.data)return o.data;let a=e.FAIL_OPEN_UPSTREAM||"https://freedns.controld.com/no-ads-malware-typo";return console.warn(`[DoH] D1 unavailable. Providing emergency fallback profile for key ${t} -> ${a}`),{id:t,name:"Emergency Fallback",settings:JSON.stringify({upstream:[a],default_policy:"ALLOW",log_retention_days:0,ecs:{enabled:!0,use_client_ip:!0}}),owner_id:"system",created_at:Math.floor(s/1e3),updated_at:Math.floor(s/1e3)}}return null}async function Cc(t,e){let n=t.SERVERFULL_DEFAULT_PROFILE_KEY||t.DEFAULT_PROFILE_KEY;if(n){let r=await Un(n,t,e);if(r)return r}try{let r=new q(t.DB),s=await r.list("ORDER BY created_at ASC LIMIT 1",[]);if(s&&s.length>0){let o=await r.getById(s[0].id);if(o)return o}}catch(r){console.warn("[Profile] Failed to query fallback default profile:",r.message||r)}return{id:"default",name:"Default Profile",settings:JSON.stringify({upstream:[t.FAIL_OPEN_UPSTREAM||"https://security.cloudflare-dns.com/dns-query"],default_policy:"ALLOW",log_retention_days:0,ecs:{enabled:!0,use_client_ip:!0}}),owner_id:"system",created_at:Math.floor(Date.now()/1e3),updated_at:Math.floor(Date.now()/1e3)}}async function Dc(t,e,n,r){let s=caches.default,o=null;try{let i=await Un(r,e,n);if(!i)return new Response("Invalid Profile Key",{status:404});let c=i.id,a=await vo(t);if(!a)return new Response("Invalid DNS Query",{status:400});o=a.raw;let l={profileId:c,accessPointId:i.access_point_id,accessPointName:i.access_point_name,startTime:Date.now(),env:e,ctx:n},d=await de.process(t,a,l);return n.waitUntil((async()=>{try{let u=t.headers.get("CF-Connecting-IP")||"127.0.0.1",f=Number(e.ACTIVE_DNS_CACHE_TTL)||60;await P.set(s,`active_dns:${u}`,c,f);let p=Math.floor(Date.now()/1e3),m=`active_throttle:${c}`,h=await P.get(s,m),g=Number(e.THROTTLE_ACTIVE_SEC)||3600;if(!h||p-h>g){try{await new q(e.DB).updateLastActive(c,p),await new Y(e.DB,e).updateLastActiveByProfile(c,p)}catch{}await P.set(s,m,p,g)}}catch(u){console.error(`[Background Task] Error for ${c}:`,u)}})()),new Response(d.answer,{headers:{"Content-Type":"application/dns-message","Cache-Control":`max-age=${d.ttl}`}})}catch(i){console.error("[DoH Pipeline] Internal Error:",i);try{let c=e.FAIL_OPEN_UPSTREAM||"https://freedns.controld.com/no-ads-malware-typo",a=o||await bu(t);if(a&&a.length>0){let l=_t(c),d=await St(l,a);return new Response(d.answer,{headers:{"Content-Type":"application/dns-message","Cache-Control":"max-age=60"}})}if(c.startsWith("http://")||c.startsWith("https://")){let l=new URL(c),d=new URL(t.url);return l.search=d.search,await fetch(l.toString(),{method:t.method,headers:{Accept:t.headers.get("Accept")||"application/dns-message","Content-Type":t.headers.get("Content-Type")||"application/dns-message"},body:t.method==="POST"?t.body:void 0})}return new Response("Invalid DNS Query",{status:400})}catch(c){return console.error("[DoH Pipeline] Emergency fallback failed:",c),new Response("Internal Server Error",{status:500})}}}import kc from"node:fs";import{execSync as zt}from"node:child_process";function Eu(t,e){try{let n=e.toLowerCase(),r=zt(`netstat -ano -p ${n}`,{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:3e3}),s=null,o=r.split(/\r?\n/);for(let a of o){let l=a.trim();if(!l.toUpperCase().startsWith(e))continue;let d=l.split(/\s+/);if(d.length<4)continue;let u=d[1];if(!u)continue;if(u.endsWith(`:${t}`)||u.endsWith(`]:${t}`)){if(e==="TCP"&&d[3]!=="LISTENING")continue;let p=d[d.length-1],m=parseInt(p,10);if(!isNaN(m)&&m>0){s=m;break}}}if(!s)return null;let i=`PID ${s}`,c;try{let l=zt(`tasklist /SVC /FI "PID eq ${s}" /FO CSV /NH`,{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:2500}).trim().match(/"([^"]+)"\s*,\s*"(\d+)"\s*(?:,\s*"([^"]+)")?/);l&&(i=l[1],l[3]&&l[3]!=="N/A"&&(c=l[3]))}catch{}return{pid:s,processName:i,serviceName:c}}catch{return null}}function _u(t,e){try{let r=zt(`ss ${e==="TCP"?"-lptn":"-lpun"} "sport = :${t}"`,{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:3e3});for(let s of r.split(/\r?\n/)){let i=s.trim().match(/users:\(\("([^"]+)",pid=(\d+)/);if(i)return{processName:i[1],pid:parseInt(i[2],10)}}if(t===53&&r.includes("127.0.0.53"))return{processName:"systemd-resolved",serviceName:"DNSStubListener (127.0.0.53)"}}catch{}try{let n=e==="TCP"?`-iTCP:${t} -sTCP:LISTEN`:`-iUDP:${t}`,s=zt(`lsof -nP ${n}`,{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:3e3}).trim().split(/\r?\n/);if(s.length>1){let i=s[1].trim().split(/\s+/);if(i.length>=2){let c=i[0],a=parseInt(i[1],10);return{processName:c,pid:isNaN(a)?void 0:a}}}}catch{}try{let n=e.toLowerCase(),s=zt(`fuser ${t}/${n}`,{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:2e3}).trim().match(/(\d+)/);if(s){let o=parseInt(s[1],10),i=`PID ${o}`;try{kc.existsSync(`/proc/${o}/comm`)&&(i=kc.readFileSync(`/proc/${o}/comm`,"utf-8").trim())}catch{}return{pid:o,processName:i}}}catch{}if(t===53)try{if(zt("systemctl is-active systemd-resolved",{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:1e3}).trim()==="active")return{processName:"systemd-resolved",serviceName:"DNSStubListener"}}catch{}return null}function Su(t,e){try{let n=e==="TCP"?`-iTCP:${t} -sTCP:LISTEN`:`-iUDP:${t}`,s=zt(`lsof -nP ${n}`,{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:3e3}).trim().split(/\r?\n/);if(s.length>1){let i=s[1].trim().split(/\s+/);if(i.length>=2){let c=i[0],a=parseInt(i[1],10);return{processName:c,pid:isNaN(a)?void 0:a}}}}catch{}return null}function Qt(t,e){return process.platform==="win32"?Eu(t,e):process.platform==="linux"?_u(t,e):Su(t,e)}function Zt(t){let e=t.processName;return t.pid&&(e+=` (PID ${t.pid})`),t.serviceName&&t.serviceName!==t.processName&&(e+=` [${t.serviceName}]`),e}function Mn(t,e=" "){return t?`
331
+ `).bind(r),c=await this.db.batch([s,o,i]);return{clearedProfiles:c[1].meta.changes||0,deletedUsers:c[2].meta.changes||0}}};var Y=class{secrets;core;security;mfa;lifecycle;constructor(e,t){this.secrets=new so(e,t),this.core=new oo(e,this.secrets),this.security=new io(e),this.mfa=new ao(e,t),this.lifecycle=new co(e)}async getById(e){return this.core.getById(e)}async getByUsername(e){return this.core.getByUsername(e)}async listAll(){return this.core.listAll()}async create(e){return this.core.create(e)}async updateUsername(e,t){return this.core.updateUsername(e,t)}async updateTimezone(e,t){return this.core.updateTimezone(e,t)}async updateLocale(e,t){return this.core.updateLocale(e,t)}async delete(e){return this.core.delete(e)}async isEmpty(){return this.core.isEmpty()}async updatePassword(e,t,r=2){return this.security.updatePassword(e,t,r)}async updatePinHash(e,t){return this.security.updatePinHash(e,t)}async updateSessionLockTimeout(e,t){return this.security.updateSessionLockTimeout(e,t)}async updateTOTP(e,t,r){return this.mfa.updateTOTP(e,t,r)}async removeTOTP(e,t=!1){return this.mfa.removeTOTP(e,t)}async updateRecoveryKeys(e,t){return this.mfa.updateRecoveryKeys(e,t)}async updateTOTPSettings(e,t){return this.mfa.updateTOTPSettings(e,t)}async consumeRecoveryKey(e,t,r){return this.mfa.consumeRecoveryKey(e,t,r)}async updateLastActiveByProfile(e,t){return this.lifecycle.updateLastActiveByProfile(e,t)}async applyInactivityPolicy(e){return this.lifecycle.applyInactivityPolicy(e)}};ge();async function Pu(n){try{if(n.method==="GET"){let t=new URL(n.url).searchParams.get("dns");if(!t)return null;let r=t.replace(/-/g,"+").replace(/_/g,"/");for(;r.length%4;)r+="=";let s=atob(r),o=new Uint8Array(s.length);for(let i=0;i<s.length;i++)o[i]=s.charCodeAt(i);return o}else if(n.method==="POST"){let e=await n.clone().arrayBuffer();return new Uint8Array(e)}}catch{return null}return null}async function Kn(n,e,t){let r=caches.default,s=Date.now(),o=lr.get(n);if(o&&s-o.ts<3e5)return o.data;let i=`doh_key_v1:${n}`;try{let c=await P.get(r,i);if(c)return lr.set(n,{data:c,ts:s}),c}catch{}try{let a=await new q(e.DB).findByKey(n);if(a)return lr.set(n,{data:a,ts:s}),t.waitUntil(P.set(r,i,a,3600)),a}catch(c){if(console.warn(`[DoH] D1 profile lookup failed for key ${n}:`,c.message||c),o?.data)return o.data;let a=e.FAIL_OPEN_UPSTREAM||"https://freedns.controld.com/no-ads-malware-typo";return console.warn(`[DoH] D1 unavailable. Providing emergency fallback profile for key ${n} -> ${a}`),{id:n,name:"Emergency Fallback",settings:JSON.stringify({upstream:[a],default_policy:"ALLOW",log_retention_days:0,ecs:{enabled:!0,use_client_ip:!0}}),owner_id:"system",created_at:Math.floor(s/1e3),updated_at:Math.floor(s/1e3)}}return null}async function Ic(n,e){let t=n.SERVERFULL_DEFAULT_PROFILE_KEY||n.DEFAULT_PROFILE_KEY;if(t){let r=await Kn(t,n,e);if(r)return r}try{let r=new q(n.DB),s=await r.list("ORDER BY created_at ASC LIMIT 1",[]);if(s&&s.length>0){let o=await r.getById(s[0].id);if(o)return o}}catch(r){console.warn("[Profile] Failed to query fallback default profile:",r.message||r)}return{id:"default",name:"Default Profile",settings:JSON.stringify({upstream:[n.FAIL_OPEN_UPSTREAM||"https://security.cloudflare-dns.com/dns-query"],default_policy:"ALLOW",log_retention_days:0,ecs:{enabled:!0,use_client_ip:!0}}),owner_id:"system",created_at:Math.floor(Date.now()/1e3),updated_at:Math.floor(Date.now()/1e3)}}async function Uc(n,e,t,r){let s=caches.default,o=null;try{let i=await Kn(r,e,t);if(!i)return new Response("Invalid Profile Key",{status:404});let c=i.id,a=await Oo(n);if(!a)return new Response("Invalid DNS Query",{status:400});o=a.raw;let l={profileId:c,accessPointId:i.access_point_id,accessPointName:i.access_point_name,startTime:Date.now(),env:e,ctx:t},d=await de.process(n,a,l);return t.waitUntil((async()=>{try{let u=n.headers.get("CF-Connecting-IP")||"127.0.0.1",f=Number(e.ACTIVE_DNS_CACHE_TTL)||60;await P.set(s,`active_dns:${u}`,c,f);let p=Math.floor(Date.now()/1e3),m=`active_throttle:${c}`,h=await P.get(s,m),g=Number(e.THROTTLE_ACTIVE_SEC)||3600;if(!h||p-h>g){try{await new q(e.DB).updateLastActive(c,p),await new Y(e.DB,e).updateLastActiveByProfile(c,p)}catch{}await P.set(s,m,p,g)}}catch(u){console.error(`[Background Task] Error for ${c}:`,u)}})()),new Response(d.answer,{headers:{"Content-Type":"application/dns-message","Cache-Control":`max-age=${d.ttl}`}})}catch(i){console.error("[DoH Pipeline] Internal Error:",i);try{let c=e.FAIL_OPEN_UPSTREAM||"https://freedns.controld.com/no-ads-malware-typo",a=o||await Pu(n);if(a&&a.length>0){let l=Tt(c),d=await xt(l,a);return new Response(d.answer,{headers:{"Content-Type":"application/dns-message","Cache-Control":"max-age=60"}})}if(c.startsWith("http://")||c.startsWith("https://")){let l=new URL(c),d=new URL(n.url);return l.search=d.search,await fetch(l.toString(),{method:n.method,headers:{Accept:n.headers.get("Accept")||"application/dns-message","Content-Type":n.headers.get("Content-Type")||"application/dns-message"},body:n.method==="POST"?n.body:void 0})}return new Response("Invalid DNS Query",{status:400})}catch(c){return console.error("[DoH Pipeline] Emergency fallback failed:",c),new Response("Internal Server Error",{status:500})}}}import Mc from"node:fs";import{execSync as tn}from"node:child_process";function Cu(n,e){try{let t=e.toLowerCase(),r=tn(`netstat -ano -p ${t}`,{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:3e3}),s=null,o=r.split(/\r?\n/);for(let a of o){let l=a.trim();if(!l.toUpperCase().startsWith(e))continue;let d=l.split(/\s+/);if(d.length<4)continue;let u=d[1];if(!u)continue;if(u.endsWith(`:${n}`)||u.endsWith(`]:${n}`)){if(e==="TCP"&&d[3]!=="LISTENING")continue;let p=d[d.length-1],m=parseInt(p,10);if(!isNaN(m)&&m>0){s=m;break}}}if(!s)return null;let i=`PID ${s}`,c;try{let l=tn(`tasklist /SVC /FI "PID eq ${s}" /FO CSV /NH`,{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:2500}).trim().match(/"([^"]+)"\s*,\s*"(\d+)"\s*(?:,\s*"([^"]+)")?/);l&&(i=l[1],l[3]&&l[3]!=="N/A"&&(c=l[3]))}catch{}return{pid:s,processName:i,serviceName:c}}catch{return null}}function Du(n,e){try{let r=tn(`ss ${e==="TCP"?"-lptn":"-lpun"} "sport = :${n}"`,{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:3e3});for(let s of r.split(/\r?\n/)){let i=s.trim().match(/users:\(\("([^"]+)",pid=(\d+)/);if(i)return{processName:i[1],pid:parseInt(i[2],10)}}if(n===53&&r.includes("127.0.0.53"))return{processName:"systemd-resolved",serviceName:"DNSStubListener (127.0.0.53)"}}catch{}try{let t=e==="TCP"?`-iTCP:${n} -sTCP:LISTEN`:`-iUDP:${n}`,s=tn(`lsof -nP ${t}`,{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:3e3}).trim().split(/\r?\n/);if(s.length>1){let i=s[1].trim().split(/\s+/);if(i.length>=2){let c=i[0],a=parseInt(i[1],10);return{processName:c,pid:isNaN(a)?void 0:a}}}}catch{}try{let t=e.toLowerCase(),s=tn(`fuser ${n}/${t}`,{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:2e3}).trim().match(/(\d+)/);if(s){let o=parseInt(s[1],10),i=`PID ${o}`;try{Mc.existsSync(`/proc/${o}/comm`)&&(i=Mc.readFileSync(`/proc/${o}/comm`,"utf-8").trim())}catch{}return{pid:o,processName:i}}}catch{}if(n===53)try{if(tn("systemctl is-active systemd-resolved",{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:1e3}).trim()==="active")return{processName:"systemd-resolved",serviceName:"DNSStubListener"}}catch{}return null}function ku(n,e){try{let t=e==="TCP"?`-iTCP:${n} -sTCP:LISTEN`:`-iUDP:${n}`,s=tn(`lsof -nP ${t}`,{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:3e3}).trim().split(/\r?\n/);if(s.length>1){let i=s[1].trim().split(/\s+/);if(i.length>=2){let c=i[0],a=parseInt(i[1],10);return{processName:c,pid:isNaN(a)?void 0:a}}}}catch{}return null}function nn(n,e){return process.platform==="win32"?Cu(n,e):process.platform==="linux"?Du(n,e):ku(n,e)}function rn(n){let e=n.processName;return n.pid&&(e+=` (PID ${n.pid})`),n.serviceName&&n.serviceName!==n.processName&&(e+=` [${n.serviceName}]`),e}function Wn(n,e=" "){return n?`
332
332
  Tip:
333
- ${Array.isArray(t)?t.map(r=>`${e}${r}`).join(`
334
- `):`${e}${t}`}
335
- `:""}function Lc(t){let{name:e,description:n,usage:r,commands:s,options:o,services:i,envVars:c,tip:a}=t,l=" ",d=4,u=[...s||[],...o||[]],f=Math.max(...u.map(w=>w.label.length),0),p=(w,b,y)=>{if(!b||b.length===0)return"";let E=y??Math.max(...b.map(S=>S.label.length),0),_=b.map(S=>`${l}${S.label.padEnd(E+d)}${S.desc}`);return`
336
- ${w}:
333
+ ${Array.isArray(n)?n.map(r=>`${e}${r}`).join(`
334
+ `):`${e}${n}`}
335
+ `:""}function Bc(n){let{name:e,description:t,usage:r,commands:s,options:o,services:i,envVars:c,tip:a}=n,l=" ",d=4,u=[...s||[],...o||[]],f=Math.max(...u.map(b=>b.label.length),0),p=(b,w,y)=>{if(!w||w.length===0)return"";let E=y??Math.max(...w.map(S=>S.label.length),0),_=w.map(S=>`${l}${S.label.padEnd(E+d)}${S.desc}`);return`
336
+ ${b}:
337
337
  ${_.join(`
338
- `)}`},m=Array.isArray(r)?r.map(w=>`${l}${w}`).join(`
339
- `):`${l}${r}`,h=a?Mn(a,l).trimEnd():"";return[`${e} - ${n}`,`
338
+ `)}`},m=Array.isArray(r)?r.map(b=>`${l}${b}`).join(`
339
+ `):`${l}${r}`,h=a?Wn(a,l).trimEnd():"";return[`${e} - ${t}`,`
340
340
  Usage:
341
341
  ${m}`,p("Commands",s,f),p("Options",o,f),p("Current Service Ports",i),p("Environment Variables",c),h].filter(Boolean).join(`
342
342
  `)+`
343
- `}function ro(t){let{title:e,items:n,indent:r=" ",gap:s=4}=t;if(!n||n.length===0)return"";let o=Math.max(...n.map(c=>c.command.length),0),i=n.map(c=>`${r}${c.command.padEnd(o+s)}# ${c.desc}`);return e?`${e}
343
+ `}function lo(n){let{title:e,items:t,indent:r=" ",gap:s=4}=n;if(!t||t.length===0)return"";let o=Math.max(...t.map(c=>c.command.length),0),i=t.map(c=>`${r}${c.command.padEnd(o+s)}# ${c.desc}`);return e?`${e}
344
344
  ${i.join(`
345
345
  `)}
346
346
  `:i.join(`
347
347
  `)+`
348
- `}function so(t){let{title:e,content:n,borderChar:r="-",minWidth:s=60,tip:o}=t,i=`[${e}]`,c=Math.max(s,i.length+8),a=r.repeat(c),l=3,d=Math.max(3,c-i.length-l-2),f=[`${r.repeat(l)} ${i} ${r.repeat(d)}`,n,a];return o&&f.push(`Tip: ${o}`),`
348
+ `}function uo(n){let{title:e,content:t,borderChar:r="-",minWidth:s=60,tip:o}=n,i=`[${e}]`,c=Math.max(s,i.length+8),a=r.repeat(c),l=3,d=Math.max(3,c-i.length-l-2),f=[`${r.repeat(l)} ${i} ${r.repeat(d)}`,t,a];return o&&f.push(`Tip: ${o}`),`
349
349
  `+f.join(`
350
350
  `)+`
351
- `}function Ct(t){let{title:e,bullet:n="\u2022 ",items:r,indent:s=" ",gap:o=2}=t;if(!r||r.length===0)return"";let i=Math.max(...r.map(a=>a.label.length),0),c=r.map(a=>`${s}${n}${a.label.padEnd(i+o)}: ${a.value}`);return e?`${e}
351
+ `}function nt(n){let{title:e,bullet:t="\u2022 ",items:r,indent:s=" ",gap:o=2}=n;if(!r||r.length===0)return"";let i=Math.max(...r.map(a=>a.label.length),0),c=r.map(a=>`${s}${t}${a.label.padEnd(i+o)}: ${a.value}`);return e?`${e}
352
352
  ${c.join(`
353
353
  `)}`:c.join(`
354
- `)}function We(t){let{title:e,subtitle:n,borderChar:r="-",bullet:s="\u2022 ",minWidth:o=54,items:i}=t,c=[e.length+6,n?n.length+6:0,...(i||[]).map(f=>f.label.length+f.value.length+10)],a=Math.max(o,...c),l=r.repeat(a),d=f=>{let p=Math.max(0,Math.floor((a-f.length)/2));return" ".repeat(p)+f},u=[l,d(e)];if(n&&u.push(d(n)),u.push(l),i&&i.length>0){let f=Math.max(...i.map(m=>m.label.length),0),p=i.map(m=>` ${s}${m.label.padEnd(f+2)}: ${m.value}`);u.push(...p),u.push(l)}return u.join(`
355
- `)}function M(t){let{title:e,message:n,details:r,causes:s,solutions:o}=t,i=" ",c=" ",a=[`[${e}] ${n}`];if(r&&r.length>0&&a.push(r.map(l=>`${i}${l}`).join(`
354
+ `)}function Ce(n){let{title:e,subtitle:t,borderChar:r="-",bullet:s="\u2022 ",minWidth:o=54,items:i}=n,c=[e.length+6,t?t.length+6:0,...(i||[]).map(f=>f.label.length+f.value.length+10)],a=Math.max(o,...c),l=r.repeat(a),d=f=>{let p=Math.max(0,Math.floor((a-f.length)/2));return" ".repeat(p)+f},u=[l,d(e)];if(t&&u.push(d(t)),u.push(l),i&&i.length>0){let f=Math.max(...i.map(m=>m.label.length),0),p=i.map(m=>` ${s}${m.label.padEnd(f+2)}: ${m.value}`);u.push(...p),u.push(l)}return u.join(`
355
+ `)}function O(n){let{title:e,message:t,details:r,causes:s,solutions:o}=n,i=" ",c=" ",a=[`[${e}] ${t}`];if(r&&r.length>0&&a.push(r.map(l=>`${i}${l}`).join(`
356
356
  `)),s&&s.length>0){let l=`${i}Possible causes:`,d=s.map(u=>`${c}- ${u}`).join(`
357
357
  `);a.push(`${l}
358
358
  ${d}`)}if(o&&o.length>0){let l=o.length===1?`${i}Solution:`:`${i}Solutions:`,d=o.map(u=>`${c}- ${u}`).join(`
@@ -360,9 +360,9 @@ ${d}`)}if(o&&o.length>0){let l=o.length===1?`${i}Solution:`:`${i}Solutions:`,d=o
360
360
  ${d}`)}return`
361
361
  `+a.filter(Boolean).join(`
362
362
  `)+`
363
- `}function qt(t){let{serviceName:e,protocol:n,port:r,err:s,alternateOption:o,disableOption:i}=t,c=s?.code;if(c==="EADDRINUSE"){let l=n==="UDP"?"UDP":"TCP",d=t.occupant!==void 0?t.occupant:Qt(r,l),u=d?Zt(d):null,f=[],p=[],m=[];if(u&&p.push(`Occupying Program: ${u}`),n==="UDP"&&r===53)if(d?.processName.includes("systemd-resolve"))f.push("systemd-resolved is occupying port 53 via its local DNS stub listener (127.0.0.53)."),m.push("Disable systemd-resolved DNSStubListener (set 'DNSStubListener=no' in /etc/systemd/resolved.conf, then run 'systemctl restart systemd-resolved').");else if(d?.serviceName==="SharedAccess")f.push("Windows Internet Connection Sharing (ICS) / Mobile Hotspot is occupying UDP port 53."),m.push("Stop Internet Connection Sharing / Mobile Hotspot in Windows Network Settings (or run: 'Stop-Service SharedAccess' in PowerShell).");else if(d){if(f.push(`Program '${u}' is currently listening on UDP port 53.`),d.pid){let g=process.platform==="win32"?`taskkill /PID ${d.pid} /F`:`sudo kill ${d.pid}`;m.push(`Terminate conflicting process: '${g}'`)}}else f.push("Linux: systemd-resolved or another DNS server (bind9, dnsmasq, AdGuard Home) is listening on port 53."),f.push("Windows: Internet Connection Sharing (ICS) or another service is listening on port 53.");else if(d){if(f.push(`Program '${u}' is currently listening on ${n} port ${r}.`),d.pid){let g=process.platform==="win32"?`taskkill /PID ${d.pid} /F`:`sudo kill ${d.pid}`;m.push(`Terminate conflicting process: '${g}'`)}}else f.push(`Another service or application is already listening on ${n} port ${r}.`);m.push(`Use ${o} to specify an alternate port.`),i&&m.push(`Or use ${i} to disable this transport.`);let h=u?`${e} port ${r} is already in use by ${u}.`:`${e} port ${r} is already in use.`;return M({level:"error",title:"Port Conflict",message:h,details:p.length>0?p:void 0,causes:f,solutions:m})}if(c==="EACCES"){let l=["Port numbers below 1024 require elevated privileges on Linux/macOS (e.g. DNS port 53).","On Windows, the port may fall within a reserved NAT/Hyper-V port exclusion range."],d=process.platform==="linux",u=[d?"Run persistently as systemd service (Recommended): 'sudo dns-worker service install' (enables port 53 via CAP_NET_BIND_SERVICE)":"Run with elevated Administrator privileges.",d?"Or run directly in foreground with sudo: 'sudo dns-worker'":null,`Or bind to an unprivileged port: '${o}'`,i?`Or disable this transport: '${i}'`:null].filter(Boolean);return M({level:"error",title:"Permission Denied",message:`Permission denied binding to ${e} port ${r}.`,causes:l,solutions:u})}let a=s instanceof Error?s.message:String(s);return`
363
+ `}function sn(n){let{serviceName:e,protocol:t,port:r,err:s,alternateOption:o,disableOption:i}=n,c=s?.code;if(c==="EADDRINUSE"){let l=t==="UDP"?"UDP":"TCP",d=n.occupant!==void 0?n.occupant:nn(r,l),u=d?rn(d):null,f=[],p=[],m=[];if(u&&p.push(`Occupying Program: ${u}`),t==="UDP"&&r===53)if(d?.processName.includes("systemd-resolve"))f.push("systemd-resolved is occupying port 53 via its local DNS stub listener (127.0.0.53)."),m.push("Disable systemd-resolved DNSStubListener (set 'DNSStubListener=no' in /etc/systemd/resolved.conf, then run 'systemctl restart systemd-resolved').");else if(d?.serviceName==="SharedAccess")f.push("Windows Internet Connection Sharing (ICS) / Mobile Hotspot is occupying UDP port 53."),m.push("Stop Internet Connection Sharing / Mobile Hotspot in Windows Network Settings (or run: 'Stop-Service SharedAccess' in PowerShell).");else if(d){if(f.push(`Program '${u}' is currently listening on UDP port 53.`),d.pid){let g=process.platform==="win32"?`taskkill /PID ${d.pid} /F`:`sudo kill ${d.pid}`;m.push(`Terminate conflicting process: '${g}'`)}}else f.push("Linux: systemd-resolved or another DNS server (bind9, dnsmasq, AdGuard Home) is listening on port 53."),f.push("Windows: Internet Connection Sharing (ICS) or another service is listening on port 53.");else if(d){if(f.push(`Program '${u}' is currently listening on ${t} port ${r}.`),d.pid){let g=process.platform==="win32"?`taskkill /PID ${d.pid} /F`:`sudo kill ${d.pid}`;m.push(`Terminate conflicting process: '${g}'`)}}else f.push(`Another service or application is already listening on ${t} port ${r}.`);m.push(`Use ${o} to specify an alternate port.`),i&&m.push(`Or use ${i} to disable this transport.`);let h=u?`${e} port ${r} is already in use by ${u}.`:`${e} port ${r} is already in use.`;return O({level:"error",title:"Port Conflict",message:h,details:p.length>0?p:void 0,causes:f,solutions:m})}if(c==="EACCES"){let l=["Port numbers below 1024 require elevated privileges on Linux/macOS (e.g. DNS port 53).","On Windows, the port may fall within a reserved NAT/Hyper-V port exclusion range."],d=process.platform==="linux",u=[d?"Run persistently as systemd service (Recommended): 'sudo dns-worker service install' (enables port 53 via CAP_NET_BIND_SERVICE)":"Run with elevated Administrator privileges.",d?"Or run directly in foreground with sudo: 'sudo dns-worker'":null,`Or bind to an unprivileged port: '${o}'`,i?`Or disable this transport: '${i}'`:null].filter(Boolean);return O({level:"error",title:"Permission Denied",message:`Permission denied binding to ${e} port ${r}.`,causes:l,solutions:u})}let a=s instanceof Error?s.message:String(s);return`
364
364
  [${e}] Startup Error: ${a}
365
- `}var oo=class{constructor(e){this.options=e}options;socket=null;isRunning=!1;start(){return new Promise((e,n)=>{try{this.socket=Ru.createSocket("udp4");let r=s=>{try{this.socket?.close()}catch{}this.socket=null,console.error(qt({serviceName:"UDP DNS",protocol:"UDP",port:this.options.port,err:s,alternateOption:"--dns-port <port> (e.g. --dns-port 5353)",disableOption:"--disable-udp"})),n(s)};this.socket.once("error",r),this.socket.on("message",async(s,o)=>{await this.handleMessage(s,o)}),this.socket.bind(this.options.port,this.options.host,()=>{this.socket?.removeListener("error",r),this.socket?.on("error",s=>{console.error("[UDP DNS] Socket runtime error:",s)});try{this.socket?.setRecvBufferSize(4*1024*1024),this.socket?.setSendBufferSize(4*1024*1024)}catch{}this.isRunning=!0,console.log(`[UDP DNS] Classic DNS listening on udp://${this.options.host}:${this.options.port}`),e()})}catch(r){n(r)}})}async handleMessage(e,n){try{let r=new Uint8Array(e.buffer,e.byteOffset,e.byteLength),s=dn(r);if(!s)return;let o=this.options.env,i={waitUntil(p){p.catch(m=>console.error("[UDP Background Task Error]:",m))},passThroughOnException(){}},c=null;if(this.options.defaultProfileKey&&(c=await Un(this.options.defaultProfileKey,o,i)),c||(c=await Cc(o,i)),!c)return;let a={profileId:c.id,accessPointId:c.access_point_id,accessPointName:c.access_point_name,startTime:Date.now(),env:o,ctx:i},l=n.address.includes(":")?`[${n.address}]`:n.address,d=new Request(`http://${l}/dns-query`,{headers:{"CF-Connecting-IP":n.address,Accept:"application/dns-message","Content-Type":"application/dns-message"}}),u=await de.process(d,s,a);if(!u||!u.answer||u.answer.length===0)return;let f=u.answer;if(f.length>512){let p=new Uint8Array(f);p[2]|=2,f=p.slice(0,512)}this.socket?.send(f,n.port,n.address,p=>{p&&console.warn(`[UDP DNS] Failed to send answer to ${n.address}:${n.port}:`,p.message)})}catch(r){console.error("[UDP DNS] Message handling exception:",r);try{let s=this.options.env.FAIL_OPEN_UPSTREAM||"https://freedns.controld.com/no-ads-malware-typo",o=new Uint8Array(e.buffer,e.byteOffset,e.byteLength),i=_t(s),a=(await St(i,o)).answer;if(a.length>512){let l=new Uint8Array(a);l[2]|=2,a=l.slice(0,512)}this.socket?.send(a,n.port,n.address)}catch(s){console.error("[UDP DNS] Fail-open upstream fallback failed:",s)}}}stop(){return new Promise(e=>{this.socket&&this.isRunning?this.socket.close(()=>{this.isRunning=!1,console.log("[UDP DNS] Service stopped."),e()}):e()})}};import io from"node:fs";import xu from"node:tls";import{Buffer as ao}from"node:buffer";import Dr from"node:fs";import Tu from"node:crypto";function Bn(t,e){if(!!!(t&&e))return{configured:!1,filesExist:!1,certPath:t||"",keyPath:e||"",isWildcard:!1,domains:[],expiresAt:null};let r=!1,s=!1,o;try{Dr.accessSync(t,Dr.constants.R_OK),r=!0}catch(c){let a=c?.code,l=c instanceof Error?c.message:String(c);a==="EACCES"?o=`Permission denied (EACCES) reading certPath: ${t}`:a==="ENOENT"?o=`Certificate file not found: ${t}`:o=`Cannot read certPath (${t}): ${l}`}try{Dr.accessSync(e,Dr.constants.R_OK),s=!0}catch(c){let a=c?.code,l=c instanceof Error?c.message:String(c),d=a==="EACCES"?`Permission denied (EACCES) reading keyPath: ${e}`:a==="ENOENT"?`Private key file not found: ${e}`:`Cannot read keyPath (${e}): ${l}`;o=o?`${o}; ${d}`:d}if(!(r&&s))return{configured:!0,filesExist:!1,certPath:t,keyPath:e,isWildcard:!1,domains:[],expiresAt:null,error:o};try{let c=Dr.readFileSync(t,"utf-8"),a=new Tu.X509Certificate(c),l=[],d=!1;if(a.subjectAltName){let f=a.subjectAltName.split(",").map(p=>p.trim());for(let p of f)if(p.startsWith("DNS:")){let m=p.slice(4).trim().toLowerCase();l.includes(m)||l.push(m),m.startsWith("*.")&&(d=!0)}}if(a.subject){let f=a.subject.match(/CN=([^,\n\/]+)/i);if(f){let p=f[1].trim().toLowerCase();l.includes(p)||l.push(p),p.startsWith("*.")&&(d=!0)}}let u=new Date(a.validTo);return{configured:!0,filesExist:!0,certPath:t,keyPath:e,isWildcard:d,domains:l,expiresAt:u}}catch(c){let a=c instanceof Error?c.message:String(c);return{configured:!0,filesExist:!0,certPath:t,keyPath:e,isWildcard:!1,domains:[],expiresAt:null,error:a}}}function kr(t){let e=t?t.replace(/^\*\./,"").trim():"your.domain";return`certbot certonly -d *.${e} -d ${e} --manual --preferred-challenges dns`}function Ti(t,e){let n=kr(e);return t==="missing"?{level:"warning",title:"TLS Certificate Not Configured / Missing",message:"No valid TLS certificate detected. HTTPS Web UI (port 10443) and DoT (port 853) are disabled.",details:["Plain HTTP Web UI (port 10080) and Classic UDP DNS (port 53) remain fully operational."],solutions:["To enable HTTPS and DoT with per-profile routing, register a free wildcard certificate using certbot:",` ${n}`,"Then configure SERVERFULL_TLS_CERT_PATH and SERVERFULL_TLS_KEY_PATH in your .env file."]}:{level:"warning",title:"Non-Wildcard TLS Certificate Detected (DoT Paused)",message:"The current certificate does not cover wildcard subdomains (*.domain). DoT (DNS over TLS / DoQ) is paused until a valid wildcard certificate is installed.",details:["DoT requires a wildcard certificate (*.domain) to securely route queries to specific profiles via TLS SNI (<profileKey>.your.domain).","The policy allowing access to Default Profile without a wildcard certificate has been disabled."],solutions:["You can register a wildcard certificate using Certbot via DNS challenge:",` ${n}`,"Then update SERVERFULL_TLS_CERT_PATH and SERVERFULL_TLS_KEY_PATH to resume DoT service."]}}var co=class{constructor(e){this.options=e}options;server=null;isRunning=!1;start(){return new Promise((e,n)=>{let{tlsKeyPath:r,tlsCertPath:s,port:o,host:i}=this.options;if(!r||!s){console.warn(M({level:"warning",title:"DoT - TLS Not Configured",message:"TLS key or certificate path not provided. Skipping DoT server startup.",solutions:["Set SERVERFULL_TLS_KEY_PATH and SERVERFULL_TLS_CERT_PATH to enable DNS over TLS (DoT)."]})),e();return}if(!io.existsSync(r)||!io.existsSync(s)){console.warn(M({level:"warning",title:"DoT - TLS Files Missing",message:"Configured TLS key or certificate files were not found on disk. Skipping DoT server startup.",details:[`Key path : ${r}`,`Cert path : ${s}`],solutions:["Verify the file paths or generate TLS certificates before enabling DoT."]})),e();return}if(!Bn(s,r).isWildcard){console.warn(M({level:"warning",title:"DoT - Paused (No Wildcard Certificate)",message:"DNS over TLS (DoT) is paused because no valid wildcard certificate (*.domain) was detected.",details:["DoT requires a wildcard certificate (*.domain) to securely route queries to specific profiles via TLS SNI (<profileKey>.your.domain).","Accessing default profile without a wildcard certificate has been disabled."],solutions:["Register a wildcard certificate using Certbot via DNS challenge:",` ${kr(this.options.dotDomain)}`,"Install the wildcard certificate and restart dns-worker to resume DoT service."]})),e();return}try{let a={key:io.readFileSync(r),cert:io.readFileSync(s),ALPNProtocols:["dot"],sessionIdContext:"dns-worker-dot"};this.server=xu.createServer(a,d=>{this.handleConnection(d)});let l=d=>{this.server=null,console.error(qt({serviceName:"DNS over TLS (DoT)",protocol:"DoT",port:o,err:d,alternateOption:"--dot-port <port> (e.g. --dot-port 8853)",disableOption:"--disable-dot"})),n(d)};this.server.once("error",l),this.server.listen(o,i,()=>{this.server?.removeListener("error",l),this.server?.on("error",u=>{console.error("[DoT] Runtime error:",u)}),this.isRunning=!0;let d=this.options.dotDomain?` (${this.options.dotDomain})`:"";console.log(`[DoT] DNS over TLS listening on tls://${i}:${o}${d}`),e()})}catch(a){console.error("[DoT] Failed to initialize TLS server:",a),n(a)}})}handleConnection(e){e.setNoDelay(!0),e.setKeepAlive(!0,6e4);let n=e.remoteAddress?.replace(/^::ffff:/,"")||"127.0.0.1",r=ao.alloc(0),s=(e.servername||"").toLowerCase().trim(),o="",i=this.options.dotDomain?.toLowerCase().trim().replace(/^\*\./,"");if(i&&s){if(s===i)o="";else if(s.endsWith("."+i)){let a=s.slice(0,-(i.length+1)),l=a.split(".")[0];Ft.test(l)?o=l:Ft.test(a)&&(o=a)}}if(!o&&s){let a=s.split(".")[0];Ft.test(a)&&(o=a)}e.setTimeout(3e4,()=>{e.destroy()}),e.on("error",a=>{a.code!=="ECONNRESET"&&console.warn(`[DoT] Socket error from ${n}:`,a.message)});let c=65537;e.on("data",async a=>{if(r.length+a.length>c){e.destroy();return}for(r=ao.concat([r,a]);r.length>=2;){let l=r.readUInt16BE(0);if(r.length<2+l)break;let d=r.subarray(2,2+l);r=r.subarray(2+l),await this.processQuery(e,d,n,o)}})}async processQuery(e,n,r,s){try{let o=dn(n);if(!o)return;let i=this.options.env,c={waitUntil(p){p.catch(m=>console.error("[DoT Background Task Error]:",m))},passThroughOnException(){}};if(!s){e.destroy();return}let a=await Un(s,i,c);if(!a){e.destroy();return}let l={profileId:a.id,accessPointId:a.access_point_id,accessPointName:a.access_point_name,startTime:Date.now(),env:i,ctx:c},d=r.includes(":")?`[${r}]`:r,u=new Request(`http://${d}/dns-query`,{headers:{"CF-Connecting-IP":r,Accept:"application/dns-message","Content-Type":"application/dns-message"}}),f=await de.process(u,o,l);if(!f||!f.answer||f.answer.length===0)return;if(!e.destroyed&&e.writable){let p=f.answer,m=ao.allocUnsafe(2+p.length);m.writeUInt16BE(p.length,0),m.set(p,2),e.write(m)}}catch(o){console.error("[DoT] Query processing exception:",o);try{let i=this.options.env.FAIL_OPEN_UPSTREAM||"https://freedns.controld.com/no-ads-malware-typo",c=_t(i),a=await St(c,n);if(!e.destroyed&&e.writable){let l=a.answer,d=ao.allocUnsafe(2+l.length);d.writeUInt16BE(l.length,0),d.set(l,2),e.write(d)}}catch(i){console.error("[DoT] Fail-open upstream fallback failed:",i)}}}stop(){return new Promise(e=>{this.server&&this.isRunning?this.server.close(()=>{this.isRunning=!1,console.log("[DoT] Service stopped."),e()}):e()})}};import Nu from"node:http";import Iu from"node:https";import Ir from"node:fs";import go from"node:path";import{Buffer as wl}from"node:buffer";pe();function Oc(t,e){return`#!/bin/bash
365
+ `}var po=class{constructor(e){this.options=e}options;socket=null;isRunning=!1;start(){return new Promise((e,t)=>{try{this.socket=Lu.createSocket("udp4");let r=s=>{try{this.socket?.close()}catch{}this.socket=null,console.error(sn({serviceName:"UDP DNS",protocol:"UDP",port:this.options.port,err:s,alternateOption:"--dns-port <port> (e.g. --dns-port 5353)",disableOption:"--disable-udp"})),t(s)};this.socket.once("error",r),this.socket.on("message",async(s,o)=>{await this.handleMessage(s,o)}),this.socket.bind(this.options.port,this.options.host,()=>{this.socket?.removeListener("error",r),this.socket?.on("error",s=>{console.error("[UDP DNS] Socket runtime error:",s)});try{this.socket?.setRecvBufferSize(4*1024*1024),this.socket?.setSendBufferSize(4*1024*1024)}catch{}this.isRunning=!0,console.log(`[UDP DNS] Classic DNS listening on udp://${this.options.host}:${this.options.port}`),e()})}catch(r){t(r)}})}async handleMessage(e,t){try{let r=new Uint8Array(e.buffer,e.byteOffset,e.byteLength),s=gn(r);if(!s)return;let o=this.options.env,i={waitUntil(p){p.catch(m=>console.error("[UDP Background Task Error]:",m))},passThroughOnException(){}},c=null;if(this.options.defaultProfileKey&&(c=await Kn(this.options.defaultProfileKey,o,i)),c||(c=await Ic(o,i)),!c)return;let a={profileId:c.id,accessPointId:c.access_point_id,accessPointName:c.access_point_name,startTime:Date.now(),env:o,ctx:i},l=t.address.includes(":")?`[${t.address}]`:t.address,d=new Request(`http://${l}/dns-query`,{headers:{"CF-Connecting-IP":t.address,Accept:"application/dns-message","Content-Type":"application/dns-message"}}),u=await de.process(d,s,a);if(!u||!u.answer||u.answer.length===0)return;let f=u.answer;if(f.length>512){let p=new Uint8Array(f);p[2]|=2,f=p.slice(0,512)}this.socket?.send(f,t.port,t.address,p=>{p&&console.warn(`[UDP DNS] Failed to send answer to ${t.address}:${t.port}:`,p.message)})}catch(r){console.error("[UDP DNS] Message handling exception:",r);try{let s=this.options.env.FAIL_OPEN_UPSTREAM||"https://freedns.controld.com/no-ads-malware-typo",o=new Uint8Array(e.buffer,e.byteOffset,e.byteLength),i=Tt(s),a=(await xt(i,o)).answer;if(a.length>512){let l=new Uint8Array(a);l[2]|=2,a=l.slice(0,512)}this.socket?.send(a,t.port,t.address)}catch(s){console.error("[UDP DNS] Fail-open upstream fallback failed:",s)}}}stop(){return new Promise(e=>{this.socket&&this.isRunning?this.socket.close(()=>{this.isRunning=!1,console.log("[UDP DNS] Service stopped."),e()}):e()})}};import fo from"node:fs";import Nu from"node:tls";import{Buffer as mo}from"node:buffer";import Br from"node:fs";import Ou from"node:crypto";function jn(n,e){if(!!!(n&&e))return{configured:!1,filesExist:!1,certPath:n||"",keyPath:e||"",isWildcard:!1,domains:[],expiresAt:null};let r=!1,s=!1,o;try{Br.accessSync(n,Br.constants.R_OK),r=!0}catch(c){let a=c?.code,l=c instanceof Error?c.message:String(c);a==="EACCES"?o=`Permission denied (EACCES) reading certPath: ${n}`:a==="ENOENT"?o=`Certificate file not found: ${n}`:o=`Cannot read certPath (${n}): ${l}`}try{Br.accessSync(e,Br.constants.R_OK),s=!0}catch(c){let a=c?.code,l=c instanceof Error?c.message:String(c),d=a==="EACCES"?`Permission denied (EACCES) reading keyPath: ${e}`:a==="ENOENT"?`Private key file not found: ${e}`:`Cannot read keyPath (${e}): ${l}`;o=o?`${o}; ${d}`:d}if(!(r&&s))return{configured:!0,filesExist:!1,certPath:n,keyPath:e,isWildcard:!1,domains:[],expiresAt:null,error:o};try{let c=Br.readFileSync(n,"utf-8"),a=new Ou.X509Certificate(c),l=[],d=!1;if(a.subjectAltName){let f=a.subjectAltName.split(",").map(p=>p.trim());for(let p of f)if(p.startsWith("DNS:")){let m=p.slice(4).trim().toLowerCase();l.includes(m)||l.push(m),m.startsWith("*.")&&(d=!0)}}if(a.subject){let f=a.subject.match(/CN=([^,\n\/]+)/i);if(f){let p=f[1].trim().toLowerCase();l.includes(p)||l.push(p),p.startsWith("*.")&&(d=!0)}}let u=new Date(a.validTo);return{configured:!0,filesExist:!0,certPath:n,keyPath:e,isWildcard:d,domains:l,expiresAt:u}}catch(c){let a=c instanceof Error?c.message:String(c);return{configured:!0,filesExist:!0,certPath:n,keyPath:e,isWildcard:!1,domains:[],expiresAt:null,error:a}}}function Fr(n){let e=n?n.replace(/^\*\./,"").trim():"your.domain";return`certbot certonly -d *.${e} -d ${e} --manual --preferred-challenges dns`}function Di(n,e){let t=Fr(e);return n==="missing"?{level:"warning",title:"TLS Certificate Not Configured / Missing",message:"No valid TLS certificate detected. HTTPS Web UI (port 10443) and DoT (port 853) are disabled.",details:["Plain HTTP Web UI (port 10080) and Classic UDP DNS (port 53) remain fully operational."],solutions:["To enable HTTPS and DoT with per-profile routing, register a free wildcard certificate using certbot:",` ${t}`,"Then configure SERVERFULL_TLS_CERT_PATH and SERVERFULL_TLS_KEY_PATH in your .env file."]}:{level:"warning",title:"Non-Wildcard TLS Certificate Detected (DoT Paused)",message:"The current certificate does not cover wildcard subdomains (*.domain). DoT (DNS over TLS / DoQ) is paused until a valid wildcard certificate is installed.",details:["DoT requires a wildcard certificate (*.domain) to securely route queries to specific profiles via TLS SNI (<profileKey>.your.domain).","The policy allowing access to Default Profile without a wildcard certificate has been disabled."],solutions:["You can register a wildcard certificate using Certbot via DNS challenge:",` ${t}`,"Then update SERVERFULL_TLS_CERT_PATH and SERVERFULL_TLS_KEY_PATH to resume DoT service."]}}var ho=class{constructor(e){this.options=e}options;server=null;isRunning=!1;start(){return new Promise((e,t)=>{let{tlsKeyPath:r,tlsCertPath:s,port:o,host:i}=this.options;if(!r||!s){console.warn(O({level:"warning",title:"DoT - TLS Not Configured",message:"TLS key or certificate path not provided. Skipping DoT server startup.",solutions:["Set SERVERFULL_TLS_KEY_PATH and SERVERFULL_TLS_CERT_PATH to enable DNS over TLS (DoT)."]})),e();return}if(!fo.existsSync(r)||!fo.existsSync(s)){console.warn(O({level:"warning",title:"DoT - TLS Files Missing",message:"Configured TLS key or certificate files were not found on disk. Skipping DoT server startup.",details:[`Key path : ${r}`,`Cert path : ${s}`],solutions:["Verify the file paths or generate TLS certificates before enabling DoT."]})),e();return}if(!jn(s,r).isWildcard){console.warn(O({level:"warning",title:"DoT - Paused (No Wildcard Certificate)",message:"DNS over TLS (DoT) is paused because no valid wildcard certificate (*.domain) was detected.",details:["DoT requires a wildcard certificate (*.domain) to securely route queries to specific profiles via TLS SNI (<profileKey>.your.domain).","Accessing default profile without a wildcard certificate has been disabled."],solutions:["Register a wildcard certificate using Certbot via DNS challenge:",` ${Fr(this.options.dotDomain)}`,"Install the wildcard certificate and restart dns-worker to resume DoT service."]})),e();return}try{let a={key:fo.readFileSync(r),cert:fo.readFileSync(s),ALPNProtocols:["dot"],sessionIdContext:"dns-worker-dot"};this.server=Nu.createServer(a,d=>{this.handleConnection(d)});let l=d=>{this.server=null,console.error(sn({serviceName:"DNS over TLS (DoT)",protocol:"DoT",port:o,err:d,alternateOption:"--dot-port <port> (e.g. --dot-port 8853)",disableOption:"--disable-dot"})),t(d)};this.server.once("error",l),this.server.listen(o,i,()=>{this.server?.removeListener("error",l),this.server?.on("error",u=>{console.error("[DoT] Runtime error:",u)}),this.isRunning=!0;let d=this.options.dotDomain?` (${this.options.dotDomain})`:"";console.log(`[DoT] DNS over TLS listening on tls://${i}:${o}${d}`),e()})}catch(a){console.error("[DoT] Failed to initialize TLS server:",a),t(a)}})}handleConnection(e){e.setNoDelay(!0),e.setKeepAlive(!0,6e4);let t=e.remoteAddress?.replace(/^::ffff:/,"")||"127.0.0.1",r=mo.alloc(0),s=(e.servername||"").toLowerCase().trim(),o="",i=this.options.dotDomain?.toLowerCase().trim().replace(/^\*\./,"");if(i&&s){if(s===i)o="";else if(s.endsWith("."+i)){let a=s.slice(0,-(i.length+1)),l=a.split(".")[0];Wt.test(l)?o=l:Wt.test(a)&&(o=a)}}if(!o&&s){let a=s.split(".")[0];Wt.test(a)&&(o=a)}e.setTimeout(3e4,()=>{e.destroy()}),e.on("error",a=>{a.code!=="ECONNRESET"&&console.warn(`[DoT] Socket error from ${t}:`,a.message)});let c=65537;e.on("data",async a=>{if(r.length+a.length>c){e.destroy();return}for(r=mo.concat([r,a]);r.length>=2;){let l=r.readUInt16BE(0);if(r.length<2+l)break;let d=r.subarray(2,2+l);r=r.subarray(2+l),await this.processQuery(e,d,t,o)}})}async processQuery(e,t,r,s){try{let o=gn(t);if(!o)return;let i=this.options.env,c={waitUntil(p){p.catch(m=>console.error("[DoT Background Task Error]:",m))},passThroughOnException(){}};if(!s){e.destroy();return}let a=await Kn(s,i,c);if(!a){e.destroy();return}let l={profileId:a.id,accessPointId:a.access_point_id,accessPointName:a.access_point_name,startTime:Date.now(),env:i,ctx:c},d=r.includes(":")?`[${r}]`:r,u=new Request(`http://${d}/dns-query`,{headers:{"CF-Connecting-IP":r,Accept:"application/dns-message","Content-Type":"application/dns-message"}}),f=await de.process(u,o,l);if(!f||!f.answer||f.answer.length===0)return;if(!e.destroyed&&e.writable){let p=f.answer,m=mo.allocUnsafe(2+p.length);m.writeUInt16BE(p.length,0),m.set(p,2),e.write(m)}}catch(o){console.error("[DoT] Query processing exception:",o);try{let i=this.options.env.FAIL_OPEN_UPSTREAM||"https://freedns.controld.com/no-ads-malware-typo",c=Tt(i),a=await xt(c,t);if(!e.destroyed&&e.writable){let l=a.answer,d=mo.allocUnsafe(2+l.length);d.writeUInt16BE(l.length,0),d.set(l,2),e.write(d)}}catch(i){console.error("[DoT] Fail-open upstream fallback failed:",i)}}}stop(){return new Promise(e=>{this.server&&this.isRunning?this.server.close(()=>{this.isRunning=!1,console.log("[DoT] Service stopped."),e()}):e()})}};import Wu from"node:http";import ju from"node:https";import jr from"node:fs";import _o from"node:path";import{Buffer as xl}from"node:buffer";pe();function Fc(n,e){return`#!/bin/bash
366
366
  sudo curl -L 'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64' -o /usr/local/bin/cloudflared
367
367
  sudo chmod +x /usr/local/bin/cloudflared
368
368
  sudo tee /etc/systemd/system/cloudflared-dns.service > /dev/null <<EOF
@@ -372,7 +372,7 @@ After=network.target
372
372
 
373
373
  [Service]
374
374
  Type=simple
375
- ExecStart=/usr/local/bin/cloudflared proxy-dns --upstream ${t}/${e} --port 53
375
+ ExecStart=/usr/local/bin/cloudflared proxy-dns --upstream ${n}/${e} --port 53
376
376
  Restart=always
377
377
 
378
378
  [Install]
@@ -382,15 +382,15 @@ sudo systemctl daemon-reload
382
382
  sudo systemctl enable --now cloudflared-dns
383
383
  echo "DNS Worker DoH Proxy installed successfully."
384
384
  echo "Please change your system DNS to 127.0.0.1"
385
- `}Lr();async function Ic(t,e){let n=new URL(t.url),r=new Y(e.DB,e);if(n.pathname==="/api/auth/config"&&t.method==="GET"){let s=new he(e.DB),[o,i,c,a,l]=await Promise.all([s.get("turnstile_site_key"),s.get("turnstile_enabled_signup"),s.get("turnstile_enabled_login"),r.isEmpty().then(d=>!d).catch(()=>!1),s.get("registration_enabled")]);return new Response(JSON.stringify({turnstile_site_key:o,turnstile_enabled_signup:i==="true",turnstile_enabled_login:c==="true",optional_session_expiration_days:Number(e.OPTIONAL_SESSION_EXPIRATION_DAYS)||7,has_users:a,registration_enabled:l!=="false"}),{headers:{"Content-Type":"application/json","Cache-Control":a?"public, max-age=300, s-maxage=300":"no-store, no-cache"}})}if(n.pathname==="/api/auth/check-username"&&t.method==="GET"){let s=n.searchParams.get("username")||"";if(!Et.test(s))return new Response(JSON.stringify({error:"Invalid username"}),{status:400,headers:{"Content-Type":"application/json"}});let o=await r.getByUsername(s);return new Response(JSON.stringify({exists:!!o}),{headers:{"Content-Type":"application/json"}})}return new Response("Not Found",{status:404})}pe();Ue();Re();var oe=class{constructor(e){this.db=e}db;async record(e,n,r,s,o,i){try{let c=Math.floor(Date.now()/1e3);await this.db.prepare("INSERT INTO user_activity_log (user_id, action, ip_address, user_agent, timestamp, extra, session_id_hash) VALUES (?, ?, ?, ?, ?, ?, ?)").bind(e,n,r,s??null,c,o?JSON.stringify(o):null,i??null).run()}catch(c){console.error(`[ActivityLog] Failed to record '${n}' event for user ${e}:`,c?.message||c)}}async listByUser(e,n=20,r){let s=Math.min(n,50);if(r){let{results:i}=await this.db.prepare("SELECT * FROM user_activity_log WHERE user_id = ? AND timestamp < ? ORDER BY timestamp DESC LIMIT ?").bind(e,r,s).all();return i}let{results:o}=await this.db.prepare("SELECT * FROM user_activity_log WHERE user_id = ? ORDER BY timestamp DESC LIMIT ?").bind(e,s).all();return o}};var Pi="ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";function Au(t){let e="",n=0,r=0;for(let s of t)for(n=n<<8|s,r+=8;r>=5;)r-=5,e+=Pi[n>>r&31];return r>0&&(e+=Pi[n<<5-r&31]),e}function vu(t){let e=t.length;for(;e>0&&t[e-1]==="=";)e--;let n=t.slice(0,e).toUpperCase(),r=[],s=0,o=0;for(let i of n){let c=Pi.indexOf(i);c!==-1&&(s=s<<5|c,o+=5,o>=8&&(o-=8,r.push(s>>o&255)))}return new Uint8Array(r)}function Uc(){let t=new Uint8Array(20);return crypto.getRandomValues(t),Au(t)}async function Pu(t,e){let n=vu(t),r=new Uint8Array(8),s=new DataView(r.buffer);s.setUint32(4,e>>>0,!1),s.setUint32(0,Math.floor(e/4294967296)>>>0,!1);let o=await crypto.subtle.importKey("raw",n,{name:"HMAC",hash:"SHA-1"},!1,["sign"]),i=await crypto.subtle.sign("HMAC",o,r),c=new Uint8Array(i),a=c[c.length-1]&15;return(((c[a]&127)<<24|(c[a+1]&255)<<16|(c[a+2]&255)<<8|c[a+3]&255)%1e6).toString().padStart(6,"0")}async function Or(t,e,n){if(!t||!e)return{valid:!1};if(!n&&!Zi.test(e))return{valid:!1};try{let r=Math.floor(Date.now()/1e3/30);for(let s of[-1,0,1]){let o=r+s,i=await Pu(t,o);if(n){let c=new TextEncoder().encode(i+n),a=await crypto.subtle.digest("SHA-256",c);if(Array.from(new Uint8Array(a)).map(d=>d.toString(16).padStart(2,"0")).join("")===e)return{valid:!0,timeStep:o}}else if(i===e)return{valid:!0,timeStep:o}}}catch(r){return console.error("[TOTP Verification Error]:",r),{valid:!1}}return{valid:!1}}async function lo(t,e,n){return(await Or(t,e,n)).valid}function Mc(t,e,n){let r=encodeURIComponent(`${n}:${e}`),s=new URLSearchParams({secret:t,issuer:n,algorithm:"SHA1",digits:"6",period:"30"});return`otpauth://totp/${r}?${s.toString()}`}function Cu(){for(;;){let t=new Uint32Array(1);crypto.getRandomValues(t);let e=t[0]%1e5,n=e%11;if(n<10){let r=e.toString().padStart(5,"0"),s=n.toString();return`${r}${s}`}}}function tn(){let t=[];for(let e=0;e<5;e++)t.push(Cu());return t.join("-")}function uo(){return[tn()]}async function je(t){let e=t.replace(/[-\s]/g,"").toUpperCase().trim(),n=new TextEncoder().encode(e),r=await crypto.subtle.digest("SHA-256",n);return Array.from(new Uint8Array(r)).map(s=>s.toString(16).padStart(2,"0")).join("")}async function Hn(t,e){let n=await je(t),r=t.replace(/[-\s]/g,"").toUpperCase().trim();return e.findIndex(s=>{if(!s)return!1;if(typeof s=="string")return s===n?!0:s.replace(/[-\s]/g,"").toUpperCase().trim()===r;if(typeof s=="object"){if(s.hash&&s.hash===n)return!0;if(s.key)return String(s.key).replace(/[-\s]/g,"").toUpperCase().trim()===r}return!1})}ge();async function $n(t,e,n){if(!t||!e)return!1;try{let r=new URLSearchParams;return r.append("secret",e),r.append("response",t),r.append("remoteip",n),!!(await(await fetch("https://challenges.cloudflare.com/turnstile/v0/siteverify",{method:"POST",body:r,headers:{"Content-Type":"application/x-www-form-urlencoded"},signal:AbortSignal.timeout(5e3)})).json()).success}catch{return!1}}async function Bc(t,e){let n=new Y(e.DB,e),r=new oe(e.DB),s=typeof caches<"u"?caches.default:null,o=t.headers.get("CF-Connecting-IP")||"127.0.0.1",i=t.headers.get("User-Agent");if(t.headers.get("X-Password-Leaked")==="true"||t.headers.get("Exposed-Credential-Check")==="true")return new Response("password_leaked",{status:400});if(await P.isRateLimited(s,`signup:${o}`,10,60))return new Response("Too many attempts",{status:429});let{username:c,password:a,turnstileToken:l}=await t.json(),d=new he(e.DB),[u,f,p,m]=await Promise.all([d.get("turnstile_secret_key"),d.get("turnstile_enabled_signup"),d.get("registration_enabled"),n.isEmpty()]);if(!m&&p==="false")return new Response("registration_disabled",{status:403});if(f==="true"&&u&&!await $n(l,u,o))return new Response("Verification failed",{status:400});if(!Et.test(c))return new Response("Invalid username",{status:400});if(!a||!bt.test(a))return new Response("Password format error",{status:400});if(await n.getByUsername(c))return new Response("username_exists",{status:400});let{latitude:h,longitude:g}=mn(t);if(h===null||g===null)return new Response("geolocation_missing",{status:400});let w=gn(e.JWT_SECRET);if(w==="missing")return new Response("jwt_secret_missing",{status:400});if(w==="preset")return new Response("jwt_secret_preset",{status:400});let b;try{b=await Le(e.JWT_SECRET)}catch{return new Response("jwt_secret_invalid",{status:400})}let y=await et(a,2),E=j(15),S=t.cf?.timezone||t.headers.get("CF-Timezone")||null,x=m?"admin":"user",T=!1;try{await n.create({id:E,username:c,passwordHash:y,role:x,timezone:S,passwordVersion:2}),T=!0;let v=new q(e.DB),C=j(6),L=x==="admin"?7:1;await v.create({id:C,owner_id:E,name:"Default",settings:{upstream:["https://security.cloudflare-dns.com/dns-query"],ecs:{enabled:!0,use_client_ip:!0},log_retention_days:L,skip_log_on_pass:!1,default_policy:"ALLOW",best_effort_ech:{enabled:!1,fronting_domain:"cloudflare-ech.com"}}});let H=tn(),V=await je(H);await n.updateRecoveryKeys(E,[{hash:V}]);let{session:Q,refreshToken:Z}=await bn(e,E,o,i,h,g,!1),_e=await re(Q.id,E);await r.record(E,"signup",o,i,void 0,_e);let K=ht(Z,e,!1),Se=j(32),ie=tt(Se,e,!1),k=Number(e.ACCESS_TOKEN_EXPIRATION_MINUTES)||10,R=await yn({userId:E,role:x,sessionId:Q.id,exp:Math.floor(Date.now()/1e3)+k*60},b),A=new Headers;return A.append("Set-Cookie",K),A.append("Set-Cookie",ie),A.append("Content-Type","application/json"),new Response(JSON.stringify({success:!0,accessToken:R,recoveryKey:H}),{headers:A})}catch(v){if(T)try{await e.DB.prepare("DELETE FROM profiles WHERE owner_id = ?").bind(E).run(),await e.DB.prepare("DELETE FROM users WHERE id = ?").bind(E).run()}catch(C){console.error("Failed to clean up incomplete user registration:",C)}return new Response(v.message,{status:400})}}pe();Ue();Re();pe();var ae=class{constructor(e){this.db=e}db;async listByUser(e){let{results:n}=await this.db.prepare("SELECT * FROM passkeys WHERE user_id = ? ORDER BY created_at DESC").bind(e).all();return n}async getById(e,n){return await this.db.prepare("SELECT * FROM passkeys WHERE id = ? AND user_id = ?").bind(e,n).first()}async getByCredentialId(e){return await this.db.prepare("SELECT * FROM passkeys WHERE credential_id = ?").bind(e).first()}async getByIdOrCredentialId(e,n){let r=await this.db.prepare("SELECT * FROM passkeys WHERE (id = ? OR credential_id = ?) AND user_id = ?").bind(e,e,n).first();if(r)return r;let s=await this.listByUser(n),o=e.replace(/=/g,"").replace(/\+/g,"-").replace(/\//g,"_");return s.find(i=>{let c=i.credential_id.replace(/=/g,"").replace(/\+/g,"-").replace(/\//g,"_");return i.id===e||c===o})||null}async create(e){let n=j(12),r=Math.floor(Date.now()/1e3),s=e.transports?JSON.stringify(e.transports):null;return await this.db.prepare(`INSERT INTO passkeys (id, user_id, name, credential_id, public_key, algorithm, sign_count, transports, aaguid, created_at, last_used_at)
386
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).bind(n,e.userId,e.name,e.credentialId,e.publicKey,e.algorithm,e.signCount,s,e.aaguid||null,r,null).run(),{id:n,user_id:e.userId,name:e.name,credential_id:e.credentialId,public_key:e.publicKey,algorithm:e.algorithm,sign_count:e.signCount,transports:s,aaguid:e.aaguid||null,created_at:r,last_used_at:null}}async updateName(e,n,r){return(await this.db.prepare("UPDATE passkeys SET name = ? WHERE id = ? AND user_id = ?").bind(r,e,n).run()).success}async updateUsage(e,n){let r=Math.floor(Date.now()/1e3);return(await this.db.prepare("UPDATE passkeys SET sign_count = ?, last_used_at = ? WHERE id = ?").bind(n,r,e).run()).success}async delete(e,n){return(await this.db.prepare("DELETE FROM passkeys WHERE id = ? AND user_id = ?").bind(e,n).run()).success}async countByUser(e){return(await this.db.prepare("SELECT COUNT(*) as count FROM passkeys WHERE user_id = ?").bind(e).first())?.count||0}};ge();function at(t){let e=t instanceof Uint8Array?t:new Uint8Array(t),n="";for(let r=0;r<e.length;r++)n+=String.fromCharCode(e[r]);return btoa(n).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function kt(t){let e=t.replace(/-/g,"+").replace(/_/g,"/");for(;e.length%4!==0;)e+="=";let n=atob(e),r=new Uint8Array(n.length);for(let s=0;s<n.length;s++)r[s]=n.charCodeAt(s);return r}function nn(){let t=new Uint8Array(32);return crypto.getRandomValues(t),at(t)}function Fc(t){if(t[0]!==48){if(t.length===64)return t;throw new Error("Invalid ECDSA signature: expected ASN.1 SEQUENCE")}let e=2;if(t[1]&128&&(e=2+(t[1]&127)),t[e++]!==2)throw new Error("Expected INTEGER for r in signature");let n=t[e++],r=t.subarray(e,e+n);if(e+=n,t[e++]!==2)throw new Error("Expected INTEGER for s in signature");let s=t[e++],o=t.subarray(e,e+s);for(;r.length>32&&r[0]===0;)r=r.subarray(1);for(;o.length>32&&o[0]===0;)o=o.subarray(1);let i=new Uint8Array(64);return i.set(r,32-r.length),i.set(o,64-o.length),i}function Ci(t){let e=0;function n(o){if(o<24)return o;if(o===24)return t[e++];if(o===25){let i=t[e]<<8|t[e+1];return e+=2,i}if(o===26){let i=(t[e]<<24>>>0)+(t[e+1]<<16)+(t[e+2]<<8)+t[e+3];return e+=4,i}if(o===27){let i=BigInt((t[e]<<24>>>0)+(t[e+1]<<16)+(t[e+2]<<8)+t[e+3]),c=BigInt((t[e+4]<<24>>>0)+(t[e+5]<<16)+(t[e+6]<<8)+t[e+7]);return e+=8,i<<32n|c}throw new Error(`Unsupported CBOR uint info: ${o}`)}function r(){if(e>=t.length)throw new Error("Unexpected end of CBOR data");let o=t[e++],i=o>>5,c=o&31;switch(i){case 0:{let a=n(c);return typeof a=="bigint"?Number(a):a}case 1:{let a=n(c);return typeof a=="bigint"?Number(-1n-a):-1-Number(a)}case 2:{let a=Number(n(c)),l=t.subarray(e,e+a);return e+=a,l}case 3:{let a=Number(n(c)),l=t.subarray(e,e+a);return e+=a,new TextDecoder().decode(l)}case 4:{let a=Number(n(c)),l=[];for(let d=0;d<a;d++)l.push(r());return l}case 5:{let a=Number(n(c)),l={};for(let d=0;d<a;d++){let u=r(),f=r();l[u]=f}return l}case 7:return c===20?!1:c===21?!0:c===22?null:void 0;default:throw new Error(`Unsupported CBOR major type: ${i}`)}}return{value:r(),bytesRead:e}}async function Du(t){if(t.length<37)throw new Error("Invalid authenticatorData length");let e=t.subarray(0,32),n=t[32],r=(t[33]<<24>>>0)+(t[34]<<16)+(t[35]<<8)+t[36];if(!!!(n&64))throw new Error("Attestation does not contain attested credential data");let o=37,i=t.subarray(o,o+16);o+=16;let c=Array.from(i).map(h=>h.toString(16).padStart(2,"0")).join(""),a=t[o]<<8|t[o+1];o+=2;let l=t.subarray(o,o+a);o+=a;let d=at(l),u=t.subarray(o),{value:f}=Ci(u),p=f[3]??-7,m="";if(p===-7){let h=f[-2],g=f[-3];if(!h||!g||h.length!==32||g.length!==32)throw new Error("Invalid EC2 COSE public key components");let w=new Uint8Array(65);w[0]=4,w.set(h,1),w.set(g,33);let b=await crypto.subtle.importKey("raw",w,{name:"ECDSA",namedCurve:"P-256"},!0,["verify"]),y=await crypto.subtle.exportKey("spki",b);m=at(y)}else if(p===-257){let h=f[-1],g=f[-2];if(!h||!g)throw new Error("Invalid RSA COSE public key components");let w={kty:"RSA",n:at(h),e:at(g),alg:"RS256",ext:!0},b=await crypto.subtle.importKey("jwk",w,{name:"RSASSA-PKCS1-v1_5",hash:"SHA-256"},!0,["verify"]),y=await crypto.subtle.exportKey("spki",b);m=at(y)}else throw new Error(`Unsupported COSE algorithm: ${p}`);return{rpIdHash:e,flags:n,signCount:r,aaguid:c,credentialId:d,publicKeySpki:m,algorithm:p}}async function Hc(t){let{clientDataJSON:e,attestationObject:n,expectedChallenge:r,expectedOrigin:s,expectedRpId:o}=t,i=kt(e),c=JSON.parse(new TextDecoder().decode(i));if(c.type!=="webauthn.create")throw new Error(`Invalid clientData type: ${c.type}`);if(c.challenge!==r)throw new Error("WebAuthn challenge mismatch");let a=new URL(c.origin),l=s.includes("://")?new URL(s):new URL(`https://${s}`);if(a.origin.toLowerCase()!==l.origin.toLowerCase())throw new Error(`WebAuthn origin mismatch: expected ${l.origin}, received ${a.origin}`);if(!(a.hostname==="localhost"||a.hostname==="127.0.0.1")&&a.protocol!=="https:")throw new Error(`WebAuthn requires HTTPS origin, received: ${a.protocol}`);let u=kt(n),{value:f}=Ci(u);if(!f.authData)throw new Error("Missing authData in attestationObject");let p=await Du(f.authData),m=new Uint8Array(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(o)));for(let h=0;h<32;h++)if(p.rpIdHash[h]!==m[h])throw new Error("WebAuthn rpIdHash mismatch");if(!(p.flags&1))throw new Error("User Presence (UP) flag not set");return p}async function Kn(t){let{clientDataJSON:e,authenticatorData:n,signature:r,publicKeySpki:s,algorithm:o,expectedChallenge:i,expectedOrigin:c,expectedRpId:a,previousSignCount:l=0}=t,d=kt(e),u=JSON.parse(new TextDecoder().decode(d));if(u.type!=="webauthn.get")throw new Error(`Invalid clientData type: ${u.type}`);if(u.challenge!==i)throw new Error("WebAuthn challenge mismatch");let f=new URL(u.origin),p=c.includes("://")?new URL(c):new URL(`https://${c}`);if(f.origin.toLowerCase()!==p.origin.toLowerCase())throw new Error(`WebAuthn origin mismatch: expected ${p.origin}, received ${f.origin}`);if(!(f.hostname==="localhost"||f.hostname==="127.0.0.1")&&f.protocol!=="https:")throw new Error(`WebAuthn requires HTTPS origin, received: ${f.protocol}`);let h=kt(n);if(h.length<37)throw new Error("Invalid authenticatorData length");let g=h.subarray(0,32),w=h[32],b=(h[33]<<24>>>0)+(h[34]<<16)+(h[35]<<8)+h[36],y=new Uint8Array(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(a)));for(let T=0;T<32;T++)if(g[T]!==y[T])throw new Error("WebAuthn rpIdHash mismatch");if(!(w&1))throw new Error("User Presence flag (UP) was not set by authenticator");if(b>0&&l>0&&b<=l)throw new Error("Authenticator sign count is not strictly monotonic. Possible cloned authenticator detected.");let E=new Uint8Array(await crypto.subtle.digest("SHA-256",d)),_=new Uint8Array(h.length+E.length);_.set(h,0),_.set(E,h.length);let S=kt(r),x=kt(s);if(o===-7){let T=await crypto.subtle.importKey("spki",x,{name:"ECDSA",namedCurve:"P-256"},!1,["verify"]),v=Fc(S);if(!await crypto.subtle.verify({name:"ECDSA",hash:"SHA-256"},T,v,_))throw new Error("WebAuthn signature verification failed")}else if(o===-257){let T=await crypto.subtle.importKey("spki",x,{name:"RSASSA-PKCS1-v1_5",hash:"SHA-256"},!1,["verify"]);if(!await crypto.subtle.verify({name:"RSASSA-PKCS1-v1_5"},T,S,_))throw new Error("WebAuthn signature verification failed")}else throw new Error(`Unsupported public key algorithm: ${o}`);return{signCount:b}}async function $c(t,e){let n=new URL(t.url),r=new Y(e.DB,e),s=new oe(e.DB),o=caches.default,i=t.headers.get("CF-Connecting-IP")||"127.0.0.1",c=t.headers.get("User-Agent");if(n.pathname==="/api/auth/prelogin"&&t.method==="POST"){if(await P.isRateLimited(o,`login_fail:${i}`,10,900))return new Response("Too many attempts",{status:429});let{username:a,turnstileToken:l}=await t.json(),d=new he(e.DB),[u,f]=await Promise.all([d.get("turnstile_secret_key"),d.get("turnstile_enabled_login")]);if(f==="true"&&u&&!await $n(l,u,i))return new Response("Verification failed",{status:400});let p=await r.getByUsername(a);if(!p)return await r.isEmpty().catch(()=>!1)?new Response("no_users_registered",{status:404}):(await P.isRateLimited(o,`login_fail:${i}`,100,900),new Response("User not found",{status:404}));let m=await ps(e,p.id),h=as(m,e),g=!p.totp_skip_password,w=!!p.totp_enabled,b=p.password_version??1,E=await new ae(e.DB).listByUser(p.id),_=E.length>0,S=null,x=null;_&&(x=nn(),S={challenge:x,rpId:n.hostname,allowCredentials:E.map(L=>({id:L.credential_id,type:"public-key",transports:L.transports?JSON.parse(L.transports):void 0})),timeout:6e4,userVerification:"preferred"});let T=j(32),v=null;b===2&&p.hashed_password&&(v=os(p.hashed_password));let C=Number(e.PREAUTH_TTL_SECONDS)||300;return await P.set(o,`preauth_state:${m}`,{nonce:T,failedAttempts:0,passkeyChallenge:x,rpId:n.hostname},C),new Response(JSON.stringify({requires_password:g,requires_totp:w,has_passkey:_,passkey_options:S,password_version:b,nonce:T,serverSalt:v}),{headers:{"Set-Cookie":h,"Content-Type":"application/json"}})}if(n.pathname==="/api/auth/login"&&t.method==="POST"){if(t.headers.get("X-Password-Leaked")==="true"||t.headers.get("Exposed-Credential-Check")==="true")return new Response("password_leaked",{status:400});if(await P.isRateLimited(o,`login_fail:${i}`,10,900))return new Response("Too many login attempts",{status:429});let a=ls(t.headers.get("Cookie"));if(!a)return new Response("Pre-auth session missing or expired",{status:401});let l=await fs(e,a);if(!l)return new Response("Session expired, please start over",{status:401});let d=await P.get(o,`preauth_state:${a}`);if(!d)return await dr(e,a),new Response("Session expired, please start over",{status:401});let{nonce:u}=d,f=await r.getById(l);if(!f)return new Response("User not found",{status:404});let{password:p,totpTokenHash:m,totpSalt:h,recoveryKey:g,passkeyAssertion:w,keepLoggedIn:b}=await t.json(),y=!1,E=new ae(e.DB),_=await E.listByUser(l),S=_.length>0,x=!!f.totp_enabled,T=!!f.totp_recovery_keys,v=x||S,C=S&&!!w;if(!(!!f.totp_skip_password||C)){if(!p)return new Response("Password is required",{status:400});if((f.password_version??1)===2){let F=await is(f.hashed_password,u);if(p!==F){await P.isRateLimited(o,`login_fail:${i}`,100,900),await s.record(l,"login_fail",i,c,{reason:"wrong_password"});let N=await Xe(o,a,e);return N<=0?new Response("Invalid password",{status:400}):new Response(`Invalid password. ${N} attempt${N>1?"s":""} remaining.`,{status:400})}}else{if(!await mt(p,f.hashed_password,1)){await P.isRateLimited(o,`login_fail:${i}`,100,900),await s.record(l,"login_fail",i,c,{reason:"wrong_password"});let N=await Xe(o,a,e);return N<=0?new Response("Invalid password",{status:400}):new Response(`Invalid password. ${N} attempt${N>1?"s":""} remaining.`,{status:400})}y=!0}}let H=!1,V=!1,Q=!1,Z=0,_e;if(v)if(w&&d.passkeyChallenge){let F=w.id,N=_.find(W=>W.credential_id===F);if(!N){await s.record(l,"passkey_verify_fail",i,c,{reason:"credential_not_found"});let W=await Xe(o,a,e);return W<=0?new Response("Invalid Passkey",{status:400}):new Response(`Invalid Passkey. ${W} attempt${W>1?"s":""} remaining.`,{status:400})}try{let{signCount:W}=await Kn({clientDataJSON:w.response.clientDataJSON,authenticatorData:w.response.authenticatorData,signature:w.response.signature,publicKeySpki:N.public_key,algorithm:N.algorithm,expectedChallenge:d.passkeyChallenge,expectedOrigin:`${n.protocol}//${n.host}`,expectedRpId:d.rpId||n.hostname,previousSignCount:N.sign_count});await E.updateUsage(N.id,W),Q=!0}catch(W){console.warn("[Passkey Login] Verification failed:",W.message||W),await s.record(l,"passkey_verify_fail",i,c,{reason:W.message});let J=await Xe(o,a,e);return J<=0?new Response("Invalid Passkey signature",{status:400}):new Response(`Invalid Passkey signature. ${J} attempt${J>1?"s":""} remaining.`,{status:400})}}else if((x||S||T)&&g){let F=[];try{let te=f.totp_recovery_keys;F=typeof te=="string"?JSON.parse(te||"[]"):te||[],Array.isArray(F)||(F=[F])}catch{}if(await Hn(g,F)===-1){await s.record(l,"totp_verify_fail",i,c,{method:"recovery_key"});let te=await Xe(o,a,e);return te<=0?new Response("Invalid recovery key",{status:400}):new Response(`Invalid recovery key. ${te} attempt${te>1?"s":""} remaining.`,{status:400})}let W=tn(),J=await je(W);await r.updateRecoveryKeys(l,[{hash:J}]),_e=W,V=!0,Z=1}else if(x&&m){let F=await Or(f.totp_secret||"",m,h);if(!F.valid){await s.record(l,"totp_verify_fail",i,c);let N=await Xe(o,a,e);return N<=0?new Response("Invalid TOTP code",{status:400}):new Response(`Invalid TOTP code. ${N} attempt${N>1?"s":""} remaining.`,{status:400})}if(F.timeStep!==void 0){let N=`totp_used:${l}:${F.timeStep}`;if(await P.get(o,N))return await s.record(l,"totp_verify_fail",i,c,{reason:"replay_blocked"}),new Response("TOTP code has already been used. Please wait for the next 30-second code.",{status:400});await P.set(o,N,1,90)}H=!0}else{let F=await Xe(o,a,e);return F<=0?new Response("Missing MFA verification",{status:400}):new Response(`Missing MFA verification (Passkey, TOTP code, or recovery key). ${F} attempt${F>1?"s":""} remaining.`,{status:400})}await dr(e,a),await P.delete(o,`preauth_state:${a}`),await P.delete(o,`ratelimit:login_fail:${i}`);let{latitude:K,longitude:Se}=mn(t);if(K===null||Se===null)return new Response("geolocation_missing",{status:400});let{session:ie,refreshToken:k}=await bn(e,l,i,c,K,Se,!!b),R=await re(ie.id,l);Q?await s.record(l,"passkey_verify_success",i,c,void 0,R):H?await s.record(l,"totp_verify_success",i,c,void 0,R):V&&await s.record(l,"recovery_key_used",i,c,{remaining:Z},R),await s.record(l,"login_success",i,c,void 0,R);let A=j(32),D=tt(A,e,!!b),O=await Me(e),I=await Le(O),U=Number(e.ACCESS_TOKEN_EXPIRATION_MINUTES)||10,$=await yn({userId:l,role:f.role,sessionId:ie.id,exp:Math.floor(Date.now()/1e3)+U*60},I),B=new Headers({"Content-Type":"application/json"});return B.append("Set-Cookie",ht(k,e,!!b)),B.append("Set-Cookie",D),B.append("Set-Cookie",cs()),new Response(JSON.stringify({success:!0,accessToken:$,needsMigration:y,rotatedRecoveryKey:_e}),{headers:B})}return new Response("Not Found",{status:404})}pe();Ue();ge();async function Kc(t,e){let n=caches.default,r=t.headers.get("CF-Connecting-IP")||"127.0.0.1",s=t.headers.get("User-Agent"),o=new oe(e.DB);if(await P.isRateLimited(n,`refresh_fail:${r}`,20,60))return new Response("Too many attempts",{status:429});let i=De(t.headers.get("Cookie"));if(!i)return new Response("Refresh token missing",{status:401});let{getRequestCoordinates:c}=await Promise.resolve().then(()=>(pe(),ur)),{latitude:a,longitude:l}=c(t),{session:d,user:u,newRefreshToken:f,reason:p}=await us(e,i,a,l);if(!d||!u||!f){if(u){let E=i?Ae(i):null,_=E?await re(E.sid,u.id):null;await o.record(u.id,"logout",r,s,{reason:p||"unknown"},_)}return await P.isRateLimited(n,`refresh_fail:${r}`,100,60),new Response(JSON.stringify({error:"Invalid refresh token",reason:p||"unknown"}),{status:401,headers:{"Set-Cookie":Ye(),"Content-Type":"application/json"}})}let m=await Me(e),h=await Le(m),g=Number(e.ACCESS_TOKEN_EXPIRATION_MINUTES)||10,w=await yn({userId:u.id,role:u.role,sessionId:d.id,exp:Math.floor(Date.now()/1e3)+g*60},h),b=new Headers({"Content-Type":"application/json"}),y=d.id.startsWith("k_");return b.append("Set-Cookie",ht(f,e,y)),new Response(JSON.stringify({success:!0,accessToken:w}),{headers:b})}pe();Ie();Lr();async function Wc(t,e){let n=t.headers.get("CF-Connecting-IP")||"127.0.0.1",r=t.headers.get("User-Agent"),s=new oe(e.DB),o=De(t.headers.get("Cookie"));if(o){let c=Ae(o);if(c){let l=await new le(e.DB).getSessionUserId(c.sid);if(await yt(e,c.sid),Fn(c.sid),l){let d=await re(c.sid,l);await s.record(l,"logout",n,r,{reason:"user_active"},d)}}}let i=new Headers({"Content-Type":"application/json"});return i.append("Set-Cookie",Ye()),i.append("Set-Cookie","csrf_token=; SameSite=Lax; Path=/; Max-Age=0; Secure"),new Response(JSON.stringify({success:!0}),{headers:i})}pe();Ue();Re();Ie();ge();Lr();async function ku(t,e){try{if(await mt(t,e))return!0}catch{}try{let n=atob(e),r=new Uint8Array(n.length);for(let s=0;s<n.length;s++)r[s]=n.charCodeAt(s);if(r.length===48){let s=r.slice(0,16),o=r.slice(16),i=Array.from(s).map(d=>d.toString(16).padStart(2,"0")).join(""),c=new TextEncoder().encode(t+i),a=await crypto.subtle.digest("SHA-256",c),l=new Uint8Array(a);if(l.length===o.length){let d=0;for(let u=0;u<l.length;u++)d|=l[u]^o[u];if(d===0)return!0}}}catch{}return!1}async function jc(t,e){let n=new URL(t.url),r=new Y(e.DB,e),s=new oe(e.DB),o=caches.default,i=t.headers.get("CF-Connecting-IP")||"127.0.0.1",c=t.headers.get("User-Agent");if(n.pathname==="/api/auth/unlock-session"&&t.method==="GET"){let a=t.headers.get("Authorization")||"",l="";if(a.startsWith("Bearer ")&&(l=a.slice(7)),!l)return new Response("Unauthorized",{status:401});try{let d=await Me(e),u=await Le(d),f=await wn(l,u);if(!f)return new Response("Unauthorized",{status:401});let p=await r.getById(f.userId),m=!!(p?.pin_hash&&!/^[a-f0-9]{64}$/.test(p.pin_hash)),h=j(32),g=`unlock_nonce:${f.sessionId}`;return await P.set(o,g,{nonce:h,isLegacy:m},300),new Response(JSON.stringify({nonce:h,legacy:m}),{headers:{"Content-Type":"application/json"}})}catch{return new Response("Unauthorized",{status:401})}}if(n.pathname==="/api/auth/unlock-session"&&t.method==="POST"){let a=t.headers.get("Authorization")||"",l="";if(a.startsWith("Bearer ")&&(l=a.slice(7)),!l)return new Response("Unauthorized",{status:401});try{let d=await Me(e),u=await Le(d),f=await wn(l,u);if(!f)return new Response("Unauthorized",{status:401});let{pinHash:p,nonce:m}=await t.json();if(!p)return new Response("Missing pinHash",{status:400});if(!m)return new Response("Missing nonce",{status:400});let h=new le(e.DB),g=await h.getSession(f.sessionId);if(!g)return new Response("Session not found",{status:401});let w=await r.getById(f.userId);if(!w||!w.pin_hash)return new Response("PIN not configured",{status:400});let b=`unlock_nonce:${f.sessionId}`,y=await P.get(o,b);if(!y?.nonce)return new Response("Challenge expired, please start over",{status:400});let E=y.nonce,_=!!y.isLegacy;if(await P.delete(o,b),m!==E)return new Response("Invalid nonce",{status:400});let S=`unlock_fail:${g.id}`,T=(await P.get(o,S))?.count||0,v=await re(g.id,f.userId),C=!1;if(_)C=await ku(p,w.pin_hash),C&&await r.updatePinHash(f.userId,p);else{let H=await Ji(w.pin_hash,E);if(p.length===H.length){let V=0;for(let Q=0;Q<p.length;Q++)V|=p.charCodeAt(Q)^H.charCodeAt(Q);C=V===0}}if(!C){let H=T+1;return H>=3?(await h.deleteSession(g.id),await P.delete(o,S),await s.record(f.userId,"pin_verify_fail",i,c,{reason:"too_many_attempts"},v),new Response(JSON.stringify({success:!1,error:"too_many_attempts"}),{status:401,headers:{"Content-Type":"application/json"}})):(await P.set(o,S,{count:H},900),await s.record(f.userId,"pin_verify_fail",i,c,{reason:"incorrect_pin",attempt:H},v),new Response(JSON.stringify({success:!1,error:"incorrect_pin",attemptsRemaining:3-H}),{status:400,headers:{"Content-Type":"application/json"}}))}let L=Math.floor(Date.now()/1e3);return await h.resumeSession(g.id,L),Fn(g.id),await P.delete(o,S),await s.record(f.userId,"pin_verify_success",i,c,void 0,v),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}catch(d){return console.error("Unlock session error:",d),new Response("Unauthorized",{status:401})}}if(n.pathname==="/api/auth/lock-session"&&t.method==="POST"){let a=t.headers.get("Authorization")||"",l="";if(a.startsWith("Bearer ")&&(l=a.slice(7)),!l)return new Response("Unauthorized",{status:401});try{let d=await Me(e),u=await Le(d),f=await wn(l,u);if(!f)return new Response("Unauthorized",{status:401});let p=new le(e.DB),m=await p.getSession(f.sessionId);return m?(await p.pauseSession(m.id),Fn(m.id),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})):new Response("Session not found",{status:401})}catch{return new Response("Unauthorized",{status:401})}}return new Response("Not Found",{status:404})}Ie();ge();Re();async function Vc(t,e){let n=new URL(t.url),r=n.pathname,s=new Y(e.DB,e),o=new oe(e.DB),i=caches.default,c=t.headers.get("CF-Connecting-IP")||"127.0.0.1",a=t.headers.get("User-Agent");if(r==="/api/auth/forgot-password/init"&&t.method==="POST"){if(await P.isRateLimited(i,`forgot_pw_ip:${c}`,10,600))return new Response("Too many attempts",{status:429});let{username:l,turnstileToken:d}=await t.json();if(!l)return new Response("Username is required",{status:400});let u=new he(e.DB),[f,p]=await Promise.all([u.get("turnstile_secret_key"),u.get("turnstile_enabled_login")]);if(p==="true"&&f&&!await $n(d,f,c))return new Response("Verification failed",{status:400});let m=await s.getByUsername(l);if(!m)return await P.isRateLimited(i,`forgot_pw_ip:${c}`,100,600),new Response("User not found",{status:404});let g=await new ae(e.DB).listByUser(m.id),w=g.length>0,b=!!m.totp_enabled&&(!!m.totp_secret||!!m.totp_secret_encrypted),y=!1,E=m.totp_recovery_keys;if(E)try{let v=typeof E=="string"?JSON.parse(E):E;y=Array.isArray(v)&&v.length>0}catch{y=typeof E=="string"&&E.length>0}else m.totp_recovery_keys_encrypted&&(y=!0);if(!w&&!b&&!y)return new Response(JSON.stringify({can_reset:!1,reason:"no_mfa_configured"}),{status:200,headers:{"Content-Type":"application/json"}});let _=null,S=null;w&&(_=nn(),S={challenge:_,rpId:n.hostname,allowCredentials:g.map(v=>({id:v.credential_id,type:"public-key",transports:v.transports?JSON.parse(v.transports):void 0})),timeout:6e4,userVerification:"preferred"});let x=j(32),T={userId:m.id,username:m.username,passkeyChallenge:_,rpId:n.hostname,failedAttempts:0};return await P.set(i,`forgot_pw_state:${x}`,T,300),new Response(JSON.stringify({can_reset:!0,recoveryToken:x,has_passkey:w,passkey_options:S,has_totp:b,has_recovery_keys:y}),{headers:{"Content-Type":"application/json"}})}if(r==="/api/auth/forgot-password/verify"&&t.method==="POST"){let{recoveryToken:l,passkeyAssertion:d,totpTokenHash:u,totpSalt:f,recoveryKey:p}=await t.json();if(!l)return new Response("Recovery token is required",{status:400});let m=`forgot_pw_state:${l}`,h=await P.get(i,m);if(!h)return new Response("Recovery session expired or invalid",{status:400});if(h.failedAttempts>=3)return await P.delete(i,m),new Response("Too many failed attempts. Please start over.",{status:429});let g=await s.getById(h.userId);if(!g)return await P.delete(i,m),new Response("User not found",{status:404});if(d&&h.passkeyChallenge){let y=new ae(e.DB),_=(await y.listByUser(g.id)).find(S=>S.credential_id===d.id);if(!_)return h.failedAttempts++,await P.set(i,m,h,300),new Response("Passkey not recognized",{status:400});try{let{signCount:S}=await Kn({clientDataJSON:d.response.clientDataJSON,authenticatorData:d.response.authenticatorData,signature:d.response.signature,publicKeySpki:_.public_key,algorithm:_.algorithm,expectedChallenge:h.passkeyChallenge,expectedOrigin:`${n.protocol}//${n.host}`,expectedRpId:h.rpId,previousSignCount:_.sign_count});await y.updateUsage(_.id,S),await o.record(g.id,"passkey_verify_success",c,a,{flow:"forgot_password"})}catch{return h.failedAttempts++,await P.set(i,m,h,300),new Response("Passkey verification failed",{status:400})}}else if(p){let y=[];try{let _=g.totp_recovery_keys;y=typeof _=="string"?JSON.parse(_||"[]"):_||[],Array.isArray(y)||(y=[y])}catch{}let E=await Hn(p,y);if(E===-1)return h.failedAttempts++,await P.set(i,m,h,300),new Response("Invalid recovery key",{status:400});await s.consumeRecoveryKey(g.id,E,y),await o.record(g.id,"recovery_key_used",c,a,{flow:"forgot_password",remaining:y.length-1})}else if(u&&g.totp_secret){let y=await Or(g.totp_secret,u,f);if(!y.valid)return h.failedAttempts++,await P.set(i,m,h,300),new Response("Invalid TOTP code",{status:400});if(y.timeStep!==void 0){let E=`totp_step:${g.id}:${y.timeStep}`;if(await P.get(i,E))return h.failedAttempts++,await P.set(i,m,h,300),new Response("TOTP code already used, please wait for next code",{status:400});await P.set(i,E,!0,180)}await o.record(g.id,"totp_verify_success",c,a,{flow:"forgot_password"})}else return new Response("No valid MFA credential provided",{status:400});await P.delete(i,m);let w=j(32),b={userId:g.id,username:g.username};return await P.set(i,`forgot_pw_reset:${w}`,b,300),new Response(JSON.stringify({success:!0,resetToken:w}),{headers:{"Content-Type":"application/json"}})}if(r==="/api/auth/forgot-password/reset"&&t.method==="POST"){let{resetToken:l,newPassword:d}=await t.json();if(!l||!d)return new Response("Reset token and new password are required",{status:400});if(!bt.test(d))return new Response("Password format error",{status:400});let u=`forgot_pw_reset:${l}`,f=await P.get(i,u);if(!f)return new Response("Reset token expired or invalid",{status:400});await P.delete(i,u);let p=await s.getById(f.userId);if(!p)return new Response("User not found",{status:404});let m=await et(d,2);return await s.updatePassword(p.id,m,2),await new le(e.DB).deleteAllByUserId(p.id),await o.record(p.id,"password_change_success",c,a,{method:"forgot_password_reset"}),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}return new Response("Not Found",{status:404})}async function Jc(t,e){try{let r=new URL(t.url).pathname;return r==="/api/auth/config"||r==="/api/auth/check-username"?await Ic(t,e):r==="/api/auth/signup"?await Bc(t,e):r==="/api/auth/prelogin"||r==="/api/auth/login"?await $c(t,e):r==="/api/auth/refresh"?await Kc(t,e):r==="/api/auth/logout"?await Wc(t,e):r.startsWith("/api/auth/forgot-password")?await Vc(t,e):r==="/api/auth/unlock-session"||r==="/api/auth/lock-session"?await jc(t,e):new Response("Not Found",{status:404})}catch(n){return console.error("[Auth API] Unhandled Error:",n.message||n),new Response(n.message||"Internal Server Error",{status:500,headers:{"Content-Type":"text/plain; charset=utf-8"}})}}var Wn=class{static isAdmin(e){return e.role==="admin"}static canAccessProfile(e,n){return n.owner_id===e.id}};pe();async function Gc(t,e,n,r){let s=new q(e.DB);if(t.method==="GET"){let o=await s.listByOwner(n.id);return new Response(JSON.stringify(o),{headers:{"Content-Type":"application/json"}})}if(t.method==="POST"){let o=await t.json();if(!o.name||!Vo.test(o.name))return new Response("Invalid Profile Name format",{status:400});let i=await s.listByOwner(n.id),c=Number(e.MAX_PROFILES_PER_USER)||10;if(i.length>=c)return new Response(`Profile limit exceeded (max ${c})`,{status:400});if(i.find(g=>g.name===o.name))return new Response("The profile name already exists",{status:400});let l=j(6),d=e.MAX_LOG_RETENTION_DAYS!==void 0&&e.MAX_LOG_RETENTION_DAYS!==""?Number(e.MAX_LOG_RETENTION_DAYS):30,u=e.DEFAULT_LOG_RETENTION_DAYS!==void 0&&e.DEFAULT_LOG_RETENTION_DAYS!==""?Math.min(Number(e.DEFAULT_LOG_RETENTION_DAYS),d):Math.min(7,d),f=e.NORMAL_USER_MAX_LOG_RETENTION_DAYS!==void 0&&e.NORMAL_USER_MAX_LOG_RETENTION_DAYS!==""?Math.min(Number(e.NORMAL_USER_MAX_LOG_RETENTION_DAYS),d):Math.min(7,d),p=e.NORMAL_USER_DEFAULT_LOG_RETENTION_DAYS!==void 0&&e.NORMAL_USER_DEFAULT_LOG_RETENTION_DAYS!==""?Math.min(Number(e.NORMAL_USER_DEFAULT_LOG_RETENTION_DAYS),f):Math.min(1,f),m=n?.role==="admin"?u:p,h={upstream:["https://security.cloudflare-dns.com/dns-query"],ecs:{enabled:!0,use_client_ip:!0},log_retention_days:m,skip_log_on_pass:!1,default_policy:"ALLOW",best_effort_ech:{enabled:!1,fronting_domain:"cloudflare-ech.com"}};await s.create({id:l,owner_id:n.id,name:o.name||"Unnamed Profile",settings:h});try{let g=await e.DB.prepare("SELECT public_key, is_active FROM user_log_keys WHERE profile_id IN (SELECT id FROM profiles WHERE owner_id = ?) LIMIT 1").bind(n.id).first();if(g?.public_key){let w=Math.floor(Date.now()/1e3);await e.DB.prepare("INSERT INTO user_log_keys (profile_id, public_key, created_at, is_active) VALUES (?, ?, ?, ?)").bind(l,g.public_key,w,g.is_active??1).run();let b=await e.DB.prepare("SELECT encrypted_sk, iv, salt FROM user_recovery_wrapped_keys WHERE profile_id IN (SELECT id FROM profiles WHERE owner_id = ?) LIMIT 1").bind(n.id).first();b&&await e.DB.prepare("INSERT INTO user_recovery_wrapped_keys (profile_id, encrypted_sk, iv, salt, created_at) VALUES (?, ?, ?, ?, ?)").bind(l,b.encrypted_sk,b.iv,b.salt,w).run()}}catch(g){console.error("[Profiles] Failed to inherit E2EE log key for new profile:",g)}return new Response(JSON.stringify({id:l}),{status:201})}return new Response("Method Not Allowed",{status:405})}async function Yc(t,e,n,r,s,o){let i=new q(e.DB),c=new Oe(e.DB),a=r.id;if(s.length===3){if(t.method==="DELETE")return await i.delete(a),new Response(null,{status:204});if(t.method==="PATCH"){let{name:l}=await t.json();return!l||!Vo.test(l)?new Response("Invalid Profile Name format",{status:400}):(await i.updateName(a,l),o.waitUntil(de.clearCache(a,!0,e)),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}}))}return t.method==="GET"?new Response(JSON.stringify(r),{headers:{"Content-Type":"application/json"}}):new Response("Method Not Allowed",{status:405})}if(s[3]==="rotate_key"&&t.method==="POST"){let l=j(12);return await i.rotateKey(a,l),o.waitUntil(de.clearCache(a,!1,e)),new Response(JSON.stringify({profile_key:l}),{headers:{"Content-Type":"application/json"}})}if(s[3]==="settings"&&t.method==="PATCH"){let l=await t.json(),d=e.MAX_LOG_RETENTION_DAYS!==void 0&&e.MAX_LOG_RETENTION_DAYS!==""?Number(e.MAX_LOG_RETENTION_DAYS):30,u=e.ADMIN_USER_MAX_LOG_RETENTION_DAYS!==void 0&&e.ADMIN_USER_MAX_LOG_RETENTION_DAYS!==""?Math.min(Number(e.ADMIN_USER_MAX_LOG_RETENTION_DAYS),d):d,f=e.NORMAL_USER_MAX_LOG_RETENTION_DAYS!==void 0&&e.NORMAL_USER_MAX_LOG_RETENTION_DAYS!==""?Math.min(Number(e.NORMAL_USER_MAX_LOG_RETENTION_DAYS),d):Math.min(7,d),p=n?.role==="admin"?u:f;if(l.log_retention_days!=null&&(l.log_retention_days=Math.min(Number(l.log_retention_days),p)),l.upstream&&Array.isArray(l.upstream))for(let w of l.upstream){let b=w.startsWith("https://"),y=w.startsWith("http://"),E=w.startsWith("tcp://"),_=w.startsWith("tls://"),S=w.startsWith("dot://"),x=w.startsWith("udp://"),T=w.startsWith("sdns://"),v=!w.includes("//")&&!w.startsWith("/");if(!b&&!y&&!E&&!_&&!S&&!x&&!T&&!v)return new Response("Invalid upstream URL format. Only HTTP(S), TCP, TLS (DoT), DNS Stamp (sdns://), or bare host[:port] are allowed.",{status:400});let C=v?`tcp://${w}`:w;if(!ze(C))return new Response("Invalid upstream URL. Private networks and localhosts are not allowed.",{status:400})}let m=await i.getById(a),h=30;try{let w=JSON.parse(m?.settings||"{}");w?.log_retention_days!=null&&(h=Number(w.log_retention_days))}catch{}await i.updateSettings(a,l);let g=l.log_retention_days;if(g!=null&&Number(g)<h)if(Number(g)===0)o.waitUntil((async()=>{try{await e.DB.prepare("DELETE FROM logs WHERE profile_id = ?").bind(a).run(),await c.kemKeys.cleanupProfileOrphans(a)}catch(w){console.error("[Profile] Failed to purge logs on retention disable:",w?.message||w)}})());else{let w=Math.floor(Date.now()/1e3-Number(g)*24*3600);o.waitUntil(c.cleanup(a,w))}return o.waitUntil(de.clearCache(a,!1,e)),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}if(s[3]==="test"&&t.method==="POST"){let{domain:l,type:d}=await t.json(),u=Ut(l,d),f=await de.process(t,{name:l,type:d,raw:u},{profileId:a,startTime:Date.now(),env:e,ctx:o});return new Response(JSON.stringify({action:f.action,reason:f.reason,answers:f.answer.length>0?Ce(f.answer):[],diagnostics:f.diagnostics,latency:f.latency,timings:f.timings,client_ip:t.headers.get("CF-Connecting-IP")||"127.0.0.1",geo_country:t.cf?.country||t.headers.get("CF-IPCountry")||"UNKNOWN",success:!0}),{headers:{"Content-Type":"application/json"}})}return new Response("Not Found",{status:404})}pe();var po=class{constructor(e){this.db=e}db;async getAccessPoints(e){let{results:n}=await this.db.prepare("SELECT * FROM access_points WHERE profile_id = ? ORDER BY created_at ASC").bind(e).all();return n}async addAccessPoint(e,n){let r=Math.floor(Date.now()/1e3),s=j(12),o=5;for(let i=0;i<o;i++){let c=Mt(5);try{return await this.db.prepare("INSERT INTO access_points (id, profile_id, name, token, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)").bind(s,e,n,c,r,r).run(),{id:s,profile_id:e,name:n,token:c,created_at:r,updated_at:r}}catch(a){if(i<o-1&&(String(a).includes("UNIQUE constraint failed")||String(a).includes("SQLITE_CONSTRAINT")))continue;throw a}}throw new Error("Failed to generate a unique access point token")}async updateAccessPointName(e,n,r){let s=Math.floor(Date.now()/1e3);return(await this.db.prepare("UPDATE access_points SET name = ?, updated_at = ? WHERE id = ? AND profile_id = ?").bind(r,s,e,n).run()).success}async rotateAccessPointToken(e,n){let r=Math.floor(Date.now()/1e3),s=5;for(let o=0;o<s;o++){let i=Mt(5);try{if(!(await this.db.prepare("UPDATE access_points SET token = ?, updated_at = ? WHERE id = ? AND profile_id = ?").bind(i,r,e,n).run()).success)throw new Error("Failed to update access point token");return i}catch(c){if(o<s-1&&(String(c).includes("UNIQUE constraint failed")||String(c).includes("SQLITE_CONSTRAINT")))continue;throw c}}throw new Error("Failed to generate a unique access point token")}async deleteAccessPoint(e,n){return(await this.db.prepare("DELETE FROM access_points WHERE id = ? AND profile_id = ?").bind(e,n).run()).success}};async function Xc(t,e,n,r,s,o){let i=new po(e.DB);if(t.method==="GET"){let c=await i.getAccessPoints(r);return new Response(JSON.stringify(c),{headers:{"Content-Type":"application/json"}})}if(t.method==="POST"){if(s.length===6&&s[5]==="rotate_token"){let u=s[4],f=await i.rotateAccessPointToken(u,r);return new Response(JSON.stringify({token:f}),{headers:{"Content-Type":"application/json"}})}let c=await t.json();if(!c.name)return new Response("Name is required",{status:400});if(!Wo.test(c.name))return new Response("Invalid Access Point name format",{status:400});let a=await i.getAccessPoints(r);if(a.some(u=>u.name.toLowerCase()===c.name.toLowerCase()))return new Response("Access Point name already exists",{status:400});let l=Number(e.MAX_ACCESS_POINTS_PER_PROFILE)||100;if(a.length>=l)return new Response(`Access point limit exceeded (max ${l})`,{status:400});let d=await i.addAccessPoint(r,c.name);return new Response(JSON.stringify(d),{status:201,headers:{"Content-Type":"application/json"}})}if(t.method==="PATCH"&&s.length===5){let c=s[4],a=await t.json();return a.name?Wo.test(a.name)?(await i.getAccessPoints(r)).some(d=>d.id!==c&&d.name.toLowerCase()===a.name.toLowerCase())?new Response("Access Point name already exists",{status:400}):(await i.updateAccessPointName(c,r,a.name),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})):new Response("Invalid Access Point name format",{status:400}):new Response("Name is required",{status:400})}if(t.method==="DELETE"&&s.length===5){let c=s[4];return await i.deleteAccessPoint(c,r),new Response(null,{status:204})}return new Response("Method Not Allowed",{status:405})}async function zc(t,e,n,r,s,o){let i=new En(e.DB);if(t.method==="GET"){let c=await i.getRules(r);return new Response(JSON.stringify(c),{headers:{"Content-Type":"application/json"}})}if(t.method==="POST"){let c=await t.json();if(Array.isArray(c)||c&&Array.isArray(c.rules)){let f=Array.isArray(c)?c:c.rules,p=new Set,m=[];for(let y of f){if(!y||typeof y.pattern!="string")continue;let E=y.pattern.trim().toLowerCase();if(!E||p.has(E))continue;p.add(E);let _=String(y.type||"BLOCK").toUpperCase();_!=="ALLOW"&&_!=="BLOCK"&&_!=="REDIRECT"||m.push({type:_,pattern:E,v_a:y.v_a||null,v_aaaa:y.v_aaaa||null,v_txt:y.v_txt||null,v_cname:y.v_cname||null,created_at:typeof y.created_at=="number"?y.created_at:void 0})}if(m.length===0)return new Response(JSON.stringify({count:0,message:"No valid rules provided"}),{status:200,headers:{"Content-Type":"application/json"}});let h=await i.getRules(r),g=new Set(h.map(y=>y.pattern.trim().toLowerCase())),w=m.filter(y=>!g.has(y.pattern)),b=0;return w.length>0&&(b=await i.addRulesBulk(r,w),o.waitUntil(de.clearCache(r,!1,e))),new Response(JSON.stringify({success:!0,count:b}),{status:201,headers:{"Content-Type":"application/json"}})}let l=c,d=l.pattern?l.pattern.trim():"";return d?await i.getRuleByPattern(r,d)?new Response("Rule for this domain already exists",{status:400}):(await i.addRule(r,l),o.waitUntil(de.clearCache(r,!1,e)),new Response(null,{status:201})):new Response("Domain pattern cannot be empty",{status:400})}if(t.method==="PUT"){let c=await t.json(),a=c.pattern?c.pattern.trim():"";return a?await i.getRuleByPatternExcludeId(r,a,c.id)?new Response("Rule for this domain already exists",{status:400}):(await i.updateRule(c.id,r,c),o.waitUntil(de.clearCache(r,!1,e)),new Response(null,{status:200})):new Response("Domain pattern cannot be empty",{status:400})}if(t.method==="DELETE"){let{id:c}=await t.json();return await i.deleteRule(c,r),o.waitUntil(de.clearCache(r,!1,e)),new Response(null,{status:204})}return new Response("Method Not Allowed",{status:405})}var Lt=class{constructor(e){this.db=e}db;async getLists(e){let{results:n}=await this.db.prepare("SELECT * FROM lists WHERE profile_id = ?").bind(e).all();return n}async addList(e,n){return(await this.db.prepare("INSERT INTO lists (profile_id, url) VALUES (?, ?)").bind(e,n).run()).success}async addListsBulk(e,n){if(!n||n.length===0)return 0;let r=n.map(o=>{let i=typeof o=="string"?o.trim():o.url.trim(),c=typeof o=="object"&&o.enabled!==void 0?o.enabled?1:0:1;return this.db.prepare("INSERT INTO lists (profile_id, url, enabled) VALUES (?, ?, ?)").bind(e,i,c)}),s=0;for(let o=0;o<r.length;o+=100){let i=r.slice(o,o+100),c=await this.db.batch(i);for(let a of c)a.success&&(s+=a.meta.changes||1)}return s}async setEnabled(e,n,r){return(await this.db.prepare("UPDATE lists SET enabled = ? WHERE id = ? AND profile_id = ?").bind(r?1:0,e,n).run()).success}async getListById(e,n){return await this.db.prepare("SELECT * FROM lists WHERE id = ? AND profile_id = ?").bind(e,n).first()}async deleteList(e,n){return(await this.db.prepare("DELETE FROM lists WHERE id = ? AND profile_id = ?").bind(e,n).run()).success}async updateListSyncStatus(e,n,r,s=null){return r!=null?(await this.db.prepare("UPDATE lists SET last_synced_at = ?, enabled = ?, sync_error = ? WHERE id = ?").bind(n,r,s,e).run()).success:(await this.db.prepare("UPDATE lists SET last_synced_at = ?, sync_error = ? WHERE id = ?").bind(n,s,e).run()).success}async resetListSyncStatus(e){return(await this.db.prepare("UPDATE lists SET last_synced_at = 0 WHERE profile_id = ?").bind(e).run()).success}};var Ot=class{constructor(e){this.db=e}db;async upsertListBloom(e,n,r){let s=new Uint8Array(n),o=[];o.push(this.db.prepare("DELETE FROM list_blooms WHERE list_id = ?").bind(e));let i=0;for(let a=0;a<s.length;a+=1572864){let l=s.slice(a,a+1572864).buffer;o.push(this.db.prepare("INSERT INTO list_blooms (list_id, chunk_index, bloom_filter_chunk, updated_at) VALUES (?, ?, ?, ?)").bind(e,i,l,r)),i++}return(await this.db.batch(o)).every(a=>a.success)}async hasListBloom(e){return!!await this.db.prepare("SELECT 1 AS present FROM list_blooms WHERE list_id = ? LIMIT 1").bind(e).first()}async getListBloom(e){let{results:n}=await this.db.prepare("SELECT bloom_filter_chunk FROM list_blooms WHERE list_id = ? ORDER BY chunk_index ASC").bind(e).all();if(!n||n.length===0)return null;let r=n.reduce((i,c)=>{let a=c.bloom_filter_chunk.byteLength??c.bloom_filter_chunk.length;return i+a},0),s=new Uint8Array(r),o=0;for(let i of n){let c=new Uint8Array(i.bloom_filter_chunk);s.set(c,o),o+=c.length}return s.buffer}async deleteListBloom(e){return(await this.db.prepare("DELETE FROM list_blooms WHERE list_id = ?").bind(e).run()).success}async getActiveListBloomsForProfile(e){let{results:n}=await this.db.prepare(`
385
+ `}Hr();async function $c(n,e){let t=new URL(n.url),r=new Y(e.DB,e);if(t.pathname==="/api/auth/config"&&n.method==="GET"){let s=new he(e.DB),[o,i,c,a,l]=await Promise.all([s.get("turnstile_site_key"),s.get("turnstile_enabled_signup"),s.get("turnstile_enabled_login"),r.isEmpty().then(d=>!d).catch(()=>!1),s.get("registration_enabled")]);return new Response(JSON.stringify({turnstile_site_key:o,turnstile_enabled_signup:i==="true",turnstile_enabled_login:c==="true",optional_session_expiration_days:Number(e.OPTIONAL_SESSION_EXPIRATION_DAYS)||7,has_users:a,registration_enabled:l!=="false"}),{headers:{"Content-Type":"application/json","Cache-Control":a?"public, max-age=300, s-maxage=300":"no-store, no-cache"}})}if(t.pathname==="/api/auth/check-username"&&n.method==="GET"){let s=t.searchParams.get("username")||"";if(!Rt.test(s))return new Response(JSON.stringify({error:"Invalid username"}),{status:400,headers:{"Content-Type":"application/json"}});let o=await r.getByUsername(s);return new Response(JSON.stringify({exists:!!o}),{headers:{"Content-Type":"application/json"}})}return new Response("Not Found",{status:404})}pe();Fe();Te();var oe=class{constructor(e){this.db=e}db;async record(e,t,r,s,o,i){try{let c=Math.floor(Date.now()/1e3);await this.db.prepare("INSERT INTO user_activity_log (user_id, action, ip_address, user_agent, timestamp, extra, session_id_hash) VALUES (?, ?, ?, ?, ?, ?, ?)").bind(e,t,r,s??null,c,o?JSON.stringify(o):null,i??null).run()}catch(c){console.error(`[ActivityLog] Failed to record '${t}' event for user ${e}:`,c?.message||c)}}async listByUser(e,t=20,r){let s=Math.min(t,50);if(r){let{results:i}=await this.db.prepare("SELECT * FROM user_activity_log WHERE user_id = ? AND timestamp < ? ORDER BY timestamp DESC LIMIT ?").bind(e,r,s).all();return i}let{results:o}=await this.db.prepare("SELECT * FROM user_activity_log WHERE user_id = ? ORDER BY timestamp DESC LIMIT ?").bind(e,s).all();return o}};var Ni="ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";function Iu(n){let e="",t=0,r=0;for(let s of n)for(t=t<<8|s,r+=8;r>=5;)r-=5,e+=Ni[t>>r&31];return r>0&&(e+=Ni[t<<5-r&31]),e}function Uu(n){let e=n.length;for(;e>0&&n[e-1]==="=";)e--;let t=n.slice(0,e).toUpperCase(),r=[],s=0,o=0;for(let i of t){let c=Ni.indexOf(i);c!==-1&&(s=s<<5|c,o+=5,o>=8&&(o-=8,r.push(s>>o&255)))}return new Uint8Array(r)}function Kc(){let n=new Uint8Array(20);return crypto.getRandomValues(n),Iu(n)}async function Mu(n,e){let t=Uu(n),r=new Uint8Array(8),s=new DataView(r.buffer);s.setUint32(4,e>>>0,!1),s.setUint32(0,Math.floor(e/4294967296)>>>0,!1);let o=await crypto.subtle.importKey("raw",t,{name:"HMAC",hash:"SHA-1"},!1,["sign"]),i=await crypto.subtle.sign("HMAC",o,r),c=new Uint8Array(i),a=c[c.length-1]&15;return(((c[a]&127)<<24|(c[a+1]&255)<<16|(c[a+2]&255)<<8|c[a+3]&255)%1e6).toString().padStart(6,"0")}async function $r(n,e,t){if(!n||!e)return{valid:!1};if(!t&&!sa.test(e))return{valid:!1};try{let r=Math.floor(Date.now()/1e3/30);for(let s of[-1,0,1]){let o=r+s,i=await Mu(n,o);if(t){let c=new TextEncoder().encode(i+t),a=await crypto.subtle.digest("SHA-256",c);if(Array.from(new Uint8Array(a)).map(d=>d.toString(16).padStart(2,"0")).join("")===e)return{valid:!0,timeStep:o}}else if(i===e)return{valid:!0,timeStep:o}}}catch(r){return console.error("[TOTP Verification Error]:",r),{valid:!1}}return{valid:!1}}async function Kr(n,e,t){return(await $r(n,e,t)).valid}function Wc(n,e,t){let r=encodeURIComponent(`${t}:${e}`),s=new URLSearchParams({secret:n,issuer:t,algorithm:"SHA1",digits:"6",period:"30"});return`otpauth://totp/${r}?${s.toString()}`}function Bu(){for(;;){let n=new Uint32Array(1);crypto.getRandomValues(n);let e=n[0]%1e5,t=e%11;if(t<10){let r=e.toString().padStart(5,"0"),s=t.toString();return`${r}${s}`}}}function an(){let n=[];for(let e=0;e<5;e++)n.push(Bu());return n.join("-")}function go(){return[an()]}async function Ge(n){let e=n.replace(/[-\s]/g,"").toUpperCase().trim(),t=new TextEncoder().encode(e),r=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(r)).map(s=>s.toString(16).padStart(2,"0")).join("")}async function Gn(n,e){let t=await Ge(n),r=n.replace(/[-\s]/g,"").toUpperCase().trim();return e.findIndex(s=>{if(!s)return!1;if(typeof s=="string")return s===t?!0:s.replace(/[-\s]/g,"").toUpperCase().trim()===r;if(typeof s=="object"){if(s.hash&&s.hash===t)return!0;if(s.key)return String(s.key).replace(/[-\s]/g,"").toUpperCase().trim()===r}return!1})}ge();async function Jn(n,e,t){if(!n||!e)return!1;try{let r=new URLSearchParams;return r.append("secret",e),r.append("response",n),r.append("remoteip",t),!!(await(await fetch("https://challenges.cloudflare.com/turnstile/v0/siteverify",{method:"POST",body:r,headers:{"Content-Type":"application/x-www-form-urlencoded"},signal:AbortSignal.timeout(5e3)})).json()).success}catch{return!1}}async function jc(n,e){let t=new Y(e.DB,e),r=new oe(e.DB),s=typeof caches<"u"?caches.default:null,o=n.headers.get("CF-Connecting-IP")||"127.0.0.1",i=n.headers.get("User-Agent");if(n.headers.get("X-Password-Leaked")==="true"||n.headers.get("Exposed-Credential-Check")==="true")return new Response("password_leaked",{status:400});if(await P.isRateLimited(s,`signup:${o}`,10,60))return new Response("Too many attempts",{status:429});let{username:c,password:a,turnstileToken:l}=await n.json(),d=new he(e.DB),[u,f,p,m]=await Promise.all([d.get("turnstile_secret_key"),d.get("turnstile_enabled_signup"),d.get("registration_enabled"),t.isEmpty()]);if(!m&&p==="false")return new Response("registration_disabled",{status:403});if(f==="true"&&u&&!await Jn(l,u,o))return new Response("Verification failed",{status:400});if(!Rt.test(c))return new Response("Invalid username",{status:400});if(!a||!St.test(a))return new Response("Password format error",{status:400});if(await t.getByUsername(c))return new Response("username_exists",{status:400});let{latitude:h,longitude:g}=En(n);if(h===null||g===null)return new Response("geolocation_missing",{status:400});let b=Sn(e.JWT_SECRET);if(b==="missing")return new Response("jwt_secret_missing",{status:400});if(b==="preset")return new Response("jwt_secret_preset",{status:400});let w;try{w=await Ne(e.JWT_SECRET)}catch{return new Response("jwt_secret_invalid",{status:400})}let y=await ot(a,2),E=j(15),S=n.cf?.timezone||n.headers.get("CF-Timezone")||null,x=m?"admin":"user",T=!1;try{await t.create({id:E,username:c,passwordHash:y,role:x,timezone:S,passwordVersion:2}),T=!0;let v=new q(e.DB),C=j(6),L=x==="admin"?7:1;await v.create({id:C,owner_id:E,name:"Default",settings:{upstream:["https://security.cloudflare-dns.com/dns-query"],ecs:{enabled:!0,use_client_ip:!0},log_retention_days:L,skip_log_on_pass:!1,default_policy:"ALLOW",best_effort_ech:{enabled:!1,fronting_domain:"cloudflare-ech.com"}}});let H=an(),V=await Ge(H);await t.updateRecoveryKeys(E,[{hash:V}]);let{session:Q,refreshToken:Z}=await xn(e,E,o,i,h,g,!1),_e=await re(Q.id,E);await r.record(E,"signup",o,i,void 0,_e);let K=wt(Z,e,!1),Se=j(32),ie=it(Se,e,!1),k=Number(e.ACCESS_TOKEN_EXPIRATION_MINUTES)||10,R=await Rn({userId:E,role:x,sessionId:Q.id,exp:Math.floor(Date.now()/1e3)+k*60},w),A=new Headers;return A.append("Set-Cookie",K),A.append("Set-Cookie",ie),A.append("Content-Type","application/json"),new Response(JSON.stringify({success:!0,accessToken:R,recoveryKey:H}),{headers:A})}catch(v){if(T)try{await e.DB.prepare("DELETE FROM profiles WHERE owner_id = ?").bind(E).run(),await e.DB.prepare("DELETE FROM users WHERE id = ?").bind(E).run()}catch(C){console.error("Failed to clean up incomplete user registration:",C)}return new Response(v.message,{status:400})}}pe();Fe();Te();pe();var ae=class{constructor(e){this.db=e}db;async listByUser(e){let{results:t}=await this.db.prepare("SELECT * FROM passkeys WHERE user_id = ? ORDER BY created_at DESC").bind(e).all();return t}async getById(e,t){return await this.db.prepare("SELECT * FROM passkeys WHERE id = ? AND user_id = ?").bind(e,t).first()}async getByCredentialId(e){return await this.db.prepare("SELECT * FROM passkeys WHERE credential_id = ?").bind(e).first()}async getByIdOrCredentialId(e,t){let r=await this.db.prepare("SELECT * FROM passkeys WHERE (id = ? OR credential_id = ?) AND user_id = ?").bind(e,e,t).first();if(r)return r;let s=await this.listByUser(t),o=e.replace(/=/g,"").replace(/\+/g,"-").replace(/\//g,"_");return s.find(i=>{let c=i.credential_id.replace(/=/g,"").replace(/\+/g,"-").replace(/\//g,"_");return i.id===e||c===o})||null}async create(e){let t=j(12),r=Math.floor(Date.now()/1e3),s=e.transports?JSON.stringify(e.transports):null;return await this.db.prepare(`INSERT INTO passkeys (id, user_id, name, credential_id, public_key, algorithm, sign_count, transports, aaguid, created_at, last_used_at)
386
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).bind(t,e.userId,e.name,e.credentialId,e.publicKey,e.algorithm,e.signCount,s,e.aaguid||null,r,null).run(),{id:t,user_id:e.userId,name:e.name,credential_id:e.credentialId,public_key:e.publicKey,algorithm:e.algorithm,sign_count:e.signCount,transports:s,aaguid:e.aaguid||null,created_at:r,last_used_at:null}}async updateName(e,t,r){return(await this.db.prepare("UPDATE passkeys SET name = ? WHERE id = ? AND user_id = ?").bind(r,e,t).run()).success}async updateUsage(e,t){let r=Math.floor(Date.now()/1e3);return(await this.db.prepare("UPDATE passkeys SET sign_count = ?, last_used_at = ? WHERE id = ?").bind(t,r,e).run()).success}async delete(e,t){return(await this.db.prepare("DELETE FROM passkeys WHERE id = ? AND user_id = ?").bind(e,t).run()).success}async countByUser(e){return(await this.db.prepare("SELECT COUNT(*) as count FROM passkeys WHERE user_id = ?").bind(e).first())?.count||0}};ge();function ft(n){let e=n instanceof Uint8Array?n:new Uint8Array(n),t="";for(let r=0;r<e.length;r++)t+=String.fromCharCode(e[r]);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function Ot(n){let e=n.replace(/-/g,"+").replace(/_/g,"/");for(;e.length%4!==0;)e+="=";let t=atob(e),r=new Uint8Array(t.length);for(let s=0;s<t.length;s++)r[s]=t.charCodeAt(s);return r}function cn(){let n=new Uint8Array(32);return crypto.getRandomValues(n),ft(n)}function Vc(n){if(n[0]!==48){if(n.length===64)return n;throw new Error("Invalid ECDSA signature: expected ASN.1 SEQUENCE")}let e=2;if(n[1]&128&&(e=2+(n[1]&127)),n[e++]!==2)throw new Error("Expected INTEGER for r in signature");let t=n[e++],r=n.subarray(e,e+t);if(e+=t,n[e++]!==2)throw new Error("Expected INTEGER for s in signature");let s=n[e++],o=n.subarray(e,e+s);for(;r.length>32&&r[0]===0;)r=r.subarray(1);for(;o.length>32&&o[0]===0;)o=o.subarray(1);let i=new Uint8Array(64);return i.set(r,32-r.length),i.set(o,64-o.length),i}function Ii(n){let e=0;function t(o){if(o<24)return o;if(o===24)return n[e++];if(o===25){let i=n[e]<<8|n[e+1];return e+=2,i}if(o===26){let i=(n[e]<<24>>>0)+(n[e+1]<<16)+(n[e+2]<<8)+n[e+3];return e+=4,i}if(o===27){let i=BigInt((n[e]<<24>>>0)+(n[e+1]<<16)+(n[e+2]<<8)+n[e+3]),c=BigInt((n[e+4]<<24>>>0)+(n[e+5]<<16)+(n[e+6]<<8)+n[e+7]);return e+=8,i<<32n|c}throw new Error(`Unsupported CBOR uint info: ${o}`)}function r(){if(e>=n.length)throw new Error("Unexpected end of CBOR data");let o=n[e++],i=o>>5,c=o&31;switch(i){case 0:{let a=t(c);return typeof a=="bigint"?Number(a):a}case 1:{let a=t(c);return typeof a=="bigint"?Number(-1n-a):-1-Number(a)}case 2:{let a=Number(t(c)),l=n.subarray(e,e+a);return e+=a,l}case 3:{let a=Number(t(c)),l=n.subarray(e,e+a);return e+=a,new TextDecoder().decode(l)}case 4:{let a=Number(t(c)),l=[];for(let d=0;d<a;d++)l.push(r());return l}case 5:{let a=Number(t(c)),l={};for(let d=0;d<a;d++){let u=r(),f=r();l[u]=f}return l}case 7:return c===20?!1:c===21?!0:c===22?null:void 0;default:throw new Error(`Unsupported CBOR major type: ${i}`)}}return{value:r(),bytesRead:e}}async function Fu(n){if(n.length<37)throw new Error("Invalid authenticatorData length");let e=n.subarray(0,32),t=n[32],r=(n[33]<<24>>>0)+(n[34]<<16)+(n[35]<<8)+n[36];if(!!!(t&64))throw new Error("Attestation does not contain attested credential data");let o=37,i=n.subarray(o,o+16);o+=16;let c=Array.from(i).map(h=>h.toString(16).padStart(2,"0")).join(""),a=n[o]<<8|n[o+1];o+=2;let l=n.subarray(o,o+a);o+=a;let d=ft(l),u=n.subarray(o),{value:f}=Ii(u),p=f[3]??-7,m="";if(p===-7){let h=f[-2],g=f[-3];if(!h||!g||h.length!==32||g.length!==32)throw new Error("Invalid EC2 COSE public key components");let b=new Uint8Array(65);b[0]=4,b.set(h,1),b.set(g,33);let w=await crypto.subtle.importKey("raw",b,{name:"ECDSA",namedCurve:"P-256"},!0,["verify"]),y=await crypto.subtle.exportKey("spki",w);m=ft(y)}else if(p===-257){let h=f[-1],g=f[-2];if(!h||!g)throw new Error("Invalid RSA COSE public key components");let b={kty:"RSA",n:ft(h),e:ft(g),alg:"RS256",ext:!0},w=await crypto.subtle.importKey("jwk",b,{name:"RSASSA-PKCS1-v1_5",hash:"SHA-256"},!0,["verify"]),y=await crypto.subtle.exportKey("spki",w);m=ft(y)}else throw new Error(`Unsupported COSE algorithm: ${p}`);return{rpIdHash:e,flags:t,signCount:r,aaguid:c,credentialId:d,publicKeySpki:m,algorithm:p}}async function Gc(n){let{clientDataJSON:e,attestationObject:t,expectedChallenge:r,expectedOrigin:s,expectedRpId:o}=n,i=Ot(e),c=JSON.parse(new TextDecoder().decode(i));if(c.type!=="webauthn.create")throw new Error(`Invalid clientData type: ${c.type}`);if(c.challenge!==r)throw new Error("WebAuthn challenge mismatch");let a=new URL(c.origin),l=s.includes("://")?new URL(s):new URL(`https://${s}`);if(a.origin.toLowerCase()!==l.origin.toLowerCase())throw new Error(`WebAuthn origin mismatch: expected ${l.origin}, received ${a.origin}`);if(!(a.hostname==="localhost"||a.hostname==="127.0.0.1")&&a.protocol!=="https:")throw new Error(`WebAuthn requires HTTPS origin, received: ${a.protocol}`);let u=Ot(t),{value:f}=Ii(u);if(!f.authData)throw new Error("Missing authData in attestationObject");let p=await Fu(f.authData),m=new Uint8Array(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(o)));for(let h=0;h<32;h++)if(p.rpIdHash[h]!==m[h])throw new Error("WebAuthn rpIdHash mismatch");if(!(p.flags&1))throw new Error("User Presence (UP) flag not set");return p}async function Nt(n){let{clientDataJSON:e,authenticatorData:t,signature:r,publicKeySpki:s,algorithm:o,expectedChallenge:i,expectedOrigin:c,expectedRpId:a,previousSignCount:l=0}=n,d=Ot(e),u=JSON.parse(new TextDecoder().decode(d));if(u.type!=="webauthn.get")throw new Error(`Invalid clientData type: ${u.type}`);if(u.challenge!==i)throw new Error("WebAuthn challenge mismatch");let f=new URL(u.origin),p=c.includes("://")?new URL(c):new URL(`https://${c}`);if(f.origin.toLowerCase()!==p.origin.toLowerCase())throw new Error(`WebAuthn origin mismatch: expected ${p.origin}, received ${f.origin}`);if(!(f.hostname==="localhost"||f.hostname==="127.0.0.1")&&f.protocol!=="https:")throw new Error(`WebAuthn requires HTTPS origin, received: ${f.protocol}`);let h=Ot(t);if(h.length<37)throw new Error("Invalid authenticatorData length");let g=h.subarray(0,32),b=h[32],w=(h[33]<<24>>>0)+(h[34]<<16)+(h[35]<<8)+h[36],y=new Uint8Array(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(a)));for(let T=0;T<32;T++)if(g[T]!==y[T])throw new Error("WebAuthn rpIdHash mismatch");if(!(b&1))throw new Error("User Presence flag (UP) was not set by authenticator");if(w>0&&l>0&&w<=l)throw new Error("Authenticator sign count is not strictly monotonic. Possible cloned authenticator detected.");let E=new Uint8Array(await crypto.subtle.digest("SHA-256",d)),_=new Uint8Array(h.length+E.length);_.set(h,0),_.set(E,h.length);let S=Ot(r),x=Ot(s);if(o===-7){let T=await crypto.subtle.importKey("spki",x,{name:"ECDSA",namedCurve:"P-256"},!1,["verify"]),v=Vc(S);if(!await crypto.subtle.verify({name:"ECDSA",hash:"SHA-256"},T,v,_))throw new Error("WebAuthn signature verification failed")}else if(o===-257){let T=await crypto.subtle.importKey("spki",x,{name:"RSASSA-PKCS1-v1_5",hash:"SHA-256"},!1,["verify"]);if(!await crypto.subtle.verify({name:"RSASSA-PKCS1-v1_5"},T,S,_))throw new Error("WebAuthn signature verification failed")}else throw new Error(`Unsupported public key algorithm: ${o}`);return{signCount:w}}async function Jc(n,e){let t=new URL(n.url),r=new Y(e.DB,e),s=new oe(e.DB),o=caches.default,i=n.headers.get("CF-Connecting-IP")||"127.0.0.1",c=n.headers.get("User-Agent");if(t.pathname==="/api/auth/prelogin"&&n.method==="POST"){if(await P.isRateLimited(o,`login_fail:${i}`,10,900))return new Response("Too many attempts",{status:429});let{username:a,turnstileToken:l}=await n.json(),d=new he(e.DB),[u,f]=await Promise.all([d.get("turnstile_secret_key"),d.get("turnstile_enabled_login")]);if(f==="true"&&u&&!await Jn(l,u,i))return new Response("Verification failed",{status:400});let p=await r.getByUsername(a);if(!p)return await r.isEmpty().catch(()=>!1)?new Response("no_users_registered",{status:404}):(await P.isRateLimited(o,`login_fail:${i}`,100,900),new Response("User not found",{status:404}));let m=await Es(e,p.id),h=hs(m,e),g=!p.totp_skip_password,b=!!p.totp_enabled,w=p.password_version??1,E=await new ae(e.DB).listByUser(p.id),_=E.length>0,S=null,x=null;_&&(x=cn(),S={challenge:x,rpId:t.hostname,allowCredentials:E.map(L=>({id:L.credential_id,type:"public-key",transports:L.transports?JSON.parse(L.transports):void 0})),timeout:6e4,userVerification:"preferred"});let T=j(32),v=null;w===2&&p.hashed_password&&(v=fs(p.hashed_password));let C=Number(e.PREAUTH_TTL_SECONDS)||300;return await P.set(o,`preauth_state:${m}`,{nonce:T,failedAttempts:0,passkeyChallenge:x,rpId:t.hostname},C),new Response(JSON.stringify({requires_password:g,requires_totp:b,has_passkey:_,passkey_options:S,password_version:w,nonce:T,serverSalt:v}),{headers:{"Set-Cookie":h,"Content-Type":"application/json"}})}if(t.pathname==="/api/auth/login"&&n.method==="POST"){if(n.headers.get("X-Password-Leaked")==="true"||n.headers.get("Exposed-Credential-Check")==="true")return new Response("password_leaked",{status:400});if(await P.isRateLimited(o,`login_fail:${i}`,10,900))return new Response("Too many login attempts",{status:429});let a=ys(n.headers.get("Cookie"));if(!a)return new Response("Pre-auth session missing or expired",{status:401});let l=await _s(e,a);if(!l)return new Response("Session expired, please start over",{status:401});let d=await P.get(o,`preauth_state:${a}`);if(!d)return await gr(e,a),new Response("Session expired, please start over",{status:401});let{nonce:u}=d,f=await r.getById(l);if(!f)return new Response("User not found",{status:404});let{password:p,totpTokenHash:m,totpSalt:h,recoveryKey:g,passkeyAssertion:b,keepLoggedIn:w}=await n.json(),y=!1,E=new ae(e.DB),_=await E.listByUser(l),S=_.length>0,x=!!f.totp_enabled,T=!!f.totp_recovery_keys,v=x||S,C=S&&!!b;if(!(!!f.totp_skip_password||C)){if(!p)return new Response("Password is required",{status:400});if((f.password_version??1)===2){let F=await ms(f.hashed_password,u);if(p!==F){await P.isRateLimited(o,`login_fail:${i}`,100,900),await s.record(l,"login_fail",i,c,{reason:"wrong_password"});let I=await Ze(o,a,e);return I<=0?new Response("Invalid password",{status:400}):new Response(`Invalid password. ${I} attempt${I>1?"s":""} remaining.`,{status:400})}}else{if(!await yt(p,f.hashed_password,1)){await P.isRateLimited(o,`login_fail:${i}`,100,900),await s.record(l,"login_fail",i,c,{reason:"wrong_password"});let I=await Ze(o,a,e);return I<=0?new Response("Invalid password",{status:400}):new Response(`Invalid password. ${I} attempt${I>1?"s":""} remaining.`,{status:400})}y=!0}}let H=!1,V=!1,Q=!1,Z=0,_e;if(v)if(b&&d.passkeyChallenge){let F=b.id,I=_.find(W=>W.credential_id===F);if(!I){await s.record(l,"passkey_verify_fail",i,c,{reason:"credential_not_found"});let W=await Ze(o,a,e);return W<=0?new Response("Invalid Passkey",{status:400}):new Response(`Invalid Passkey. ${W} attempt${W>1?"s":""} remaining.`,{status:400})}try{let{signCount:W}=await Nt({clientDataJSON:b.response.clientDataJSON,authenticatorData:b.response.authenticatorData,signature:b.response.signature,publicKeySpki:I.public_key,algorithm:I.algorithm,expectedChallenge:d.passkeyChallenge,expectedOrigin:`${t.protocol}//${t.host}`,expectedRpId:d.rpId||t.hostname,previousSignCount:I.sign_count});await E.updateUsage(I.id,W),Q=!0}catch(W){console.warn("[Passkey Login] Verification failed:",W.message||W),await s.record(l,"passkey_verify_fail",i,c,{reason:W.message});let G=await Ze(o,a,e);return G<=0?new Response("Invalid Passkey signature",{status:400}):new Response(`Invalid Passkey signature. ${G} attempt${G>1?"s":""} remaining.`,{status:400})}}else if((x||S||T)&&g){let F=[];try{let te=f.totp_recovery_keys;F=typeof te=="string"?JSON.parse(te||"[]"):te||[],Array.isArray(F)||(F=[F])}catch{}if(await Gn(g,F)===-1){await s.record(l,"totp_verify_fail",i,c,{method:"recovery_key"});let te=await Ze(o,a,e);return te<=0?new Response("Invalid recovery key",{status:400}):new Response(`Invalid recovery key. ${te} attempt${te>1?"s":""} remaining.`,{status:400})}let W=an(),G=await Ge(W);await r.updateRecoveryKeys(l,[{hash:G}]),_e=W,V=!0,Z=1}else if(x&&m){let F=await $r(f.totp_secret||"",m,h);if(!F.valid){await s.record(l,"totp_verify_fail",i,c);let I=await Ze(o,a,e);return I<=0?new Response("Invalid TOTP code",{status:400}):new Response(`Invalid TOTP code. ${I} attempt${I>1?"s":""} remaining.`,{status:400})}if(F.timeStep!==void 0){let I=`totp_used:${l}:${F.timeStep}`;if(await P.get(o,I))return await s.record(l,"totp_verify_fail",i,c,{reason:"replay_blocked"}),new Response("TOTP code has already been used. Please wait for the next 30-second code.",{status:400});await P.set(o,I,1,90)}H=!0}else{let F=await Ze(o,a,e);return F<=0?new Response("Missing MFA verification",{status:400}):new Response(`Missing MFA verification (Passkey, TOTP code, or recovery key). ${F} attempt${F>1?"s":""} remaining.`,{status:400})}await gr(e,a),await P.delete(o,`preauth_state:${a}`),await P.delete(o,`ratelimit:login_fail:${i}`);let{latitude:K,longitude:Se}=En(n);if(K===null||Se===null)return new Response("geolocation_missing",{status:400});let{session:ie,refreshToken:k}=await xn(e,l,i,c,K,Se,!!w),R=await re(ie.id,l);Q?await s.record(l,"passkey_verify_success",i,c,void 0,R):H?await s.record(l,"totp_verify_success",i,c,void 0,R):V&&await s.record(l,"recovery_key_used",i,c,{remaining:Z},R),await s.record(l,"login_success",i,c,void 0,R);let A=j(32),D=it(A,e,!!w),N=await He(e),U=await Ne(N),M=Number(e.ACCESS_TOKEN_EXPIRATION_MINUTES)||10,$=await Rn({userId:l,role:f.role,sessionId:ie.id,exp:Math.floor(Date.now()/1e3)+M*60},U),B=new Headers({"Content-Type":"application/json"});return B.append("Set-Cookie",wt(k,e,!!w)),B.append("Set-Cookie",D),B.append("Set-Cookie",gs()),new Response(JSON.stringify({success:!0,accessToken:$,needsMigration:y,rotatedRecoveryKey:_e}),{headers:B})}return new Response("Not Found",{status:404})}pe();Fe();ge();async function Yc(n,e){let t=caches.default,r=n.headers.get("CF-Connecting-IP")||"127.0.0.1",s=n.headers.get("User-Agent"),o=new oe(e.DB);if(await P.isRateLimited(t,`refresh_fail:${r}`,20,60))return new Response("Too many attempts",{status:429});let i=Le(n.headers.get("Cookie"));if(!i)return new Response("Refresh token missing",{status:401});let{getRequestCoordinates:c}=await Promise.resolve().then(()=>(pe(),yr)),{latitude:a,longitude:l}=c(n),{session:d,user:u,newRefreshToken:f,reason:p}=await bs(e,i,a,l);if(!d||!u||!f){if(u){let E=i?ve(i):null,_=E?await re(E.sid,u.id):null;await o.record(u.id,"logout",r,s,{reason:p||"unknown"},_)}return await P.isRateLimited(t,`refresh_fail:${r}`,100,60),new Response(JSON.stringify({error:"Invalid refresh token",reason:p||"unknown"}),{status:401,headers:{"Set-Cookie":Qe(),"Content-Type":"application/json"}})}let m=await He(e),h=await Ne(m),g=Number(e.ACCESS_TOKEN_EXPIRATION_MINUTES)||10,b=await Rn({userId:u.id,role:u.role,sessionId:d.id,exp:Math.floor(Date.now()/1e3)+g*60},h),w=new Headers({"Content-Type":"application/json"}),y=d.id.startsWith("k_");return w.append("Set-Cookie",wt(f,e,y)),new Response(JSON.stringify({success:!0,accessToken:b}),{headers:w})}pe();Be();Hr();async function zc(n,e){let t=n.headers.get("CF-Connecting-IP")||"127.0.0.1",r=n.headers.get("User-Agent"),s=new oe(e.DB),o=Le(n.headers.get("Cookie"));if(o){let c=ve(o);if(c){let l=await new le(e.DB).getSessionUserId(c.sid);if(await Et(e,c.sid),Vn(c.sid),l){let d=await re(c.sid,l);await s.record(l,"logout",t,r,{reason:"user_active"},d)}}}let i=new Headers({"Content-Type":"application/json"});return i.append("Set-Cookie",Qe()),i.append("Set-Cookie","csrf_token=; SameSite=Lax; Path=/; Max-Age=0; Secure"),new Response(JSON.stringify({success:!0}),{headers:i})}pe();Fe();Te();Be();ge();Hr();async function Hu(n,e){try{if(await yt(n,e))return!0}catch{}try{let t=atob(e),r=new Uint8Array(t.length);for(let s=0;s<t.length;s++)r[s]=t.charCodeAt(s);if(r.length===48){let s=r.slice(0,16),o=r.slice(16),i=Array.from(s).map(d=>d.toString(16).padStart(2,"0")).join(""),c=new TextEncoder().encode(n+i),a=await crypto.subtle.digest("SHA-256",c),l=new Uint8Array(a);if(l.length===o.length){let d=0;for(let u=0;u<l.length;u++)d|=l[u]^o[u];if(d===0)return!0}}}catch{}return!1}async function Xc(n,e){let t=new URL(n.url),r=new Y(e.DB,e),s=new oe(e.DB),o=caches.default,i=n.headers.get("CF-Connecting-IP")||"127.0.0.1",c=n.headers.get("User-Agent");if(t.pathname==="/api/auth/unlock-session"&&n.method==="GET"){let a=n.headers.get("Authorization")||"",l="";if(a.startsWith("Bearer ")&&(l=a.slice(7)),!l)return new Response("Unauthorized",{status:401});try{let d=await He(e),u=await Ne(d),f=await Tn(l,u);if(!f)return new Response("Unauthorized",{status:401});let p=await r.getById(f.userId),m=!!(p?.pin_hash&&!/^[a-f0-9]{64}$/.test(p.pin_hash)),h=j(32),g=`unlock_nonce:${f.sessionId}`;return await P.set(o,g,{nonce:h,isLegacy:m},300),new Response(JSON.stringify({nonce:h,legacy:m}),{headers:{"Content-Type":"application/json"}})}catch{return new Response("Unauthorized",{status:401})}}if(t.pathname==="/api/auth/unlock-session"&&n.method==="POST"){let a=n.headers.get("Authorization")||"",l="";if(a.startsWith("Bearer ")&&(l=a.slice(7)),!l)return new Response("Unauthorized",{status:401});try{let d=await He(e),u=await Ne(d),f=await Tn(l,u);if(!f)return new Response("Unauthorized",{status:401});let{pinHash:p,nonce:m}=await n.json();if(!p)return new Response("Missing pinHash",{status:400});if(!m)return new Response("Missing nonce",{status:400});let h=new le(e.DB),g=await h.getSession(f.sessionId);if(!g)return new Response("Session not found",{status:401});let b=await r.getById(f.userId);if(!b||!b.pin_hash)return new Response("PIN not configured",{status:400});let w=`unlock_nonce:${f.sessionId}`,y=await P.get(o,w);if(!y?.nonce)return new Response("Challenge expired, please start over",{status:400});let E=y.nonce,_=!!y.isLegacy;if(await P.delete(o,w),m!==E)return new Response("Invalid nonce",{status:400});let S=`unlock_fail:${g.id}`,T=(await P.get(o,S))?.count||0,v=await re(g.id,f.userId),C=!1;if(_)C=await Hu(p,b.pin_hash),C&&await r.updatePinHash(f.userId,p);else{let H=await Zi(b.pin_hash,E);if(p.length===H.length){let V=0;for(let Q=0;Q<p.length;Q++)V|=p.charCodeAt(Q)^H.charCodeAt(Q);C=V===0}}if(!C){let H=T+1;return H>=3?(await h.deleteSession(g.id),await P.delete(o,S),await s.record(f.userId,"pin_verify_fail",i,c,{reason:"too_many_attempts"},v),new Response(JSON.stringify({success:!1,error:"too_many_attempts"}),{status:401,headers:{"Content-Type":"application/json"}})):(await P.set(o,S,{count:H},900),await s.record(f.userId,"pin_verify_fail",i,c,{reason:"incorrect_pin",attempt:H},v),new Response(JSON.stringify({success:!1,error:"incorrect_pin",attemptsRemaining:3-H}),{status:400,headers:{"Content-Type":"application/json"}}))}let L=Math.floor(Date.now()/1e3);return await h.resumeSession(g.id,L),Vn(g.id),await P.delete(o,S),await s.record(f.userId,"pin_verify_success",i,c,void 0,v),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}catch(d){return console.error("Unlock session error:",d),new Response("Unauthorized",{status:401})}}if(t.pathname==="/api/auth/lock-session"&&n.method==="POST"){let a=n.headers.get("Authorization")||"",l="";if(a.startsWith("Bearer ")&&(l=a.slice(7)),!l)return new Response("Unauthorized",{status:401});try{let d=await He(e),u=await Ne(d),f=await Tn(l,u);if(!f)return new Response("Unauthorized",{status:401});let p=new le(e.DB),m=await p.getSession(f.sessionId);return m?(await p.pauseSession(m.id),Vn(m.id),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})):new Response("Session not found",{status:401})}catch{return new Response("Unauthorized",{status:401})}}return new Response("Not Found",{status:404})}Be();ge();Te();async function Qc(n,e){let t=new URL(n.url),r=t.pathname,s=new Y(e.DB,e),o=new oe(e.DB),i=caches.default,c=n.headers.get("CF-Connecting-IP")||"127.0.0.1",a=n.headers.get("User-Agent");if(r==="/api/auth/forgot-password/init"&&n.method==="POST"){if(await P.isRateLimited(i,`forgot_pw_ip:${c}`,10,600))return new Response("Too many attempts",{status:429});let{username:l,turnstileToken:d}=await n.json();if(!l)return new Response("Username is required",{status:400});let u=new he(e.DB),[f,p]=await Promise.all([u.get("turnstile_secret_key"),u.get("turnstile_enabled_login")]);if(p==="true"&&f&&!await Jn(d,f,c))return new Response("Verification failed",{status:400});let m=await s.getByUsername(l);if(!m)return await P.isRateLimited(i,`forgot_pw_ip:${c}`,100,600),new Response("User not found",{status:404});let g=await new ae(e.DB).listByUser(m.id),b=g.length>0,w=!!m.totp_enabled&&(!!m.totp_secret||!!m.totp_secret_encrypted),y=!1,E=m.totp_recovery_keys;if(E)try{let v=typeof E=="string"?JSON.parse(E):E;y=Array.isArray(v)&&v.length>0}catch{y=typeof E=="string"&&E.length>0}else m.totp_recovery_keys_encrypted&&(y=!0);if(!b&&!w&&!y)return new Response(JSON.stringify({can_reset:!1,reason:"no_mfa_configured"}),{status:200,headers:{"Content-Type":"application/json"}});let _=null,S=null;b&&(_=cn(),S={challenge:_,rpId:t.hostname,allowCredentials:g.map(v=>({id:v.credential_id,type:"public-key",transports:v.transports?JSON.parse(v.transports):void 0})),timeout:6e4,userVerification:"preferred"});let x=j(32),T={userId:m.id,username:m.username,passkeyChallenge:_,rpId:t.hostname,failedAttempts:0};return await P.set(i,`forgot_pw_state:${x}`,T,300),new Response(JSON.stringify({can_reset:!0,recoveryToken:x,has_passkey:b,passkey_options:S,has_totp:w,has_recovery_keys:y}),{headers:{"Content-Type":"application/json"}})}if(r==="/api/auth/forgot-password/verify"&&n.method==="POST"){let{recoveryToken:l,passkeyAssertion:d,totpTokenHash:u,totpSalt:f,recoveryKey:p}=await n.json();if(!l)return new Response("Recovery token is required",{status:400});let m=`forgot_pw_state:${l}`,h=await P.get(i,m);if(!h)return new Response("Recovery session expired or invalid",{status:400});if(h.failedAttempts>=3)return await P.delete(i,m),new Response("Too many failed attempts. Please start over.",{status:429});let g=await s.getById(h.userId);if(!g)return await P.delete(i,m),new Response("User not found",{status:404});if(d&&h.passkeyChallenge){let y=new ae(e.DB),_=(await y.listByUser(g.id)).find(S=>S.credential_id===d.id);if(!_)return h.failedAttempts++,await P.set(i,m,h,300),new Response("Passkey not recognized",{status:400});try{let{signCount:S}=await Nt({clientDataJSON:d.response.clientDataJSON,authenticatorData:d.response.authenticatorData,signature:d.response.signature,publicKeySpki:_.public_key,algorithm:_.algorithm,expectedChallenge:h.passkeyChallenge,expectedOrigin:`${t.protocol}//${t.host}`,expectedRpId:h.rpId,previousSignCount:_.sign_count});await y.updateUsage(_.id,S),await o.record(g.id,"passkey_verify_success",c,a,{flow:"forgot_password"})}catch{return h.failedAttempts++,await P.set(i,m,h,300),new Response("Passkey verification failed",{status:400})}}else if(p){let y=[];try{let _=g.totp_recovery_keys;y=typeof _=="string"?JSON.parse(_||"[]"):_||[],Array.isArray(y)||(y=[y])}catch{}let E=await Gn(p,y);if(E===-1)return h.failedAttempts++,await P.set(i,m,h,300),new Response("Invalid recovery key",{status:400});await s.consumeRecoveryKey(g.id,E,y),await o.record(g.id,"recovery_key_used",c,a,{flow:"forgot_password",remaining:y.length-1})}else if(u&&g.totp_secret){let y=await $r(g.totp_secret,u,f);if(!y.valid)return h.failedAttempts++,await P.set(i,m,h,300),new Response("Invalid TOTP code",{status:400});if(y.timeStep!==void 0){let E=`totp_step:${g.id}:${y.timeStep}`;if(await P.get(i,E))return h.failedAttempts++,await P.set(i,m,h,300),new Response("TOTP code already used, please wait for next code",{status:400});await P.set(i,E,!0,180)}await o.record(g.id,"totp_verify_success",c,a,{flow:"forgot_password"})}else return new Response("No valid MFA credential provided",{status:400});await P.delete(i,m);let b=j(32),w={userId:g.id,username:g.username};return await P.set(i,`forgot_pw_reset:${b}`,w,300),new Response(JSON.stringify({success:!0,resetToken:b}),{headers:{"Content-Type":"application/json"}})}if(r==="/api/auth/forgot-password/reset"&&n.method==="POST"){let{resetToken:l,newPassword:d}=await n.json();if(!l||!d)return new Response("Reset token and new password are required",{status:400});if(!St.test(d))return new Response("Password format error",{status:400});let u=`forgot_pw_reset:${l}`,f=await P.get(i,u);if(!f)return new Response("Reset token expired or invalid",{status:400});await P.delete(i,u);let p=await s.getById(f.userId);if(!p)return new Response("User not found",{status:404});let m=await ot(d,2);return await s.updatePassword(p.id,m,2),await new le(e.DB).deleteAllByUserId(p.id),await o.record(p.id,"password_change_success",c,a,{method:"forgot_password_reset"}),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}return new Response("Not Found",{status:404})}async function Zc(n,e){try{let r=new URL(n.url).pathname;return r==="/api/auth/config"||r==="/api/auth/check-username"?await $c(n,e):r==="/api/auth/signup"?await jc(n,e):r==="/api/auth/prelogin"||r==="/api/auth/login"?await Jc(n,e):r==="/api/auth/refresh"?await Yc(n,e):r==="/api/auth/logout"?await zc(n,e):r.startsWith("/api/auth/forgot-password")?await Qc(n,e):r==="/api/auth/unlock-session"||r==="/api/auth/lock-session"?await Xc(n,e):new Response("Not Found",{status:404})}catch(t){return console.error("[Auth API] Unhandled Error:",t.message||t),new Response(t.message||"Internal Server Error",{status:500,headers:{"Content-Type":"text/plain; charset=utf-8"}})}}var Yn=class{static isAdmin(e){return e.role==="admin"}static canAccessProfile(e,t){return t.owner_id===e.id}};pe();async function qc(n,e,t,r){let s=new q(e.DB);if(n.method==="GET"){let o=await s.listByOwner(t.id);return new Response(JSON.stringify(o),{headers:{"Content-Type":"application/json"}})}if(n.method==="POST"){let o=await n.json();if(!o.name||!Qo.test(o.name))return new Response("Invalid Profile Name format",{status:400});let i=await s.listByOwner(t.id),c=Number(e.MAX_PROFILES_PER_USER)||10;if(i.length>=c)return new Response(`Profile limit exceeded (max ${c})`,{status:400});if(i.find(g=>g.name===o.name))return new Response("The profile name already exists",{status:400});let l=j(6),d=e.MAX_LOG_RETENTION_DAYS!==void 0&&e.MAX_LOG_RETENTION_DAYS!==""?Number(e.MAX_LOG_RETENTION_DAYS):30,u=e.DEFAULT_LOG_RETENTION_DAYS!==void 0&&e.DEFAULT_LOG_RETENTION_DAYS!==""?Math.min(Number(e.DEFAULT_LOG_RETENTION_DAYS),d):Math.min(7,d),f=e.NORMAL_USER_MAX_LOG_RETENTION_DAYS!==void 0&&e.NORMAL_USER_MAX_LOG_RETENTION_DAYS!==""?Math.min(Number(e.NORMAL_USER_MAX_LOG_RETENTION_DAYS),d):Math.min(7,d),p=e.NORMAL_USER_DEFAULT_LOG_RETENTION_DAYS!==void 0&&e.NORMAL_USER_DEFAULT_LOG_RETENTION_DAYS!==""?Math.min(Number(e.NORMAL_USER_DEFAULT_LOG_RETENTION_DAYS),f):Math.min(1,f),m=t?.role==="admin"?u:p,h={upstream:["https://security.cloudflare-dns.com/dns-query"],ecs:{enabled:!0,use_client_ip:!0},log_retention_days:m,skip_log_on_pass:!1,default_policy:"ALLOW",best_effort_ech:{enabled:!1,fronting_domain:"cloudflare-ech.com"}};await s.create({id:l,owner_id:t.id,name:o.name||"Unnamed Profile",settings:h});try{let g=await e.DB.prepare("SELECT public_key, is_active FROM user_log_keys WHERE profile_id IN (SELECT id FROM profiles WHERE owner_id = ?) LIMIT 1").bind(t.id).first();if(g?.public_key){let b=Math.floor(Date.now()/1e3);await e.DB.prepare("INSERT INTO user_log_keys (profile_id, public_key, created_at, is_active) VALUES (?, ?, ?, ?)").bind(l,g.public_key,b,g.is_active??1).run();let w=await e.DB.prepare("SELECT encrypted_sk, iv, salt FROM user_recovery_wrapped_keys WHERE profile_id IN (SELECT id FROM profiles WHERE owner_id = ?) LIMIT 1").bind(t.id).first();w&&await e.DB.prepare("INSERT INTO user_recovery_wrapped_keys (profile_id, encrypted_sk, iv, salt, created_at) VALUES (?, ?, ?, ?, ?)").bind(l,w.encrypted_sk,w.iv,w.salt,b).run()}}catch(g){console.error("[Profiles] Failed to inherit E2EE log key for new profile:",g)}return new Response(JSON.stringify({id:l}),{status:201})}return new Response("Method Not Allowed",{status:405})}async function el(n,e,t,r,s,o){let i=new q(e.DB),c=new Ie(e.DB),a=r.id;if(s.length===3){if(n.method==="DELETE")return await i.delete(a),new Response(null,{status:204});if(n.method==="PATCH"){let{name:l}=await n.json();return!l||!Qo.test(l)?new Response("Invalid Profile Name format",{status:400}):(await i.updateName(a,l),o.waitUntil(de.clearCache(a,!0,e)),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}}))}return n.method==="GET"?new Response(JSON.stringify(r),{headers:{"Content-Type":"application/json"}}):new Response("Method Not Allowed",{status:405})}if(s[3]==="rotate_key"&&n.method==="POST"){let l=j(12);return await i.rotateKey(a,l),o.waitUntil(de.clearCache(a,!1,e)),new Response(JSON.stringify({profile_key:l}),{headers:{"Content-Type":"application/json"}})}if(s[3]==="settings"&&n.method==="PATCH"){let l=await n.json(),d=e.MAX_LOG_RETENTION_DAYS!==void 0&&e.MAX_LOG_RETENTION_DAYS!==""?Number(e.MAX_LOG_RETENTION_DAYS):30,u=e.ADMIN_USER_MAX_LOG_RETENTION_DAYS!==void 0&&e.ADMIN_USER_MAX_LOG_RETENTION_DAYS!==""?Math.min(Number(e.ADMIN_USER_MAX_LOG_RETENTION_DAYS),d):d,f=e.NORMAL_USER_MAX_LOG_RETENTION_DAYS!==void 0&&e.NORMAL_USER_MAX_LOG_RETENTION_DAYS!==""?Math.min(Number(e.NORMAL_USER_MAX_LOG_RETENTION_DAYS),d):Math.min(7,d),p=t?.role==="admin"?u:f;if(l.log_retention_days!=null&&(l.log_retention_days=Math.min(Number(l.log_retention_days),p)),l.upstream&&Array.isArray(l.upstream))for(let b of l.upstream){let w=b.startsWith("https://"),y=b.startsWith("http://"),E=b.startsWith("tcp://"),_=b.startsWith("tls://"),S=b.startsWith("dot://"),x=b.startsWith("udp://"),T=b.startsWith("sdns://"),v=!b.includes("//")&&!b.startsWith("/");if(!w&&!y&&!E&&!_&&!S&&!x&&!T&&!v)return new Response("Invalid upstream URL format. Only HTTP(S), TCP, TLS (DoT), DNS Stamp (sdns://), or bare host[:port] are allowed.",{status:400});let C=v?`tcp://${b}`:b;if(!at(C))return new Response("Invalid upstream URL. Private networks and localhosts are not allowed.",{status:400})}let m=await i.getById(a),h=30;try{let b=JSON.parse(m?.settings||"{}");b?.log_retention_days!=null&&(h=Number(b.log_retention_days))}catch{}await i.updateSettings(a,l);let g=l.log_retention_days;if(g!=null&&Number(g)<h)if(Number(g)===0)o.waitUntil((async()=>{try{await e.DB.prepare("DELETE FROM logs WHERE profile_id = ?").bind(a).run(),await c.kemKeys.cleanupProfileOrphans(a)}catch(b){console.error("[Profile] Failed to purge logs on retention disable:",b?.message||b)}})());else{let b=Math.floor(Date.now()/1e3-Number(g)*24*3600);o.waitUntil(c.cleanup(a,b))}return o.waitUntil(de.clearCache(a,!1,e)),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}if(s[3]==="test"&&n.method==="POST"){let{domain:l,type:d}=await n.json(),u=Ht(l,d),f=await de.process(n,{name:l,type:d,raw:u},{profileId:a,startTime:Date.now(),env:e,ctx:o});return new Response(JSON.stringify({action:f.action,reason:f.reason,answers:f.answer.length>0?ke(f.answer):[],diagnostics:f.diagnostics,latency:f.latency,timings:f.timings,client_ip:n.headers.get("CF-Connecting-IP")||"127.0.0.1",geo_country:await Vt(n,n.headers.get("CF-Connecting-IP")||"127.0.0.1"),success:!0}),{headers:{"Content-Type":"application/json"}})}return new Response("Not Found",{status:404})}pe();var yo=class{constructor(e){this.db=e}db;async getAccessPoints(e){let{results:t}=await this.db.prepare("SELECT * FROM access_points WHERE profile_id = ? ORDER BY created_at ASC").bind(e).all();return t}async addAccessPoint(e,t){let r=Math.floor(Date.now()/1e3),s=j(12),o=5;for(let i=0;i<o;i++){let c=$t(5);try{return await this.db.prepare("INSERT INTO access_points (id, profile_id, name, token, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)").bind(s,e,t,c,r,r).run(),{id:s,profile_id:e,name:t,token:c,created_at:r,updated_at:r}}catch(a){if(i<o-1&&(String(a).includes("UNIQUE constraint failed")||String(a).includes("SQLITE_CONSTRAINT")))continue;throw a}}throw new Error("Failed to generate a unique access point token")}async updateAccessPointName(e,t,r){let s=Math.floor(Date.now()/1e3);return(await this.db.prepare("UPDATE access_points SET name = ?, updated_at = ? WHERE id = ? AND profile_id = ?").bind(r,s,e,t).run()).success}async rotateAccessPointToken(e,t){let r=Math.floor(Date.now()/1e3),s=5;for(let o=0;o<s;o++){let i=$t(5);try{if(!(await this.db.prepare("UPDATE access_points SET token = ?, updated_at = ? WHERE id = ? AND profile_id = ?").bind(i,r,e,t).run()).success)throw new Error("Failed to update access point token");return i}catch(c){if(o<s-1&&(String(c).includes("UNIQUE constraint failed")||String(c).includes("SQLITE_CONSTRAINT")))continue;throw c}}throw new Error("Failed to generate a unique access point token")}async deleteAccessPoint(e,t){return(await this.db.prepare("DELETE FROM access_points WHERE id = ? AND profile_id = ?").bind(e,t).run()).success}};async function tl(n,e,t,r,s,o){let i=new yo(e.DB);if(n.method==="GET"){let c=await i.getAccessPoints(r);return new Response(JSON.stringify(c),{headers:{"Content-Type":"application/json"}})}if(n.method==="POST"){if(s.length===6&&s[5]==="rotate_token"){let u=s[4],f=await i.rotateAccessPointToken(u,r);return new Response(JSON.stringify({token:f}),{headers:{"Content-Type":"application/json"}})}let c=await n.json();if(!c.name)return new Response("Name is required",{status:400});if(!zo.test(c.name))return new Response("Invalid Access Point name format",{status:400});let a=await i.getAccessPoints(r);if(a.some(u=>u.name.toLowerCase()===c.name.toLowerCase()))return new Response("Access Point name already exists",{status:400});let l=Number(e.MAX_ACCESS_POINTS_PER_PROFILE)||100;if(a.length>=l)return new Response(`Access point limit exceeded (max ${l})`,{status:400});let d=await i.addAccessPoint(r,c.name);return new Response(JSON.stringify(d),{status:201,headers:{"Content-Type":"application/json"}})}if(n.method==="PATCH"&&s.length===5){let c=s[4],a=await n.json();return a.name?zo.test(a.name)?(await i.getAccessPoints(r)).some(d=>d.id!==c&&d.name.toLowerCase()===a.name.toLowerCase())?new Response("Access Point name already exists",{status:400}):(await i.updateAccessPointName(c,r,a.name),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})):new Response("Invalid Access Point name format",{status:400}):new Response("Name is required",{status:400})}if(n.method==="DELETE"&&s.length===5){let c=s[4];return await i.deleteAccessPoint(c,r),new Response(null,{status:204})}return new Response("Method Not Allowed",{status:405})}async function nl(n,e,t,r,s,o){let i=new An(e.DB);if(n.method==="GET"){let c=await i.getRules(r);return new Response(JSON.stringify(c),{headers:{"Content-Type":"application/json"}})}if(n.method==="POST"){let c=await n.json();if(Array.isArray(c)||c&&Array.isArray(c.rules)){let f=Array.isArray(c)?c:c.rules,p=new Set,m=[];for(let y of f){if(!y||typeof y.pattern!="string")continue;let E=y.pattern.trim().toLowerCase();if(!E||p.has(E))continue;p.add(E);let _=String(y.type||"BLOCK").toUpperCase();_!=="ALLOW"&&_!=="BLOCK"&&_!=="REDIRECT"||m.push({type:_,pattern:E,v_a:y.v_a||null,v_aaaa:y.v_aaaa||null,v_txt:y.v_txt||null,v_cname:y.v_cname||null,created_at:typeof y.created_at=="number"?y.created_at:void 0})}if(m.length===0)return new Response(JSON.stringify({count:0,message:"No valid rules provided"}),{status:200,headers:{"Content-Type":"application/json"}});let h=await i.getRules(r),g=new Set(h.map(y=>y.pattern.trim().toLowerCase())),b=m.filter(y=>!g.has(y.pattern)),w=0;return b.length>0&&(w=await i.addRulesBulk(r,b),o.waitUntil(de.clearCache(r,!1,e))),new Response(JSON.stringify({success:!0,count:w}),{status:201,headers:{"Content-Type":"application/json"}})}let l=c,d=l.pattern?l.pattern.trim():"";return d?await i.getRuleByPattern(r,d)?new Response("Rule for this domain already exists",{status:400}):(await i.addRule(r,l),o.waitUntil(de.clearCache(r,!1,e)),new Response(null,{status:201})):new Response("Domain pattern cannot be empty",{status:400})}if(n.method==="PUT"){let c=await n.json(),a=c.pattern?c.pattern.trim():"";return a?await i.getRuleByPatternExcludeId(r,a,c.id)?new Response("Rule for this domain already exists",{status:400}):(await i.updateRule(c.id,r,c),o.waitUntil(de.clearCache(r,!1,e)),new Response(null,{status:200})):new Response("Domain pattern cannot be empty",{status:400})}if(n.method==="DELETE"){let{id:c}=await n.json();return await i.deleteRule(c,r),o.waitUntil(de.clearCache(r,!1,e)),new Response(null,{status:204})}return new Response("Method Not Allowed",{status:405})}var It=class{constructor(e){this.db=e}db;async getLists(e){let{results:t}=await this.db.prepare("SELECT * FROM lists WHERE profile_id = ?").bind(e).all();return t}async addList(e,t){return(await this.db.prepare("INSERT INTO lists (profile_id, url) VALUES (?, ?)").bind(e,t).run()).success}async addListsBulk(e,t){if(!t||t.length===0)return 0;let r=t.map(o=>{let i=typeof o=="string"?o.trim():o.url.trim(),c=typeof o=="object"&&o.enabled!==void 0?o.enabled?1:0:1;return this.db.prepare("INSERT INTO lists (profile_id, url, enabled) VALUES (?, ?, ?)").bind(e,i,c)}),s=0;for(let o=0;o<r.length;o+=100){let i=r.slice(o,o+100),c=await this.db.batch(i);for(let a of c)a.success&&(s+=a.meta.changes||1)}return s}async setEnabled(e,t,r){return(await this.db.prepare("UPDATE lists SET enabled = ? WHERE id = ? AND profile_id = ?").bind(r?1:0,e,t).run()).success}async getListById(e,t){return await this.db.prepare("SELECT * FROM lists WHERE id = ? AND profile_id = ?").bind(e,t).first()}async deleteList(e,t){return(await this.db.prepare("DELETE FROM lists WHERE id = ? AND profile_id = ?").bind(e,t).run()).success}async updateListSyncStatus(e,t,r,s=null){return r!=null?(await this.db.prepare("UPDATE lists SET last_synced_at = ?, enabled = ?, sync_error = ? WHERE id = ?").bind(t,r,s,e).run()).success:(await this.db.prepare("UPDATE lists SET last_synced_at = ?, sync_error = ? WHERE id = ?").bind(t,s,e).run()).success}async resetListSyncStatus(e){return(await this.db.prepare("UPDATE lists SET last_synced_at = 0 WHERE profile_id = ?").bind(e).run()).success}};var Ut=class{constructor(e){this.db=e}db;async upsertListBloom(e,t,r){let s=new Uint8Array(t),o=[];o.push(this.db.prepare("DELETE FROM list_blooms WHERE list_id = ?").bind(e));let i=0;for(let a=0;a<s.length;a+=1572864){let l=s.slice(a,a+1572864).buffer;o.push(this.db.prepare("INSERT INTO list_blooms (list_id, chunk_index, bloom_filter_chunk, updated_at) VALUES (?, ?, ?, ?)").bind(e,i,l,r)),i++}return(await this.db.batch(o)).every(a=>a.success)}async hasListBloom(e){return!!await this.db.prepare("SELECT 1 AS present FROM list_blooms WHERE list_id = ? LIMIT 1").bind(e).first()}async getListBloom(e){let{results:t}=await this.db.prepare("SELECT bloom_filter_chunk FROM list_blooms WHERE list_id = ? ORDER BY chunk_index ASC").bind(e).all();if(!t||t.length===0)return null;let r=t.reduce((i,c)=>{let a=c.bloom_filter_chunk.byteLength??c.bloom_filter_chunk.length;return i+a},0),s=new Uint8Array(r),o=0;for(let i of t){let c=new Uint8Array(i.bloom_filter_chunk);s.set(c,o),o+=c.length}return s.buffer}async deleteListBloom(e){return(await this.db.prepare("DELETE FROM list_blooms WHERE list_id = ?").bind(e).run()).success}async getActiveListBloomsForProfile(e){let{results:t}=await this.db.prepare(`
387
387
  SELECT lb.list_id, lb.bloom_filter_chunk
388
388
  FROM list_blooms lb
389
389
  JOIN lists l ON lb.list_id = l.id
390
390
  WHERE l.profile_id = ? AND l.enabled = 1
391
391
  ORDER BY lb.list_id ASC, lb.chunk_index ASC
392
- `).bind(e).all();if(!n||n.length===0)return[];let r=new Map;for(let o of n)r.has(o.list_id)||r.set(o.list_id,[]),r.get(o.list_id).push(o.bloom_filter_chunk);let s=[];for(let[,o]of r.entries()){let i=o.reduce((l,d)=>{let u=d.byteLength??d.length;return l+u},0),c=new Uint8Array(i),a=0;for(let l of o){let d=new Uint8Array(l);c.set(d,a),a+=d.length}s.push(c.buffer)}return s}};async function Nr(t,e,n,r,s,o,i,c,a,l){let u=(await e.getLists(t)).filter(f=>!!f.enabled);if(u.length===0)await r.clearProfileBlooms(t);else{let f=Te.create(c,a),p=!1;for(let m of u)try{let h=await n.getListBloom(m.id);if(h){let g=Te.fromUint8Array(new Uint8Array(h));f.merge(g),p=!0}}catch(h){console.error(`[Sync] Failed to load/merge list bloom for list #${m.id}:`,h)}if(p){let m=f.toUint8Array();await r.upsertProfileBloom(t,m.buffer,i)}else await r.clearProfileBlooms(t)}await s.updateListUpdatedAt(t,i),o&&typeof o.waitUntil=="function"&&o.waitUntil(ns.clear(t,!0,l))}function Lu(t){if(t.includes(":"))return!0;let e=0,n=t.length;if(n<7||n>15)return!1;for(let r=0;r<n;r++){let s=t.charCodeAt(r);if(s===46)e++;else if(s<48||s>57)return!1}return e===3}function Di(t){let e=0,n=t.length;for(;e<n;){let a=t.charCodeAt(e);if(a===32||a===9||a===13||a===10)e++;else break}let r=n;for(;r>e;){let a=t.charCodeAt(r-1);if(a===32||a===9||a===13||a===10)r--;else break}if(e>=r)return null;let s=t.charCodeAt(e);if(s===33||s===35||s===64&&e+1<r&&t.charCodeAt(e+1)===64)return null;let o=t.substring(e,r);if(o.startsWith("||")){let a=o.substring(2),l=a.indexOf("^");l!==-1&&(a=a.substring(0,l));let d=a.indexOf("$");return d!==-1&&(a=a.substring(0,d)),a=a.trim().toLowerCase(),a||null}let i=-1,c=o.length;for(let a=0;a<c;a++){let l=o.charCodeAt(a);if(l===32||l===9){i=a;break}}if(i===-1)return o.toLowerCase();{let a=o.substring(0,i),l=i;for(;l<c;){let u=o.charCodeAt(l);if(u===32||u===9)l++;else break}let d="";if(l<c){let u=l;for(;u<c;){let f=o.charCodeAt(u);if(f===32||f===9)break;u++}d=o.substring(l,u)}if(d!=="")if(Lu(a)){let u=d.toLowerCase();return u!=="localhost"&&u!=="0.0.0.0"&&u!=="127.0.0.1"?u:null}else return a.toLowerCase();else return a.toLowerCase()}}async function Qc(t,e,n,r){let s=Date.now()+n,o=t,i=0,c=5,a;try{for(;;){if(!ze(o))return{count:0,error:"Invalid list URL. Private networks, localhosts, and internal domains are not allowed."};let g=s-Date.now();if(g<=0)return{count:0,error:"Request timed out"};if(a=await fetch(o,{redirect:"manual",signal:AbortSignal.timeout(g)}),a.status>=300&&a.status<400){let w=a.headers.get("location");if(!w)return{count:0,error:`Redirect status ${a.status} without Location header`};if(i++,i>c)return{count:0,error:`Too many redirects (max ${c})`};try{let b=new URL(w,o).toString(),y=new URL(b).protocol;if(y!=="http:"&&y!=="https:")return{count:0,error:`Invalid redirect protocol: ${y}`};o=b;continue}catch{return{count:0,error:`Invalid redirect location: ${w}`}}}break}if(!a.ok)return{count:0,error:`HTTP error! Status: ${a.status} ${a.statusText}`};let l=a.headers.get("content-length");if(l&&parseInt(l,10)>e)return{count:0,error:`List too large (${(parseInt(l,10)/1024/1024).toFixed(2)} MB), limit is ${(e/1024/1024).toFixed(0)} MB`};let d=a.body?.getReader();if(!d)return{count:0,error:"Failed to get stream reader from response"};let u=new TextDecoder("utf-8",{fatal:!1,ignoreBOM:!0}),f="",p=0,m=0,h=!1;for(;;){let{done:g,value:w}=await d.read();if(g)break;if(w){if(m+=w.length,m>e){await d.cancel(),h=!0;break}let b=u.decode(w,{stream:!0});f+=b;let y=f.split(`
393
- `);f=y.pop()||"";for(let E of y){let _=Di(E);_&&(await r(_),p++)}}}if(f){let g=Di(f);g&&(await r(g),p++)}return h&&console.warn(`[Fetcher] List truncated at ${(e/1024/1024).toFixed(0)} MB: ${t}`),{count:p,error:null}}catch(l){return{count:0,error:l.message||String(l)}}}var Ou=5*1024*1024;async function fo(t,e,n,r,s,o){let i=Number(n.SYNC_TIMEOUT_MS)||3e4,c=Number(n.MAX_LIST_DOMAINS)||5e5,a=Number(n.MAX_SYNC_DOMAINS)||1e6,l=Number(n.BLOOM_FALSE_POSITIVE_RATE)||1e-4,d=Te.create(a,l),u=0,{error:f}=await Qc(e.url,Ou,i,async m=>{u<c&&(d.add(m),u++,u%5e4===0&&await new Promise(h=>setTimeout(h,0)))}),p=f;return f?console.warn(`[Sync] Profile ${t}: failed to fetch/parse list #${e.id}. Skipping and keeping old bloom. Error: ${f}`):(await s.upsertListBloom(e.id,d.toUint8Array().buffer,o),console.log(`[Sync] Profile ${t}: successfully updated list #${e.id} with ${u} domains.`)),await r.updateListSyncStatus(e.id,o,null,p),p}async function jn(t,e,n){let r=new q(e.DB),s=new Lt(e.DB),o=new wt(e.DB),i=new Ot(e.DB),c=Math.floor(Date.now()/1e3);try{let a=await r.getById(t);if(!a){console.error(`[Sync] Profile ${t} not found.`);return}let l=a.list_updated_at??0,u=(await s.getLists(t)).filter(b=>!!b.enabled);if(u.length===0){await o.clearProfileBlooms(t),await r.updateListUpdatedAt(t,c);return}!u.some(b=>(b.last_synced_at??0)>l)&&console.log(`[Sync] Profile ${t}: starting a new sync cycle.`);let p=u.filter(b=>(b.last_synced_at??0)<=l).sort((b,y)=>(b.last_synced_at??0)-(y.last_synced_at??0));if(p.length===0){let b=Number(e.MAX_SYNC_DOMAINS)||1e6,y=Number(e.BLOOM_FALSE_POSITIVE_RATE)||1e-4;await r.updateListUpdatedAt(t,c),await Nr(t,s,i,o,r,n,c,b,y,e);return}let m=p[0];await fo(t,m,e,s,i,c);let g=(await s.getLists(t)).filter(b=>!!b.enabled);if(g.every(b=>(b.last_synced_at??0)>l)){let b=Number(e.MAX_SYNC_DOMAINS)||1e6,y=Number(e.BLOOM_FALSE_POSITIVE_RATE)||1e-4;await r.updateListUpdatedAt(t,c),await Nr(t,s,i,o,r,n,c,b,y,e),console.log(`[Sync] Profile ${t}: all ${g.length} list(s) processed \u2014 promoted combined active bloom.`)}else{let b=g.filter(y=>(y.last_synced_at??0)<=l).length;console.log(`[Sync] Profile ${t}: ${b} active list(s) remaining in this cycle.`)}}catch(a){console.error(`[Sync] Critical failure for Profile ${t}:`,a),await r.updateListUpdatedAt(t,c)}}async function ki(t,e,n){let r=new q(e.DB),s=new Lt(e.DB),o=new wt(e.DB),i=new Ot(e.DB),c=Math.floor(Date.now()/1e3);try{if(!await r.getById(t)){console.error(`[Sync] Profile ${t} not found.`);return}let d=(await s.getLists(t)).filter(p=>!!p.enabled);if(d.length===0){await o.clearProfileBlooms(t),await r.updateListUpdatedAt(t,c);return}for(let p of d)await fo(t,p,e,s,i,c);await r.updateListUpdatedAt(t,c);let u=Number(e.MAX_SYNC_DOMAINS)||1e6,f=Number(e.BLOOM_FALSE_POSITIVE_RATE)||1e-4;await Nr(t,s,i,o,r,n,c,u,f,e),console.log(`[Sync] Profile ${t}: manual sync cycle complete.`)}catch(a){console.error(`[Sync] Critical failure in manual sync for Profile ${t}:`,a),await r.updateListUpdatedAt(t,c)}}async function mo(t,e,n){let r=new Lt(e.DB),s=new Ot(e.DB),o=new wt(e.DB),i=new q(e.DB),a=(await i.getById(t))?.list_updated_at??0,l=(await r.getLists(t)).filter(f=>!!f.enabled),u=(await Promise.all(l.map(f=>s.hasListBloom(f.id).catch(()=>!0)))).findIndex(f=>!f);if(u!==-1){let f=l[u];try{await fo(t,f,e,r,s,Math.floor(Date.now()/1e3))}catch(p){console.error(`[Sync] fetch of list ${f.id} during rebuild failed:`,p)}}await Nr(t,r,s,o,i,n,Math.floor(Date.now()/1e3),Number(e.MAX_SYNC_DOMAINS)||1e6,Number(e.BLOOM_FALSE_POSITIVE_RATE)||1e-4,e),await i.updateListUpdatedAt(t,a)}async function Zc(t,e,n,r,s,o){let i=new Lt(e.DB),c=new q(e.DB);if(t.method==="GET"){if(s[5]==="check"){let l=Number(s[4]);if(!Number.isInteger(l)||l<=0)return new Response("Invalid list id",{status:400});let u=(new URL(t.url).searchParams.get("domain")||"").trim().toLowerCase().replace(/\.+$/,"");if(!u||u.length>253||!/^[a-z0-9._-]+$/.test(u))return new Response("Invalid or missing domain parameter",{status:400});let f=await i.getListById(l,r);if(!f)return new Response("List Not Found",{status:404});let p=await new Ot(e.DB).getListBloom(l);if(!p)return new Response(JSON.stringify({domain:u,blocked:!1,synced:!1}),{headers:{"Content-Type":"application/json"}});let m;try{m=Te.fromUint8Array(new Uint8Array(p))}catch(w){return console.error(`[Lists] Failed to deserialize bloom filter for list #${l}:`,w),new Response(JSON.stringify({domain:u,blocked:!1,synced:!1,error:"Corrupted filter"}),{status:500,headers:{"Content-Type":"application/json"}})}let h=u,g=null;for(;h;){if(m.test(h)){g=h;break}let w=h.indexOf(".");if(w===-1)break;h=h.slice(w+1)}return new Response(JSON.stringify({domain:u,blocked:g!==null,matchedEntry:g,falsePositiveRate:Number(e.BLOOM_FALSE_POSITIVE_RATE)||1e-4,enabled:!!f.enabled,synced:!0}),{headers:{"Content-Type":"application/json"}})}let a=await i.getLists(r);return new Response(JSON.stringify(a),{headers:{"Content-Type":"application/json"}})}if(t.method==="PATCH"){let a=Number(s[4]);if(!Number.isInteger(a)||a<=0)return new Response("Invalid list id",{status:400});let l;try{l=await t.json()}catch{return new Response("Body must be { enabled: boolean }",{status:400})}return typeof l.enabled!="boolean"?new Response("Body must be { enabled: boolean }",{status:400}):await i.getListById(a,r)?await i.setEnabled(a,r,l.enabled)?(o.waitUntil(mo(r,e,o).then(()=>de.clearCache(r,!0,e)).catch(f=>console.error(`[Lists] bloom rebuild failed for ${r}:`,f))),new Response(JSON.stringify({id:a,enabled:l.enabled}),{headers:{"Content-Type":"application/json"}})):new Response("Failed to update list",{status:500}):new Response("List Not Found",{status:404})}if(t.method==="POST"){if(s[4]==="sync")return o.waitUntil(ki(r,e,o)),new Response(JSON.stringify({message:"Sync started"}),{status:202});let a=await t.json(),l=Array.isArray(a)?a:a?.lists||a?.list||a?.urls||a?.url||a?.filters||a?.filter||a?.blocklists||a?.blocklist;if(Array.isArray(l)){let f=l,p=new Set,m=[];for(let y of f){let E=typeof y=="string"?y.trim():y?.url??y?.link??y?.uri??y?.address??y?.source??y?.target??y?.download_url??"";if(typeof E!="string")continue;if(E=E.replace(/^["']|["']$/g,"").trim(),E.startsWith("//"))E=`https:${E}`;else if(!E.startsWith("http://")&&!E.startsWith("https://"))if(E.includes(".")&&!E.includes(" ")&&E.length>3)E=`https://${E}`;else continue;if(!ze(E))continue;let _=E.toLowerCase();if(p.has(_))continue;p.add(_);let S=y&&typeof y=="object"&&y.enabled!==void 0?y.enabled?1:0:1;m.push({url:E,enabled:S})}if(m.length===0)return new Response(JSON.stringify({count:0,message:"No valid URLs provided"}),{status:200,headers:{"Content-Type":"application/json"}});let h=await i.getLists(r),g=new Set(h.map(y=>y.url.trim().toLowerCase())),w=m.filter(y=>!g.has(y.url.toLowerCase())),b=0;return w.length>0&&(b=await i.addListsBulk(r,w),o.waitUntil(jn(r,e,o)),o.waitUntil(de.clearCache(r,!0,e))),new Response(JSON.stringify({success:!0,count:b}),{status:201,headers:{"Content-Type":"application/json"}})}let{url:u}=a;return!u||!u.startsWith("http://")&&!u.startsWith("https://")?new Response("Invalid list URL format",{status:400}):ze(u)?(await i.addList(r,u),o.waitUntil(jn(r,e,o)),o.waitUntil(de.clearCache(r,!0,e)),new Response(null,{status:201})):new Response("Invalid list URL. Private networks and localhosts are not allowed.",{status:400})}if(t.method==="DELETE"){let{id:a}=await t.json();return await i.deleteList(a,r),o.waitUntil(mo(r,e,o).then(()=>de.clearCache(r,!0,e)).catch(l=>console.error(`[Lists] Bloom rebuild after delete failed for ${r}:`,l))),new Response(null,{status:204})}return new Response("Method Not Allowed",{status:405})}ge();async function qc(t,e,n,r,s){let o=t.headers.get("Upgrade");if(!o||o.toLowerCase()!=="websocket")return new Response("Expected Upgrade: websocket",{status:426});let i=globalThis;if(typeof i.WebSocketPair>"u")return new Response("WebSocket is not supported on this runtime environment",{status:501});let c=new i.WebSocketPair,[a,l]=Object.values(c);l.accept();let d=r.id,u=!1,f=0,p=0,m=null,h=!1,g=null,w=new Promise(E=>{g=E});s&&typeof s.waitUntil=="function"&&s.waitUntil(w);let b=async()=>{if(!(u||h||f<=0)){h=!0;try{if(!await e.DB.prepare(`
392
+ `).bind(e).all();if(!t||t.length===0)return[];let r=new Map;for(let o of t)r.has(o.list_id)||r.set(o.list_id,[]),r.get(o.list_id).push(o.bloom_filter_chunk);let s=[];for(let[,o]of r.entries()){let i=o.reduce((l,d)=>{let u=d.byteLength??d.length;return l+u},0),c=new Uint8Array(i),a=0;for(let l of o){let d=new Uint8Array(l);c.set(d,a),a+=d.length}s.push(c.buffer)}return s}};async function Wr(n,e,t,r,s,o,i,c,a,l){let u=(await e.getLists(n)).filter(f=>!!f.enabled);if(u.length===0)await r.clearProfileBlooms(n);else{let f=xe.create(c,a),p=!1;for(let m of u)try{let h=await t.getListBloom(m.id);if(h){let g=xe.fromUint8Array(new Uint8Array(h));f.merge(g),p=!0}}catch(h){console.error(`[Sync] Failed to load/merge list bloom for list #${m.id}:`,h)}if(p){let m=f.toUint8Array();await r.upsertProfileBloom(n,m.buffer,i)}else await r.clearProfileBlooms(n)}await s.updateListUpdatedAt(n,i),o&&typeof o.waitUntil=="function"&&o.waitUntil(ds.clear(n,!0,l))}function $u(n){if(n.includes(":"))return!0;let e=0,t=n.length;if(t<7||t>15)return!1;for(let r=0;r<t;r++){let s=n.charCodeAt(r);if(s===46)e++;else if(s<48||s>57)return!1}return e===3}function Ui(n){let e=0,t=n.length;for(;e<t;){let a=n.charCodeAt(e);if(a===32||a===9||a===13||a===10)e++;else break}let r=t;for(;r>e;){let a=n.charCodeAt(r-1);if(a===32||a===9||a===13||a===10)r--;else break}if(e>=r)return null;let s=n.charCodeAt(e);if(s===33||s===35||s===64&&e+1<r&&n.charCodeAt(e+1)===64)return null;let o=n.substring(e,r);if(o.startsWith("||")){let a=o.substring(2),l=a.indexOf("^");l!==-1&&(a=a.substring(0,l));let d=a.indexOf("$");return d!==-1&&(a=a.substring(0,d)),a=a.trim().toLowerCase(),a||null}let i=-1,c=o.length;for(let a=0;a<c;a++){let l=o.charCodeAt(a);if(l===32||l===9){i=a;break}}if(i===-1)return o.toLowerCase();{let a=o.substring(0,i),l=i;for(;l<c;){let u=o.charCodeAt(l);if(u===32||u===9)l++;else break}let d="";if(l<c){let u=l;for(;u<c;){let f=o.charCodeAt(u);if(f===32||f===9)break;u++}d=o.substring(l,u)}if(d!=="")if($u(a)){let u=d.toLowerCase();return u!=="localhost"&&u!=="0.0.0.0"&&u!=="127.0.0.1"?u:null}else return a.toLowerCase();else return a.toLowerCase()}}async function rl(n,e,t,r){let s=Date.now()+t,o=n,i=0,c=5,a;try{for(;;){if(!await oa(o))return{count:0,error:"Invalid list URL. Private networks, localhosts, and internal domains are not allowed."};let g=s-Date.now();if(g<=0)return{count:0,error:"Request timed out"};if(a=await fetch(o,{redirect:"manual",signal:AbortSignal.timeout(g)}),a.status>=300&&a.status<400){let b=a.headers.get("location");if(!b)return{count:0,error:`Redirect status ${a.status} without Location header`};if(i++,i>c)return{count:0,error:`Too many redirects (max ${c})`};try{let w=new URL(b,o).toString(),y=new URL(w).protocol;if(y!=="http:"&&y!=="https:")return{count:0,error:`Invalid redirect protocol: ${y}`};o=w;continue}catch{return{count:0,error:`Invalid redirect location: ${b}`}}}break}if(!a.ok)return{count:0,error:`HTTP error! Status: ${a.status} ${a.statusText}`};let l=a.headers.get("content-length");if(l&&parseInt(l,10)>e)return{count:0,error:`List too large (${(parseInt(l,10)/1024/1024).toFixed(2)} MB), limit is ${(e/1024/1024).toFixed(0)} MB`};let d=a.body?.getReader();if(!d)return{count:0,error:"Failed to get stream reader from response"};let u=new TextDecoder("utf-8",{fatal:!1,ignoreBOM:!0}),f="",p=0,m=0,h=!1;for(;;){let{done:g,value:b}=await d.read();if(g)break;if(b){if(m+=b.length,m>e){await d.cancel(),h=!0;break}let w=u.decode(b,{stream:!0});f+=w;let y=f.split(`
393
+ `);f=y.pop()||"";for(let E of y){let _=Ui(E);_&&(await r(_),p++)}}}if(f){let g=Ui(f);g&&(await r(g),p++)}return h&&console.warn(`[Fetcher] List truncated at ${(e/1024/1024).toFixed(0)} MB: ${n}`),{count:p,error:null}}catch(l){return{count:0,error:l.message||String(l)}}}var Ku=5*1024*1024;async function wo(n,e,t,r,s,o){let i=Number(t.SYNC_TIMEOUT_MS)||3e4,c=Number(t.MAX_LIST_DOMAINS)||5e5,a=Number(t.MAX_SYNC_DOMAINS)||1e6,l=Number(t.BLOOM_FALSE_POSITIVE_RATE)||1e-4,d=xe.create(a,l),u=0,{error:f}=await rl(e.url,Ku,i,async m=>{u<c&&(d.add(m),u++,u%5e4===0&&await new Promise(h=>setTimeout(h,0)))}),p=f;return f?console.warn(`[Sync] Profile ${n}: failed to fetch/parse list #${e.id}. Skipping and keeping old bloom. Error: ${f}`):(await s.upsertListBloom(e.id,d.toUint8Array().buffer,o),console.log(`[Sync] Profile ${n}: successfully updated list #${e.id} with ${u} domains.`)),await r.updateListSyncStatus(e.id,o,null,p),p}async function zn(n,e,t){let r=new q(e.DB),s=new It(e.DB),o=new _t(e.DB),i=new Ut(e.DB),c=Math.floor(Date.now()/1e3);try{let a=await r.getById(n);if(!a){console.error(`[Sync] Profile ${n} not found.`);return}let l=a.list_updated_at??0,u=(await s.getLists(n)).filter(w=>!!w.enabled);if(u.length===0){await o.clearProfileBlooms(n),await r.updateListUpdatedAt(n,c);return}!u.some(w=>(w.last_synced_at??0)>l)&&console.log(`[Sync] Profile ${n}: starting a new sync cycle.`);let p=u.filter(w=>(w.last_synced_at??0)<=l).sort((w,y)=>(w.last_synced_at??0)-(y.last_synced_at??0));if(p.length===0){let w=Number(e.MAX_SYNC_DOMAINS)||1e6,y=Number(e.BLOOM_FALSE_POSITIVE_RATE)||1e-4;await r.updateListUpdatedAt(n,c),await Wr(n,s,i,o,r,t,c,w,y,e);return}let m=p[0];await wo(n,m,e,s,i,c);let g=(await s.getLists(n)).filter(w=>!!w.enabled);if(g.every(w=>(w.last_synced_at??0)>l)){let w=Number(e.MAX_SYNC_DOMAINS)||1e6,y=Number(e.BLOOM_FALSE_POSITIVE_RATE)||1e-4;await r.updateListUpdatedAt(n,c),await Wr(n,s,i,o,r,t,c,w,y,e),console.log(`[Sync] Profile ${n}: all ${g.length} list(s) processed \u2014 promoted combined active bloom.`)}else{let w=g.filter(y=>(y.last_synced_at??0)<=l).length;console.log(`[Sync] Profile ${n}: ${w} active list(s) remaining in this cycle.`)}}catch(a){console.error(`[Sync] Critical failure for Profile ${n}:`,a),await r.updateListUpdatedAt(n,c)}}async function Mi(n,e,t){let r=new q(e.DB),s=new It(e.DB),o=new _t(e.DB),i=new Ut(e.DB),c=Math.floor(Date.now()/1e3);try{if(!await r.getById(n)){console.error(`[Sync] Profile ${n} not found.`);return}let d=(await s.getLists(n)).filter(p=>!!p.enabled);if(d.length===0){await o.clearProfileBlooms(n),await r.updateListUpdatedAt(n,c);return}for(let p of d)await wo(n,p,e,s,i,c);await r.updateListUpdatedAt(n,c);let u=Number(e.MAX_SYNC_DOMAINS)||1e6,f=Number(e.BLOOM_FALSE_POSITIVE_RATE)||1e-4;await Wr(n,s,i,o,r,t,c,u,f,e),console.log(`[Sync] Profile ${n}: manual sync cycle complete.`)}catch(a){console.error(`[Sync] Critical failure in manual sync for Profile ${n}:`,a),await r.updateListUpdatedAt(n,c)}}async function bo(n,e,t){let r=new It(e.DB),s=new Ut(e.DB),o=new _t(e.DB),i=new q(e.DB),a=(await i.getById(n))?.list_updated_at??0,l=(await r.getLists(n)).filter(f=>!!f.enabled),u=(await Promise.all(l.map(f=>s.hasListBloom(f.id).catch(()=>!0)))).findIndex(f=>!f);if(u!==-1){let f=l[u];try{await wo(n,f,e,r,s,Math.floor(Date.now()/1e3))}catch(p){console.error(`[Sync] fetch of list ${f.id} during rebuild failed:`,p)}}await Wr(n,r,s,o,i,t,Math.floor(Date.now()/1e3),Number(e.MAX_SYNC_DOMAINS)||1e6,Number(e.BLOOM_FALSE_POSITIVE_RATE)||1e-4,e),await i.updateListUpdatedAt(n,a)}async function sl(n,e,t,r,s,o){let i=new It(e.DB),c=new q(e.DB);if(n.method==="GET"){if(s[5]==="check"){let l=Number(s[4]);if(!Number.isInteger(l)||l<=0)return new Response("Invalid list id",{status:400});let u=(new URL(n.url).searchParams.get("domain")||"").trim().toLowerCase().replace(/\.+$/,"");if(!u||u.length>253||!/^[a-z0-9._-]+$/.test(u))return new Response("Invalid or missing domain parameter",{status:400});let f=await i.getListById(l,r);if(!f)return new Response("List Not Found",{status:404});let p=await new Ut(e.DB).getListBloom(l);if(!p)return new Response(JSON.stringify({domain:u,blocked:!1,synced:!1}),{headers:{"Content-Type":"application/json"}});let m;try{m=xe.fromUint8Array(new Uint8Array(p))}catch(b){return console.error(`[Lists] Failed to deserialize bloom filter for list #${l}:`,b),new Response(JSON.stringify({domain:u,blocked:!1,synced:!1,error:"Corrupted filter"}),{status:500,headers:{"Content-Type":"application/json"}})}let h=u,g=null;for(;h;){if(m.test(h)){g=h;break}let b=h.indexOf(".");if(b===-1)break;h=h.slice(b+1)}return new Response(JSON.stringify({domain:u,blocked:g!==null,matchedEntry:g,falsePositiveRate:Number(e.BLOOM_FALSE_POSITIVE_RATE)||1e-4,enabled:!!f.enabled,synced:!0}),{headers:{"Content-Type":"application/json"}})}let a=await i.getLists(r);return new Response(JSON.stringify(a),{headers:{"Content-Type":"application/json"}})}if(n.method==="PATCH"){let a=Number(s[4]);if(!Number.isInteger(a)||a<=0)return new Response("Invalid list id",{status:400});let l;try{l=await n.json()}catch{return new Response("Body must be { enabled: boolean }",{status:400})}return typeof l.enabled!="boolean"?new Response("Body must be { enabled: boolean }",{status:400}):await i.getListById(a,r)?await i.setEnabled(a,r,l.enabled)?(o.waitUntil(bo(r,e,o).then(()=>de.clearCache(r,!0,e)).catch(f=>console.error(`[Lists] bloom rebuild failed for ${r}:`,f))),new Response(JSON.stringify({id:a,enabled:l.enabled}),{headers:{"Content-Type":"application/json"}})):new Response("Failed to update list",{status:500}):new Response("List Not Found",{status:404})}if(n.method==="POST"){if(s[4]==="sync")return o.waitUntil(Mi(r,e,o)),new Response(JSON.stringify({message:"Sync started"}),{status:202});let a=await n.json(),l=Array.isArray(a)?a:a?.lists||a?.list||a?.urls||a?.url||a?.filters||a?.filter||a?.blocklists||a?.blocklist;if(Array.isArray(l)){let f=l,p=new Set,m=[];for(let y of f){let E=typeof y=="string"?y.trim():y?.url??y?.link??y?.uri??y?.address??y?.source??y?.target??y?.download_url??"";if(typeof E!="string")continue;if(E=E.replace(/^["']|["']$/g,"").trim(),E.startsWith("//"))E=`https:${E}`;else if(!E.startsWith("http://")&&!E.startsWith("https://"))if(E.includes(".")&&!E.includes(" ")&&E.length>3)E=`https://${E}`;else continue;if(!at(E))continue;let _=E.toLowerCase();if(p.has(_))continue;p.add(_);let S=y&&typeof y=="object"&&y.enabled!==void 0?y.enabled?1:0:1;m.push({url:E,enabled:S})}if(m.length===0)return new Response(JSON.stringify({count:0,message:"No valid URLs provided"}),{status:200,headers:{"Content-Type":"application/json"}});let h=await i.getLists(r),g=new Set(h.map(y=>y.url.trim().toLowerCase())),b=m.filter(y=>!g.has(y.url.toLowerCase())),w=0;return b.length>0&&(w=await i.addListsBulk(r,b),o.waitUntil(zn(r,e,o)),o.waitUntil(de.clearCache(r,!0,e))),new Response(JSON.stringify({success:!0,count:w}),{status:201,headers:{"Content-Type":"application/json"}})}let{url:u}=a;return!u||!u.startsWith("http://")&&!u.startsWith("https://")?new Response("Invalid list URL format",{status:400}):at(u)?(await i.addList(r,u),o.waitUntil(zn(r,e,o)),o.waitUntil(de.clearCache(r,!0,e)),new Response(null,{status:201})):new Response("Invalid list URL. Private networks and localhosts are not allowed.",{status:400})}if(n.method==="DELETE"){let{id:a}=await n.json();return await i.deleteList(a,r),o.waitUntil(bo(r,e,o).then(()=>de.clearCache(r,!0,e)).catch(l=>console.error(`[Lists] Bloom rebuild after delete failed for ${r}:`,l))),new Response(null,{status:204})}return new Response("Method Not Allowed",{status:405})}ge();async function ol(n,e,t,r,s){let o=n.headers.get("Upgrade");if(!o||o.toLowerCase()!=="websocket")return new Response("Expected Upgrade: websocket",{status:426});let i=globalThis;if(typeof i.WebSocketPair>"u")return new Response("WebSocket is not supported on this runtime environment",{status:501});let c=new i.WebSocketPair,[a,l]=Object.values(c);l.accept();let d=r.id,u=!1,f=0,p=0,m=null,h=!1,g=null,b=new Promise(E=>{g=E});s&&typeof s.waitUntil=="function"&&s.waitUntil(b);let w=async()=>{if(!(u||h||f<=0)){h=!0;try{if(!await e.DB.prepare(`
394
394
  SELECT id, timestamp
395
395
  FROM logs
396
396
  WHERE profile_id = ? AND (timestamp > ? OR (timestamp = ? AND id > ?))
@@ -407,7 +407,7 @@ echo "Please change your system DNS to 127.0.0.1"
407
407
  WHERE l.profile_id = ? AND (l.timestamp > ? OR (l.timestamp = ? AND l.id > ?))
408
408
  ORDER BY l.timestamp DESC, l.id DESC
409
409
  LIMIT 50;
410
- `).bind(d,f,f,p).all();if(_&&_.length>0){let S=_[0];if(f=S.timestamp,p=Number(S.id),!u){let x={type:"NEW_LOGS",logs:_,latestTimestamp:f,latestId:p};l.send(JSON.stringify(x))}}}catch(E){console.error("[Logs WS] Error probing new logs:",E)}finally{h=!1}}};m=setInterval(()=>{b()},2e3),l.addEventListener("message",async E=>{try{let _=typeof E.data=="string"?E.data:new TextDecoder().decode(E.data),S=JSON.parse(_);switch(S.type){case"SUBSCRIBE":{f=S.sinceTimestamp,p=S.lastId||0,await b();break}case"CHECK_NEW":{S.sinceTimestamp!==void 0&&(f=S.sinceTimestamp),S.lastId!==void 0&&(p=S.lastId),await b();break}case"SYNC_GAP":{let x=Math.min(S.limit||100,100),{results:T}=await e.DB.prepare(`
410
+ `).bind(d,f,f,p).all();if(_&&_.length>0){let S=_[0];if(f=S.timestamp,p=Number(S.id),!u){let x={type:"NEW_LOGS",logs:_,latestTimestamp:f,latestId:p};l.send(JSON.stringify(x))}}}catch(E){console.error("[Logs WS] Error probing new logs:",E)}finally{h=!1}}};m=setInterval(()=>{w()},2e3),l.addEventListener("message",async E=>{try{let _=typeof E.data=="string"?E.data:new TextDecoder().decode(E.data),S=JSON.parse(_);switch(S.type){case"SUBSCRIBE":{f=S.sinceTimestamp,p=S.lastId||0,await w();break}case"CHECK_NEW":{S.sinceTimestamp!==void 0&&(f=S.sinceTimestamp),S.lastId!==void 0&&(p=S.lastId),await w();break}case"SYNC_GAP":{let x=Math.min(S.limit||100,100),{results:T}=await e.DB.prepare(`
411
411
  SELECT l.id, l.timestamp, l.client_ip, l.domain, l.action, l.record_type,
412
412
  l.latency, l.answer, l.geo_country, l.reason, l.access_point_id,
413
413
  l.dest_country_code, l.dest_country, l.dest_isp, l.encrypt_version,
@@ -418,40 +418,40 @@ echo "Please change your system DNS to 127.0.0.1"
418
418
  WHERE l.profile_id = ? AND l.timestamp >= ? AND l.timestamp <= ?
419
419
  ORDER BY l.timestamp DESC, l.id DESC
420
420
  LIMIT ?;
421
- `).bind(d,S.since,S.until,x).all();if(!u){let v={type:"SYNC_DATA",logs:T||[],hasMore:(T?.length||0)>=x};l.send(JSON.stringify(v))}break}case"PING":{if(!u){let x={type:"PONG"};l.send(JSON.stringify(x)),b()}break}default:break}}catch(_){console.error("[Logs WS] Message processing error:",_)}});let y=()=>{if(!u){u=!0,m&&(clearInterval(m),m=null);try{l.close()}catch{}g&&(g(),g=null)}};return l.addEventListener("close",y),l.addEventListener("error",y),new Response(null,{status:101,webSocket:a})}async function el(t,e,n,r,s,o){let i=new Oe(e.DB),c=r.id;if(s[3]==="logs"){if(s[4]==="ws"||t.headers.get("Upgrade")?.toLowerCase()==="websocket")return qc(t,e,n,r,o);if(t.method!=="GET")return new Response("Method Not Allowed",{status:405});let a=new URL(t.url).searchParams,l=a.get("range")||"24h",d=a.get("before"),u=a.get("status"),f=a.get("search"),p=a.get("access_point_id"),m=a.get("dest_country"),h=a.get("isp"),g=a.get("domain")||void 0,w=a.get("record_type")||void 0,b=a.get("geo_country")||void 0,y=a.get("reason")||void 0,E=a.get("start"),_=a.get("end"),S,x=Math.floor(Date.now()/1e3),T=e.MAX_LOG_RETENTION_DAYS!==void 0&&e.MAX_LOG_RETENTION_DAYS!==""?Number(e.MAX_LOG_RETENTION_DAYS):30,v=JSON.parse(r.settings),C=v.log_retention_days!==void 0?Math.min(Number(v.log_retention_days),T):T;if(C===0)return s.length>4&&s[4]!=="export"?new Response("Log Not Found",{status:404}):new Response(JSON.stringify([]),{headers:{"Content-Type":"application/json"}});let L=Math.floor(x-C*24*3600);if(E&&_)S=Math.max(parseInt(E),L),x=parseInt(_);else{switch(S=x,l){case"10m":S-=600;break;case"1h":S-=3600;break;case"24h":S-=86400;break;case"7d":S-=604800;break;case"30d":S-=2592e3;break;default:S-=86400;break}S=Math.max(S,L)}if(s.length>4){if(s[4]==="export"){let Se=await i.getLogs(c,{since:S,until:x,status:u||void 0,search:f||void 0,access_point_id:p||void 0,dest_country:m||void 0,isp:h||void 0,domain:g,record_type:w,geo_country:b,reason:y,export:!0});return new Response(JSON.stringify(Se),{headers:{"Content-Type":"application/json"}})}let Q=parseInt(s[4],10);if(isNaN(Q))return new Response("Invalid Log ID",{status:400});let Z=a.get("timestamp"),_e=Z?parseInt(Z,10):void 0,K=await i.getLog(c,Q,_e);return K?new Response(JSON.stringify(K),{headers:{"Content-Type":"application/json"}}):new Response("Log Not Found",{status:404})}let H=parseInt(a.get("limit")||"50",10);isNaN(H)||H<=0?H=50:H>100&&(H=100);let V=await i.getLogs(c,{since:S,until:x,status:u||void 0,search:f||void 0,before:d?parseInt(d):void 0,limit:H,access_point_id:p||void 0,dest_country:m||void 0,isp:h||void 0,domain:g,record_type:w,geo_country:b,reason:y});return new Response(JSON.stringify(V),{headers:{"Content-Type":"application/json"}})}if(s[3]==="analytics"){if(t.method!=="GET")return new Response("Method Not Allowed",{status:405});let a=new URL(t.url).searchParams,l=a.get("range"),d=a.get("start"),u=a.get("end"),f=a.get("access_point_id")||void 0,p,m=Math.floor(Date.now()/1e3),h;if(d&&u)p=parseInt(d),m=parseInt(u),h="(timestamp/3600)*3600";else switch(l){case"10m":p=m-600,h="(timestamp/60)*60";break;case"1h":p=m-3600,h="(timestamp/60)*60";break;case"24h":p=m-86400,h="(timestamp/3600)*3600";break;case"7d":p=m-604800,h="(timestamp/86400)*86400";break;case"30d":p=m-2592e3,h="(timestamp/86400)*86400";break;default:p=m-86400,h="(timestamp/3600)*3600";break}let g=s[4];if(g){let _=caches.default,S=`analytics_sub:${c}:${g}:${a.toString()}`,x=await P.get(_,S);if(x)return new Response(JSON.stringify(x),{headers:{"Content-Type":"application/json","X-Cache":"HIT","Cache-Control":"private, no-cache"}});let T=null;if(g==="summary"){let v=a.get("search")||void 0;T=await i.getSummary(c,p,m,v,f)}else if(g==="trend")T=await i.getTrend(c,p,m,h,f);else if(g==="top_allowed")T=await i.getTopAllowed(c,p,m,f);else if(g==="top_blocked")T=await i.getTopBlocked(c,p,m,f);else if(g==="clients")T=await i.getClients(c,p,m,f);else if(g==="destinations"){let v=a.get("limit"),C=v?parseInt(v,10):void 0;T=await i.getDestinations(c,p,m,f,C!==void 0&&!isNaN(C)?C:void 0)}else if(g==="isps"){let v=a.get("country_code")||void 0,C=a.get("limit"),L=C?parseInt(C,10):void 0;T=await i.getISPByCountry(c,v,p,m,f,L!==void 0&&!isNaN(L)?L:void 0)}else return new Response("Not Found",{status:404});return await P.set(_,S,T,300),new Response(JSON.stringify(T),{headers:{"Content-Type":"application/json","X-Cache":"MISS","Cache-Control":"private, no-cache"}})}let w=caches.default,b=`analytics:${c}:${p}:${m}:${h}:${f||"all"}`,y=await P.get(w,b);if(y)return new Response(JSON.stringify(y),{headers:{"Content-Type":"application/json","X-Cache":"HIT","Cache-Control":"private, no-cache"}});let E=await i.getAnalytics(c,p,m,h,f);return await P.set(w,b,E,60),new Response(JSON.stringify(E),{headers:{"Content-Type":"application/json","X-Cache":"MISS","Cache-Control":"private, no-cache"}})}return new Response("Not Found",{status:404})}async function tl(t,e,n,r,s,o){let i=new ae(e.DB),c=s[4];if(c==="status"&&t.method==="GET"){let[a,l,d,u]=await Promise.all([e.DB.prepare("SELECT public_key, created_at, is_active FROM user_log_keys WHERE profile_id = ?").bind(r.id).first(),e.DB.prepare(`
421
+ `).bind(d,S.since,S.until,x).all();if(!u){let v={type:"SYNC_DATA",logs:T||[],hasMore:(T?.length||0)>=x};l.send(JSON.stringify(v))}break}case"PING":{if(!u){let x={type:"PONG"};l.send(JSON.stringify(x)),w()}break}default:break}}catch(_){console.error("[Logs WS] Message processing error:",_)}});let y=()=>{if(!u){u=!0,m&&(clearInterval(m),m=null);try{l.close()}catch{}g&&(g(),g=null)}};return l.addEventListener("close",y),l.addEventListener("error",y),new Response(null,{status:101,webSocket:a})}async function il(n,e,t,r,s,o){let i=new Ie(e.DB),c=r.id;if(s[3]==="logs"){if(s[4]==="ws"||n.headers.get("Upgrade")?.toLowerCase()==="websocket")return ol(n,e,t,r,o);if(n.method!=="GET")return new Response("Method Not Allowed",{status:405});let a=new URL(n.url).searchParams,l=a.get("range")||"24h",d=a.get("before"),u=a.get("status"),f=a.get("search"),p=a.get("access_point_id"),m=a.get("dest_country"),h=a.get("isp"),g=a.get("domain")||void 0,b=a.get("record_type")||void 0,w=a.get("geo_country")||void 0,y=a.get("reason")||void 0,E=a.get("start"),_=a.get("end"),S,x=Math.floor(Date.now()/1e3),T=e.MAX_LOG_RETENTION_DAYS!==void 0&&e.MAX_LOG_RETENTION_DAYS!==""?Number(e.MAX_LOG_RETENTION_DAYS):30,v=JSON.parse(r.settings),C=v.log_retention_days!==void 0?Math.min(Number(v.log_retention_days),T):T;if(C===0)return s.length>4&&s[4]!=="export"?new Response("Log Not Found",{status:404}):new Response(JSON.stringify([]),{headers:{"Content-Type":"application/json"}});let L=Math.floor(x-C*24*3600);if(E&&_)S=Math.max(parseInt(E),L),x=parseInt(_);else{switch(S=x,l){case"10m":S-=600;break;case"1h":S-=3600;break;case"24h":S-=86400;break;case"7d":S-=604800;break;case"30d":S-=2592e3;break;default:S-=86400;break}S=Math.max(S,L)}if(s.length>4){if(s[4]==="export"){let Se=await i.getLogs(c,{since:S,until:x,status:u||void 0,search:f||void 0,access_point_id:p||void 0,dest_country:m||void 0,isp:h||void 0,domain:g,record_type:b,geo_country:w,reason:y,export:!0});return new Response(JSON.stringify(Se),{headers:{"Content-Type":"application/json"}})}let Q=parseInt(s[4],10);if(isNaN(Q))return new Response("Invalid Log ID",{status:400});let Z=a.get("timestamp"),_e=Z?parseInt(Z,10):void 0,K=await i.getLog(c,Q,_e);return K?new Response(JSON.stringify(K),{headers:{"Content-Type":"application/json"}}):new Response("Log Not Found",{status:404})}let H=parseInt(a.get("limit")||"50",10);isNaN(H)||H<=0?H=50:H>100&&(H=100);let V=await i.getLogs(c,{since:S,until:x,status:u||void 0,search:f||void 0,before:d?parseInt(d):void 0,limit:H,access_point_id:p||void 0,dest_country:m||void 0,isp:h||void 0,domain:g,record_type:b,geo_country:w,reason:y});return new Response(JSON.stringify(V),{headers:{"Content-Type":"application/json"}})}if(s[3]==="analytics"){if(n.method!=="GET")return new Response("Method Not Allowed",{status:405});let a=new URL(n.url).searchParams,l=a.get("range"),d=a.get("start"),u=a.get("end"),f=a.get("access_point_id")||void 0,p,m=Math.floor(Date.now()/1e3),h;if(d&&u)p=parseInt(d),m=parseInt(u),h="(timestamp/3600)*3600";else switch(l){case"10m":p=m-600,h="(timestamp/60)*60";break;case"1h":p=m-3600,h="(timestamp/60)*60";break;case"24h":p=m-86400,h="(timestamp/3600)*3600";break;case"7d":p=m-604800,h="(timestamp/86400)*86400";break;case"30d":p=m-2592e3,h="(timestamp/86400)*86400";break;default:p=m-86400,h="(timestamp/3600)*3600";break}let g=s[4];if(g){let _=caches.default,S=`analytics_sub:${c}:${g}:${a.toString()}`,x=await P.get(_,S);if(x)return new Response(JSON.stringify(x),{headers:{"Content-Type":"application/json","X-Cache":"HIT","Cache-Control":"private, no-cache"}});let T=null;if(g==="summary"){let v=a.get("search")||void 0;T=await i.getSummary(c,p,m,v,f)}else if(g==="trend")T=await i.getTrend(c,p,m,h,f);else if(g==="top_allowed")T=await i.getTopAllowed(c,p,m,f);else if(g==="top_blocked")T=await i.getTopBlocked(c,p,m,f);else if(g==="clients")T=await i.getClients(c,p,m,f);else if(g==="destinations"){let v=a.get("limit"),C=v?parseInt(v,10):void 0;T=await i.getDestinations(c,p,m,f,C!==void 0&&!isNaN(C)?C:void 0)}else if(g==="isps"){let v=a.get("country_code")||void 0,C=a.get("limit"),L=C?parseInt(C,10):void 0;T=await i.getISPByCountry(c,v,p,m,f,L!==void 0&&!isNaN(L)?L:void 0)}else return new Response("Not Found",{status:404});return await P.set(_,S,T,300),new Response(JSON.stringify(T),{headers:{"Content-Type":"application/json","X-Cache":"MISS","Cache-Control":"private, no-cache"}})}let b=caches.default,w=`analytics:${c}:${p}:${m}:${h}:${f||"all"}`,y=await P.get(b,w);if(y)return new Response(JSON.stringify(y),{headers:{"Content-Type":"application/json","X-Cache":"HIT","Cache-Control":"private, no-cache"}});let E=await i.getAnalytics(c,p,m,h,f);return await P.set(b,w,E,60),new Response(JSON.stringify(E),{headers:{"Content-Type":"application/json","X-Cache":"MISS","Cache-Control":"private, no-cache"}})}return new Response("Not Found",{status:404})}async function al(n,e,t,r,s,o){let i=new ae(e.DB),c=s[4];if(c==="status"&&n.method==="GET"){let[a,l,d,u]=await Promise.all([e.DB.prepare("SELECT public_key, created_at, is_active FROM user_log_keys WHERE profile_id = ?").bind(r.id).first(),e.DB.prepare(`
422
422
  SELECT upwk.passkey_id
423
423
  FROM user_passkey_wrapped_keys upwk
424
424
  JOIN passkeys pk ON upwk.passkey_id = pk.id
425
425
  WHERE pk.user_id = ?
426
- `).bind(n.id).all(),e.DB.prepare("SELECT profile_id FROM user_recovery_wrapped_keys WHERE profile_id = ?").bind(r.id).first(),i.listByUser(n.id)]);return Response.json({hasKeys:!!a,enabled:!!(a&&(a.is_active===void 0||a.is_active===1)),publicKey:a?.public_key||null,wrappedPasskeys:(l.results||[]).map(f=>f.passkey_id),hasRecoveryKey:!!d,userPasskeyCount:u.length,createdAt:a?.created_at||null})}if(c==="wrapped-key"&&t.method==="GET"){let l=new URL(t.url).searchParams.get("passkey_id"),d=null;if(l){let u=await i.getByIdOrCredentialId(l,n.id);u&&(d=await e.DB.prepare("SELECT encrypted_sk, iv FROM user_passkey_wrapped_keys WHERE passkey_id = ?").bind(u.id).first())}return d||(d=await e.DB.prepare(`
426
+ `).bind(t.id).all(),e.DB.prepare("SELECT profile_id FROM user_recovery_wrapped_keys WHERE profile_id = ?").bind(r.id).first(),i.listByUser(t.id)]);return Response.json({hasKeys:!!a,enabled:!!(a&&(a.is_active===void 0||a.is_active===1)),publicKey:a?.public_key||null,wrappedPasskeys:(l.results||[]).map(f=>f.passkey_id),hasRecoveryKey:!!d,userPasskeyCount:u.length,createdAt:a?.created_at||null})}if(c==="wrapped-key"&&n.method==="GET"){let l=new URL(n.url).searchParams.get("passkey_id"),d=null;if(l){let u=await i.getByIdOrCredentialId(l,t.id);u&&(d=await e.DB.prepare("SELECT encrypted_sk, iv FROM user_passkey_wrapped_keys WHERE passkey_id = ?").bind(u.id).first())}return d||(d=await e.DB.prepare(`
427
427
  SELECT upwk.encrypted_sk, upwk.iv
428
428
  FROM user_passkey_wrapped_keys upwk
429
429
  JOIN passkeys pk ON upwk.passkey_id = pk.id
430
430
  WHERE pk.user_id = ?
431
431
  LIMIT 1
432
- `).bind(n.id).first()),d?Response.json({encryptedSk:d.encrypted_sk,iv:d.iv}):new Response("Wrapped key not found for this passkey",{status:404})}if(c==="init"&&t.method==="POST"){let a;try{a=await t.json()}catch{return new Response("Invalid JSON body",{status:400})}let{publicKey:l,passkeyId:d,encryptedSk:u,iv:f,recovery:p}=a;if(!l||!d||!u||!f)return new Response("Missing required fields (publicKey, passkeyId, encryptedSk, iv)",{status:400});let m=await i.getByIdOrCredentialId(d,n.id);if(!m){let b=await i.listByUser(n.id);b.length>0&&(m=b[0])}if(!m)return new Response("Passkey not found or unauthorized",{status:403});let h=Math.floor(Date.now()/1e3),g=typeof l=="string"?l:JSON.stringify(l),w=[e.DB.prepare("INSERT INTO user_log_keys (profile_id, public_key, created_at) VALUES (?, ?, ?) ON CONFLICT(profile_id) DO UPDATE SET public_key = excluded.public_key, created_at = excluded.created_at").bind(r.id,g,h),e.DB.prepare("INSERT INTO user_passkey_wrapped_keys (passkey_id, profile_id, encrypted_sk, iv, created_at) VALUES (?, ?, ?, ?, ?) ON CONFLICT(passkey_id) DO UPDATE SET encrypted_sk = excluded.encrypted_sk, iv = excluded.iv, created_at = excluded.created_at").bind(m.id,r.id,u,f,h)];return p&&p.encryptedSk&&p.iv&&p.salt&&w.push(e.DB.prepare("INSERT INTO user_recovery_wrapped_keys (profile_id, encrypted_sk, iv, salt, created_at) VALUES (?, ?, ?, ?, ?) ON CONFLICT(profile_id) DO UPDATE SET encrypted_sk = excluded.encrypted_sk, iv = excluded.iv, salt = excluded.salt, created_at = excluded.created_at").bind(r.id,p.encryptedSk,p.iv,p.salt,h)),await e.DB.batch(w),Yt(r.id),Response.json({success:!0})}if(c==="wrap"&&t.method==="POST"){let a;try{a=await t.json()}catch{return new Response("Invalid JSON body",{status:400})}let{passkeyId:l,encryptedSk:d,iv:u}=a;if(!l||!d||!u)return new Response("Missing required fields (passkeyId, encryptedSk, iv)",{status:400});let f=await i.getByIdOrCredentialId(l,n.id);if(!f){let m=await i.listByUser(n.id);m.length>0&&(f=m[0])}if(!f)return new Response("Passkey not found or unauthorized",{status:403});let p=Math.floor(Date.now()/1e3);return await e.DB.prepare("INSERT INTO user_passkey_wrapped_keys (passkey_id, profile_id, encrypted_sk, iv, created_at) VALUES (?, ?, ?, ?, ?) ON CONFLICT(passkey_id) DO UPDATE SET encrypted_sk = excluded.encrypted_sk, iv = excluded.iv, created_at = excluded.created_at").bind(f.id,r.id,d,u,p).run(),Response.json({success:!0})}return t.method==="DELETE"&&(!c||c==="keys")?(await e.DB.batch([e.DB.prepare("DELETE FROM user_log_keys WHERE profile_id = ?").bind(r.id),e.DB.prepare("DELETE FROM user_passkey_wrapped_keys WHERE profile_id = ?").bind(r.id),e.DB.prepare("DELETE FROM user_recovery_wrapped_keys WHERE profile_id = ?").bind(r.id)]),Yt(r.id),Response.json({success:!0})):new Response("Not Found",{status:404})}async function nl(t,e,n,r){let o=new URL(t.url).pathname.split("/").filter(Boolean),i=new q(e.DB);if(o.length===2)return n?Gc(t,e,n,o):new Response("Unauthorized",{status:401});if(o.length>=3){let c=o[2],a=await i.getById(c);if(!a)return new Response("Profile Not Found",{status:404});if(!n)return new Response("Unauthorized",{status:401});if(!Wn.canAccessProfile(n,a))return new Response("Profile Not Found",{status:404});let l=o[3];if(!l||["rotate_key","settings","test"].includes(l))return Yc(t,e,n,a,o,r);switch(l){case"access_points":return Xc(t,e,n,c,o,r);case"rules":return zc(t,e,n,c,o,r);case"lists":return Zc(t,e,n,c,o,r);case"logs":case"analytics":return el(t,e,n,a,o,r);case"e2ee":return tl(t,e,n,a,o,r);default:return new Response("Not Found",{status:404})}}return new Response("Not Found",{status:404})}pe();async function rl(t,e,n,r,s){let o=new Y(e.DB,e),i=new Oe(e.DB),c=r[2];if(c==="me"){if(t.method==="GET"){let a=await o.getById(n.id),l=e.MAX_LOG_RETENTION_DAYS!==void 0&&e.MAX_LOG_RETENTION_DAYS!==""?Number(e.MAX_LOG_RETENTION_DAYS):30,d=e.ADMIN_USER_MAX_LOG_RETENTION_DAYS!==void 0&&e.ADMIN_USER_MAX_LOG_RETENTION_DAYS!==""?Math.min(Number(e.ADMIN_USER_MAX_LOG_RETENTION_DAYS),l):l,u=e.NORMAL_USER_MAX_LOG_RETENTION_DAYS!==void 0&&e.NORMAL_USER_MAX_LOG_RETENTION_DAYS!==""?Math.min(Number(e.NORMAL_USER_MAX_LOG_RETENTION_DAYS),l):Math.min(7,l),p=await new ae(e.DB).countByUser(n.id),m=!!a?.totp_enabled||p>0,h=!1;if(a?.totp_recovery_keys)try{let w=typeof a.totp_recovery_keys=="string"?JSON.parse(a.totp_recovery_keys):a.totp_recovery_keys;Array.isArray(w)&&w.length>0&&(h=!0)}catch{h=!0}else a?.totp_recovery_keys_encrypted&&(h=!0);let g=n.role==="admin"?ke(e.JWT_SECRET)&&!gt(e.JWT_SECRET):!1;return new Response(JSON.stringify({id:n.id,username:a?.username||"",role:n.role,totp_enabled:!!a?.totp_enabled,totp_skip_password:!!a?.totp_skip_password,passkeys_count:p,mfa_enabled:m,has_recovery_keys:h,recovery_keys_encrypted:!!a?.totp_recovery_keys_encrypted,timezone:a?.timezone||null,locale:a?.locale||"en-US",password_version:a?.password_version??1,pin_enabled:!!a?.pin_hash,session_lock_timeout:a?.session_lock_timeout??15,max_log_retention_days:n.role==="admin"?d:u,jwt_secret_warning:g}),{headers:{"Content-Type":"application/json"}})}if(t.method==="PATCH"){let a=await t.json();try{if(a.session_lock_timeout!==void 0){let l=Number(a.session_lock_timeout);await o.updateSessionLockTimeout(n.id,l)}if(a.username!==void 0){let l=a.username;if(!l||!Et.test(l))return new Response("Username format error",{status:400});await o.updateUsername(n.id,l)}if(a.timezone!==void 0){let l=a.timezone;if(l!==null&&typeof l=="string"&&l!=="")try{Intl.DateTimeFormat(void 0,{timeZone:l})}catch{return new Response("Invalid timezone format",{status:400})}await o.updateTimezone(n.id,l||null)}if(a.locale!==void 0){let l=a.locale;if(l!==null&&typeof l=="string"&&l!=="")try{Intl.DateTimeFormat(l)}catch{return new Response("Invalid locale format",{status:400})}await o.updateLocale(n.id,l||"en-US")}return new Response(JSON.stringify({success:!0}))}catch(l){return l.message?.includes("UNIQUE constraint failed")?new Response("The username is already taken",{status:400}):new Response("Failed to update settings",{status:500})}}return new Response("Method Not Allowed",{status:405})}if(c==="logs"&&t.method==="DELETE")return await i.deleteByOwner(n.id),new Response(JSON.stringify({success:!0}));if(c==="delete"&&t.method==="POST"){let{invalidateSession:a}=await Promise.resolve().then(()=>(pe(),ur)),l=t.headers.get("Cookie")||"",d=De(l),u=d&&Ae(d)?.sid||null;return u&&await a(e,u),await o.delete(n.id),new Response(JSON.stringify({success:!0}),{headers:{"Set-Cookie":Ye(),"Content-Type":"application/json"}})}return new Response("Not Found",{status:404})}Re();Re();ge();async function rn(t,e,n,r){if(e.passkeyAssertion){let o=caches.default,i=await P.get(o,`webauthn_auth_challenge:${t.id}`);if(!i)return{success:!1,error:"Passkey session expired, please try again",reason:"passkey_session_expired"};let c=new ae(n.DB),l=(await c.listByUser(t.id)).find(u=>u.credential_id===e.passkeyAssertion.id);if(!l)return{success:!1,error:"Passkey not found",reason:"passkey_not_found"};let d=new URL(r.url);try{let{signCount:u}=await Kn({clientDataJSON:e.passkeyAssertion.response.clientDataJSON,authenticatorData:e.passkeyAssertion.response.authenticatorData,signature:e.passkeyAssertion.response.signature,publicKeySpki:l.public_key,algorithm:l.algorithm,expectedChallenge:i.challenge,expectedOrigin:`${d.protocol}//${d.host}`,expectedRpId:i.rpId,previousSignCount:l.sign_count});return await c.updateUsage(l.id,u),await P.delete(o,`webauthn_auth_challenge:${t.id}`),{success:!0,method:"passkey"}}catch{return{success:!1,error:"Invalid Passkey signature",reason:"invalid_passkey"}}}if(e.totpTokenHash)return!t.totp_enabled||!t.totp_secret?{success:!1,error:"TOTP is not enabled",reason:"totp_not_enabled"}:await lo(t.totp_secret,e.totpTokenHash,e.totpSalt)?{success:!0,method:"totp"}:{success:!1,error:"Invalid TOTP code",reason:"invalid_totp"};let s=e.oldPassword||e.password;if(s)return await mt(s,t.hashed_password,t.password_version??1)?{success:!0,method:"password"}:{success:!1,error:"Current password is incorrect",reason:"wrong_current_password"};if(e.recoveryKey){let o=[];try{o=typeof t.totp_recovery_keys=="string"?JSON.parse(t.totp_recovery_keys):t.totp_recovery_keys||[]}catch{}return await Hn(e.recoveryKey,o)===-1?{success:!1,error:"Invalid Recovery Key",reason:"invalid_recovery_key"}:{success:!0,method:"recovery_key"}}return{success:!1,error:"Authentication required (Passkey, Recovery Key, or Password)",reason:"no_credentials_provided"}}async function sl(t,e,n,r,s){let o=new Y(e.DB,e),i=new oe(e.DB),c=t.headers.get("CF-Connecting-IP")||"127.0.0.1",a=t.headers.get("User-Agent"),l=r[2],d=n.sessionId?await re(n.sessionId,n.id):null;if(l==="password"&&t.method==="POST"){let u=await t.json(),{newPassword:f}=u;if(!f||!bt.test(f))return new Response("Password format error",{status:400});let p=await o.getById(n.id);if(!p)return new Response("User not found",{status:404});let m=await rn(p,u,e,t);if(!m.success)return await i.record(n.id,"password_change_fail",c,a,{reason:m.reason},d),new Response(m.error||"Authentication failed",{status:400});let h=await et(f,2);return await o.updatePassword(n.id,h,2),await i.record(n.id,"password_change_success",c,a,{method:m.method},d),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}if(l==="migrate-password"&&t.method==="POST"){let u=await t.json(),{clientHash:f}=u;if(!f)return new Response("Missing clientHash",{status:400});let p=await o.getById(n.id);if(!p)return new Response("User not found",{status:404});let m=await rn(p,u,e,t);if(!m.success)return await i.record(n.id,"password_change_fail",c,a,{reason:m.reason,flow:"migration"},d),new Response(m.error||"Authentication failed",{status:400});if((p.password_version??1)===1){let h=await et(f,2);await o.updatePassword(n.id,h,2),await i.record(n.id,"password_change_success",c,a,{method:"migration"},d)}return new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}return new Response("Not Found",{status:404})}Re();async function ol(t,e,n,r,s){let o=new Y(e.DB,e),i=new oe(e.DB),c=t.headers.get("CF-Connecting-IP")||"127.0.0.1",a=t.headers.get("User-Agent"),l=r[2],d=n.sessionId?await re(n.sessionId,n.id):null;if(l==="totp"){let u=r[3];if(u==="setup"&&t.method==="GET"){let f=await o.getById(n.id);if(f?.totp_enabled)return new Response("TOTP is already enabled",{status:409});let p=Uc(),m=new URL(t.url).hostname,h=Mc(p,f?.username||"user",m);return new Response(JSON.stringify({secret:p,uri:h}),{headers:{"Content-Type":"application/json"}})}if(u==="confirm"&&t.method==="POST"){let{secret:f,totpTokenHash:p,salt:m}=await t.json();if(!f||!p)return new Response("Missing secret or token",{status:400});if(!await lo(f,p,m))return new Response("Invalid TOTP code",{status:400});let g=uo(),w=await Promise.all(g.map(async b=>({hash:await je(b)})));return await o.updateTOTP(n.id,f,w),await o.updateTOTPSettings(n.id,!0),await i.record(n.id,"totp_setup",c,a,void 0,d),new Response(JSON.stringify({success:!0,recovery_keys:g}),{headers:{"Content-Type":"application/json"}})}if(u==="settings"&&t.method==="PATCH"){let f=await o.getById(n.id),m=await new ae(e.DB).listByUser(n.id);if(!(!!f?.totp_enabled||m.length>0))return new Response("MFA is not enabled",{status:400});let{skip_password:g}=await t.json();return await o.updateTOTPSettings(n.id,!!g),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}if(!u&&t.method==="DELETE"){let{password:f}=await t.json(),p=await o.getById(n.id);if(!p)return new Response("User not found",{status:404});if(!p.totp_skip_password&&(!f||!await mt(f,p.hashed_password,p.password_version??1)))return new Response("Incorrect password",{status:400});let g=(await new ae(e.DB).listByUser(n.id)).length>0;return await o.removeTOTP(n.id,g),await i.record(n.id,"totp_removed",c,a,void 0,d),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}}if(l==="mfa"&&r[3]==="settings"&&t.method==="PATCH"){let u=await o.getById(n.id),p=await new ae(e.DB).listByUser(n.id);if(!(!!u?.totp_enabled||p.length>0))return new Response("MFA is not enabled",{status:400});let{skip_password:h}=await t.json();return await o.updateTOTPSettings(n.id,!!h),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}return new Response("Not Found",{status:404})}async function il(t,e,n,r,s){let o=new Y(e.DB,e),i=await o.getById(n.id);if(!i)return new Response("User not found",{status:404});let c=await t.json(),a=await rn(i,c,e,t);if(!a.success)return new Response(a.error||"Authentication failed",{status:400});if(t.method==="POST"){let{pinHash:l}=c;return!l||!/^[a-fA-F0-9]{64}$/.test(l)?new Response("Invalid PIN hash format",{status:400}):(await o.updatePinHash(n.id,l),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}}))}return t.method==="DELETE"?(await o.updatePinHash(n.id,null),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})):new Response("Method Not Allowed",{status:405})}Re();ge();async function al(t,e,n,r,s){let o=new Y(e.DB,e),i=new ae(e.DB),c=new oe(e.DB),a=t.headers.get("CF-Connecting-IP")||"127.0.0.1",l=t.headers.get("User-Agent"),d=r[3],u=n.sessionId?await re(n.sessionId,n.id):null;if(!d&&t.method==="GET"){let f=await i.listByUser(n.id);return new Response(JSON.stringify(f),{headers:{"Content-Type":"application/json"}})}if(d==="auth-options"&&t.method==="POST"){let f=await i.listByUser(n.id);if(f.length===0)return new Response("No passkeys registered",{status:400});let p=nn(),h=new URL(t.url).hostname,g=caches.default;await P.set(g,`webauthn_auth_challenge:${n.id}`,{challenge:p,rpId:h},300);let w={challenge:p,rpId:h,timeout:6e4,userVerification:"preferred",allowCredentials:f.map(b=>({id:b.credential_id,passkey_id:b.id,type:"public-key",transports:b.transports?JSON.parse(b.transports):void 0}))};return new Response(JSON.stringify(w),{headers:{"Content-Type":"application/json"}})}if(d==="register"&&r[4]==="options"&&t.method==="POST"){let f=await i.listByUser(n.id),p=nn(),h=new URL(t.url).hostname,g=caches.default;await P.set(g,`webauthn_reg_challenge:${n.id}`,{challenge:p,rpId:h},300);let b=(await o.getById(n.id))?.username||n.username||"",y=b?`${b} (${h})`:h,E={challenge:p,rp:{name:h,id:h},user:{id:at(new TextEncoder().encode(n.id)),name:b||h,displayName:y},pubKeyCredParams:[{type:"public-key",alg:-7},{type:"public-key",alg:-257}],authenticatorSelection:{userVerification:"preferred",residentKey:"preferred"},timeout:6e4,excludeCredentials:f.map(_=>({id:_.credential_id,type:"public-key",transports:_.transports?JSON.parse(_.transports):void 0}))};return new Response(JSON.stringify(E),{headers:{"Content-Type":"application/json"}})}if(d==="register"&&r[4]==="verify"&&t.method==="POST"){let f=caches.default,p=await P.get(f,`webauthn_reg_challenge:${n.id}`);if(!p)return new Response("Registration session expired, please try again",{status:400});await P.delete(f,`webauthn_reg_challenge:${n.id}`);let m=await t.json(),{name:h,credential:g}=m;if(!g||!g.response)return new Response("Invalid credential data",{status:400});let w=new URL(t.url),b=`${w.protocol}//${w.host}`;try{let y=await Hc({clientDataJSON:g.response.clientDataJSON,attestationObject:g.response.attestationObject,expectedChallenge:p.challenge,expectedOrigin:b,expectedRpId:p.rpId});if(await i.getByCredentialId(y.credentialId))return new Response("This passkey is already registered",{status:409});let _=(h||"").trim();if(!jo.test(_))return new Response("Invalid Passkey name format",{status:400});let S=Array.isArray(g.response.transports)?g.response.transports:void 0,x=await i.create({userId:n.id,name:_,credentialId:y.credentialId,publicKey:y.publicKeySpki,algorithm:y.algorithm,signCount:y.signCount,transports:S,aaguid:y.aaguid});await o.updateTOTPSettings(n.id,!0);let T=await o.getById(n.id),v=[];if(T){let C=!1;if(T.totp_recovery_keys)try{let L=typeof T.totp_recovery_keys=="string"?JSON.parse(T.totp_recovery_keys):T.totp_recovery_keys;Array.isArray(L)&&L.length>0&&(C=!0)}catch{T.totp_recovery_keys.length>0&&(C=!0)}else T.totp_recovery_keys_encrypted&&(C=!0);if(!C){let L=uo(),H=await Promise.all(L.map(async V=>({hash:await je(V)})));await o.updateRecoveryKeys(n.id,H),v=L}}return await c.record(n.id,"passkey_registered",a,l,{name:_},u),new Response(JSON.stringify({...x,recovery_keys:v.length>0?v:void 0}),{status:201,headers:{"Content-Type":"application/json"}})}catch(y){return console.warn("[Passkey Registration] Verification failed:",y.message||y),new Response(y.message||"Passkey registration failed",{status:400})}}if(d&&t.method==="PATCH"){let f=d,{name:p}=await t.json(),m=(p||"").trim();if(!m||!jo.test(m))return new Response("Invalid Passkey name format",{status:400});if(!await i.getById(f,n.id))return new Response("Passkey not found",{status:404});let g=await i.updateName(f,n.id,m);return new Response(JSON.stringify({success:g}),{headers:{"Content-Type":"application/json"}})}if(d&&t.method==="DELETE"){let f=d,p=await i.getById(f,n.id);if(!p)return new Response("Passkey not found",{status:404});await i.delete(f,n.id),await c.record(n.id,"passkey_deleted",a,l,{name:p.name},u);let m=await i.countByUser(n.id),h=await o.getById(n.id);return m===0&&!h?.totp_enabled&&await o.updateTOTPSettings(n.id,!1),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}return new Response("Not Found",{status:404})}Re();async function cl(t,e,n,r,s){let o=new Y(e.DB,e),i=new oe(e.DB),c=t.headers.get("CF-Connecting-IP")||"127.0.0.1",a=t.headers.get("User-Agent"),l=r[3],d=n.sessionId?await re(n.sessionId,n.id):null;if(l==="rotate"&&t.method==="POST"){let u=await t.json(),f=await o.getById(n.id);if(!f)return new Response("User not found",{status:404});let p=await rn(f,u,e,t);if(!p.success)return new Response(p.error||"Authentication failed",{status:400});if(p.method!=="passkey"&&p.method!=="recovery_key")return new Response("Recovery Key rotation only permits authentication via existing Passkey or original Recovery Key",{status:403});let m=tn(),g=[{hash:await je(m)}];return await o.updateRecoveryKeys(n.id,g),await i.record(n.id,"recovery_key_rotated",c,a,{method:p.method},d),new Response(JSON.stringify({success:!0,recovery_key:m}),{headers:{"Content-Type":"application/json"}})}return new Response("Not Found",{status:404})}async function ll(t,e,n,r,s){switch(r[2]){case"password":case"migrate-password":return sl(t,e,n,r,s);case"totp":case"mfa":return ol(t,e,n,r,s);case"pin":return il(t,e,n,r,s);case"passkeys":return al(t,e,n,r,s);case"recovery-keys":return cl(t,e,n,r,s);default:return new Response("Not Found",{status:404})}}pe();async function dl(t,e,n,r,s){let o=new oe(e.DB),i=t.headers.get("CF-Connecting-IP")||"127.0.0.1",c=t.headers.get("User-Agent"),a=r[2];if(a==="activity"&&t.method==="GET"){let l=new URL(t.url).searchParams,d=Math.min(parseInt(l.get("limit")||"20",10),50),u=l.get("before")?parseInt(l.get("before"),10):void 0,f=await o.listByUser(n.id,d,u);return new Response(JSON.stringify(f),{headers:{"Content-Type":"application/json"}})}if(a==="sessions"){if(!r[3]&&t.method==="GET"){let{SessionModel:l}=await Promise.resolve().then(()=>(Ie(),ir)),u=await new l(e.DB).getSessionsByUser(n.id),f=t.headers.get("Cookie")||"",p=De(f),m=p&&Ae(p)?.sid||null,h=await Promise.all(u.map(async g=>({...g,id:await re(g.id,n.id),is_current:g.id===m})));return new Response(JSON.stringify(h),{headers:{"Content-Type":"application/json"}})}if(r[3]==="others"&&t.method==="DELETE"){let{SessionModel:l}=await Promise.resolve().then(()=>(Ie(),ir)),d=new l(e.DB),u=De(t.headers.get("Cookie")||""),f=u&&Ae(u)?.sid||null;if(!f)return new Response("Current session not found",{status:400});let m=(await d.getSessionsByUser(n.id)).filter(b=>b.id!==f),{invalidateSession:h}=await Promise.resolve().then(()=>(pe(),ur)),{invalidateAuthUserCache:g}=await Promise.resolve().then(()=>(Lr(),Nc));for(let b of m)await h(e,b.id),g(b.id);let w=await re(f,n.id);return await o.record(n.id,"session_revoked",i,c,{reason:"user_revoke_others",count:m.length},w),new Response(JSON.stringify({success:!0,revoked_count:m.length}),{headers:{"Content-Type":"application/json"}})}if(r[3]&&t.method==="DELETE"){let l=r[3],{SessionModel:d}=await Promise.resolve().then(()=>(Ie(),ir)),f=await new d(e.DB).getSessionsByUser(n.id),p=null;for(let b of f)if(await re(b.id,n.id)===l){p=b.id;break}if(!p)return new Response("Not Found",{status:404});let{invalidateSession:m}=await Promise.resolve().then(()=>(pe(),ur));await m(e,p);let h=De(t.headers.get("Cookie")||""),g=h&&Ae(h)?.sid||null,w=g?await re(g,n.id):null;return await o.record(n.id,"session_revoked",i,c,{reason:"user_revoke",target_session:l},l),p===g?new Response(JSON.stringify({success:!0,is_current:!0}),{headers:{"Set-Cookie":Ye(),"Content-Type":"application/json"}}):new Response(JSON.stringify({success:!0,is_current:!1}),{headers:{"Content-Type":"application/json"}})}}return new Response("Not Found",{status:404})}async function ul(t,e,n,r,s){let o=new ae(e.DB),i=new q(e.DB),c=r[3];if(c==="status"&&t.method==="GET"){let[a,l]=await Promise.all([i.listByOwner(n.id),o.listByUser(n.id)]),d=null,u=[],f=null;if(a.length>0){let[p,m,h]=await Promise.all([e.DB.prepare("SELECT public_key, created_at, is_active FROM user_log_keys WHERE profile_id IN (SELECT id FROM profiles WHERE owner_id = ?) LIMIT 1").bind(n.id).first(),e.DB.prepare(`
432
+ `).bind(t.id).first()),d?Response.json({encryptedSk:d.encrypted_sk,iv:d.iv}):new Response("Wrapped key not found for this passkey",{status:404})}if(c==="init"&&n.method==="POST"){let a;try{a=await n.json()}catch{return new Response("Invalid JSON body",{status:400})}let{publicKey:l,passkeyId:d,encryptedSk:u,iv:f,recovery:p}=a;if(!l||!d||!u||!f)return new Response("Missing required fields (publicKey, passkeyId, encryptedSk, iv)",{status:400});let m=await i.getByIdOrCredentialId(d,t.id);if(!m){let w=await i.listByUser(t.id);w.length>0&&(m=w[0])}if(!m)return new Response("Passkey not found or unauthorized",{status:403});let h=Math.floor(Date.now()/1e3),g=typeof l=="string"?l:JSON.stringify(l),b=[e.DB.prepare("INSERT INTO user_log_keys (profile_id, public_key, created_at) VALUES (?, ?, ?) ON CONFLICT(profile_id) DO UPDATE SET public_key = excluded.public_key, created_at = excluded.created_at").bind(r.id,g,h),e.DB.prepare("INSERT INTO user_passkey_wrapped_keys (passkey_id, profile_id, encrypted_sk, iv, created_at) VALUES (?, ?, ?, ?, ?) ON CONFLICT(passkey_id) DO UPDATE SET encrypted_sk = excluded.encrypted_sk, iv = excluded.iv, created_at = excluded.created_at").bind(m.id,r.id,u,f,h)];return p&&p.encryptedSk&&p.iv&&p.salt&&b.push(e.DB.prepare("INSERT INTO user_recovery_wrapped_keys (profile_id, encrypted_sk, iv, salt, created_at) VALUES (?, ?, ?, ?, ?) ON CONFLICT(profile_id) DO UPDATE SET encrypted_sk = excluded.encrypted_sk, iv = excluded.iv, salt = excluded.salt, created_at = excluded.created_at").bind(r.id,p.encryptedSk,p.iv,p.salt,h)),await e.DB.batch(b),en(r.id),Response.json({success:!0})}if(c==="wrap"&&n.method==="POST"){let a;try{a=await n.json()}catch{return new Response("Invalid JSON body",{status:400})}let{passkeyId:l,encryptedSk:d,iv:u}=a;if(!l||!d||!u)return new Response("Missing required fields (passkeyId, encryptedSk, iv)",{status:400});let f=await i.getByIdOrCredentialId(l,t.id);if(!f){let m=await i.listByUser(t.id);m.length>0&&(f=m[0])}if(!f)return new Response("Passkey not found or unauthorized",{status:403});let p=Math.floor(Date.now()/1e3);return await e.DB.prepare("INSERT INTO user_passkey_wrapped_keys (passkey_id, profile_id, encrypted_sk, iv, created_at) VALUES (?, ?, ?, ?, ?) ON CONFLICT(passkey_id) DO UPDATE SET encrypted_sk = excluded.encrypted_sk, iv = excluded.iv, created_at = excluded.created_at").bind(f.id,r.id,d,u,p).run(),Response.json({success:!0})}return n.method==="DELETE"&&(!c||c==="keys")?(await e.DB.batch([e.DB.prepare("DELETE FROM user_log_keys WHERE profile_id = ?").bind(r.id),e.DB.prepare("DELETE FROM user_passkey_wrapped_keys WHERE profile_id = ?").bind(r.id),e.DB.prepare("DELETE FROM user_recovery_wrapped_keys WHERE profile_id = ?").bind(r.id)]),en(r.id),Response.json({success:!0})):new Response("Not Found",{status:404})}async function cl(n,e,t,r){let o=new URL(n.url).pathname.split("/").filter(Boolean),i=new q(e.DB);if(o.length===2)return t?qc(n,e,t,o):new Response("Unauthorized",{status:401});if(o.length>=3){let c=o[2],a=await i.getById(c);if(!a)return new Response("Profile Not Found",{status:404});if(!t)return new Response("Unauthorized",{status:401});if(!Yn.canAccessProfile(t,a))return new Response("Profile Not Found",{status:404});let l=o[3];if(!l||["rotate_key","settings","test"].includes(l))return el(n,e,t,a,o,r);switch(l){case"access_points":return tl(n,e,t,c,o,r);case"rules":return nl(n,e,t,c,o,r);case"lists":return sl(n,e,t,c,o,r);case"logs":case"analytics":return il(n,e,t,a,o,r);case"e2ee":return al(n,e,t,a,o,r);default:return new Response("Not Found",{status:404})}}return new Response("Not Found",{status:404})}pe();function Bi(n){if(!Number.isFinite(n)||n<=0)return"0 B";let e=["B","KB","MB","GB","TB"],t=Math.min(Math.floor(Math.log(n)/Math.log(1024)),e.length-1),r=n/Math.pow(1024,t);return`${r<10?r.toFixed(2):r<100?r.toFixed(1):r.toFixed(0)} ${e[t]}`}async function ll(n){let e=n.DB;if(typeof e?.getDatabaseSize=="function")try{let t=e.getDatabaseSize();return{size_bytes:t,formatted:Bi(t),mode:"serverfull"}}catch(t){console.warn("[dbSize] Serverfull size calculation warning:",t)}try{let t=await n.DB.prepare("SELECT name FROM sqlite_master WHERE type='table';").all(),r=new Set((t.results||[]).map(i=>i.name)),s=[];r.has("profile_blooms")&&s.push("(SELECT coalesce(sum(length(bloom_filter_chunk)), 0) FROM profile_blooms)"),r.has("list_blooms")&&s.push("(SELECT coalesce(sum(length(bloom_filter_chunk)), 0) FROM list_blooms)"),r.has("profile_blooms_staging")&&s.push("(SELECT coalesce(sum(length(bloom_filter_chunk)), 0) FROM profile_blooms_staging)"),r.has("logs")&&s.push("(SELECT count(*) * 512 FROM logs)"),r.has("user_activity_log")&&s.push("(SELECT count(*) * 256 FROM user_activity_log)"),r.has("domain_hourly_rollups")&&s.push("(SELECT count(*) * 128 FROM domain_hourly_rollups)"),r.has("rules")&&s.push("(SELECT count(*) * 256 FROM rules)"),r.has("lists")&&s.push("(SELECT count(*) * 512 FROM lists)"),r.has("users")&&s.push("(SELECT count(*) * 1024 FROM users)"),r.has("profiles")&&s.push("(SELECT count(*) * 512 FROM profiles)"),r.has("access_points")&&s.push("(SELECT count(*) * 256 FROM access_points)"),r.has("sessions")&&s.push("(SELECT count(*) * 256 FROM sessions)"),r.has("passkeys")&&s.push("(SELECT count(*) * 512 FROM passkeys)"),r.has("kem_keys")&&s.push("(SELECT count(*) * 1024 FROM kem_keys)");let o=65536;if(s.length>0){let i=`SELECT (${s.join(" + ")} + 65536) AS size_bytes;`,c=await n.DB.prepare(i).first();c?.size_bytes!==void 0&&c.size_bytes!==null&&(o=Math.max(65536,Number(c.size_bytes)))}return{size_bytes:o,formatted:Bi(o),mode:"serverless"}}catch(t){return console.warn("[dbSize] Serverless D1 size calculation warning:",t),{size_bytes:65536,formatted:Bi(65536),mode:"serverless"}}}async function dl(n,e,t,r,s){let o=new Y(e.DB,e),i=new Ie(e.DB),c=r[2];if(c==="me"){if(n.method==="GET"){let a=await o.getById(t.id),l=e.MAX_LOG_RETENTION_DAYS!==void 0&&e.MAX_LOG_RETENTION_DAYS!==""?Number(e.MAX_LOG_RETENTION_DAYS):30,d=e.ADMIN_USER_MAX_LOG_RETENTION_DAYS!==void 0&&e.ADMIN_USER_MAX_LOG_RETENTION_DAYS!==""?Math.min(Number(e.ADMIN_USER_MAX_LOG_RETENTION_DAYS),l):l,u=e.NORMAL_USER_MAX_LOG_RETENTION_DAYS!==void 0&&e.NORMAL_USER_MAX_LOG_RETENTION_DAYS!==""?Math.min(Number(e.NORMAL_USER_MAX_LOG_RETENTION_DAYS),l):Math.min(7,l),p=await new ae(e.DB).countByUser(t.id),m=!!a?.totp_enabled||p>0,h=!1;if(a?.totp_recovery_keys)try{let b=typeof a.totp_recovery_keys=="string"?JSON.parse(a.totp_recovery_keys):a.totp_recovery_keys;Array.isArray(b)&&b.length>0&&(h=!0)}catch{h=!0}else a?.totp_recovery_keys_encrypted&&(h=!0);let g=t.role==="admin"?Oe(e.JWT_SECRET)&&!bt(e.JWT_SECRET):!1;return new Response(JSON.stringify({id:t.id,username:a?.username||"",role:t.role,totp_enabled:!!a?.totp_enabled,totp_skip_password:!!a?.totp_skip_password,passkeys_count:p,mfa_enabled:m,has_recovery_keys:h,recovery_keys_encrypted:!!a?.totp_recovery_keys_encrypted,timezone:a?.timezone||null,locale:a?.locale||"en-US",password_version:a?.password_version??1,pin_enabled:!!a?.pin_hash,session_lock_timeout:a?.session_lock_timeout??15,max_log_retention_days:t.role==="admin"?d:u,jwt_secret_warning:g}),{headers:{"Content-Type":"application/json"}})}if(n.method==="PATCH"){let a=await n.json();try{if(a.session_lock_timeout!==void 0){let l=Number(a.session_lock_timeout);await o.updateSessionLockTimeout(t.id,l)}if(a.username!==void 0){let l=a.username;if(!l||!Rt.test(l))return new Response("Username format error",{status:400});await o.updateUsername(t.id,l)}if(a.timezone!==void 0){let l=a.timezone;if(l!==null&&typeof l=="string"&&l!=="")try{Intl.DateTimeFormat(void 0,{timeZone:l})}catch{return new Response("Invalid timezone format",{status:400})}await o.updateTimezone(t.id,l||null)}if(a.locale!==void 0){let l=a.locale;if(l!==null&&typeof l=="string"&&l!=="")try{Intl.DateTimeFormat(l)}catch{return new Response("Invalid locale format",{status:400})}await o.updateLocale(t.id,l||"en-US")}return new Response(JSON.stringify({success:!0}))}catch(l){return l.message?.includes("UNIQUE constraint failed")?new Response("The username is already taken",{status:400}):new Response("Failed to update settings",{status:500})}}return new Response("Method Not Allowed",{status:405})}if(c==="db-size"&&n.method==="GET"){let a=await ll(e);return new Response(JSON.stringify(a),{headers:{"Content-Type":"application/json"}})}if(c==="logs"&&n.method==="DELETE"){await i.deleteByOwner(t.id);let a=e.DB;return typeof a?.vacuum=="function"&&a.vacuum(),new Response(JSON.stringify({success:!0}))}if(c==="delete"&&n.method==="POST"){let{invalidateSession:a}=await Promise.resolve().then(()=>(pe(),yr)),l=n.headers.get("Cookie")||"",d=Le(l),u=d&&ve(d)?.sid||null;return u&&await a(e,u),await o.delete(t.id),new Response(JSON.stringify({success:!0}),{headers:{"Set-Cookie":Qe(),"Content-Type":"application/json"}})}return new Response("Not Found",{status:404})}Te();Te();ge();async function ln(n,e,t,r){if(e.passkeyAssertion){let o=caches.default,i=await P.get(o,`webauthn_auth_challenge:${n.id}`);if(!i)return{success:!1,error:"Passkey session expired, please try again",reason:"passkey_session_expired"};let c=new ae(t.DB),l=(await c.listByUser(n.id)).find(u=>u.credential_id===e.passkeyAssertion.id);if(!l)return{success:!1,error:"Passkey not found",reason:"passkey_not_found"};let d=new URL(r.url);try{let{signCount:u}=await Nt({clientDataJSON:e.passkeyAssertion.response.clientDataJSON,authenticatorData:e.passkeyAssertion.response.authenticatorData,signature:e.passkeyAssertion.response.signature,publicKeySpki:l.public_key,algorithm:l.algorithm,expectedChallenge:i.challenge,expectedOrigin:`${d.protocol}//${d.host}`,expectedRpId:i.rpId,previousSignCount:l.sign_count});return await c.updateUsage(l.id,u),await P.delete(o,`webauthn_auth_challenge:${n.id}`),{success:!0,method:"passkey"}}catch{return{success:!1,error:"Invalid Passkey signature",reason:"invalid_passkey"}}}if(e.totpTokenHash)return!n.totp_enabled||!n.totp_secret?{success:!1,error:"TOTP is not enabled",reason:"totp_not_enabled"}:await Kr(n.totp_secret,e.totpTokenHash,e.totpSalt)?{success:!0,method:"totp"}:{success:!1,error:"Invalid TOTP code",reason:"invalid_totp"};let s=e.oldPassword||e.password;if(s)return await yt(s,n.hashed_password,n.password_version??1)?{success:!0,method:"password"}:{success:!1,error:"Current password is incorrect",reason:"wrong_current_password"};if(e.recoveryKey){let o=[];try{o=typeof n.totp_recovery_keys=="string"?JSON.parse(n.totp_recovery_keys):n.totp_recovery_keys||[]}catch{}return await Gn(e.recoveryKey,o)===-1?{success:!1,error:"Invalid Recovery Key",reason:"invalid_recovery_key"}:{success:!0,method:"recovery_key"}}return{success:!1,error:"Authentication required (Passkey, Recovery Key, or Password)",reason:"no_credentials_provided"}}async function ul(n,e,t,r,s){let o=new Y(e.DB,e),i=new oe(e.DB),c=n.headers.get("CF-Connecting-IP")||"127.0.0.1",a=n.headers.get("User-Agent"),l=r[2],d=t.sessionId?await re(t.sessionId,t.id):null;if(l==="password"&&n.method==="POST"){let u=await n.json(),{newPassword:f}=u;if(!f||!St.test(f))return new Response("Password format error",{status:400});let p=await o.getById(t.id);if(!p)return new Response("User not found",{status:404});let m=await ln(p,u,e,n);if(!m.success)return await i.record(t.id,"password_change_fail",c,a,{reason:m.reason},d),new Response(m.error||"Authentication failed",{status:400});let h=await ot(f,2);return await o.updatePassword(t.id,h,2),await i.record(t.id,"password_change_success",c,a,{method:m.method},d),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}if(l==="migrate-password"&&n.method==="POST"){let u=await n.json(),{clientHash:f}=u;if(!f)return new Response("Missing clientHash",{status:400});let p=await o.getById(t.id);if(!p)return new Response("User not found",{status:404});let m=await ln(p,u,e,n);if(!m.success)return await i.record(t.id,"password_change_fail",c,a,{reason:m.reason,flow:"migration"},d),new Response(m.error||"Authentication failed",{status:400});if((p.password_version??1)===1){let h=await ot(f,2);await o.updatePassword(t.id,h,2),await i.record(t.id,"password_change_success",c,a,{method:"migration"},d)}return new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}return new Response("Not Found",{status:404})}Te();async function pl(n,e,t,r,s){let o=new Y(e.DB,e),i=new oe(e.DB),c=n.headers.get("CF-Connecting-IP")||"127.0.0.1",a=n.headers.get("User-Agent"),l=r[2],d=t.sessionId?await re(t.sessionId,t.id):null;if(l==="totp"){let u=r[3];if(u==="setup"&&n.method==="GET"){let f=await o.getById(t.id);if(f?.totp_enabled)return new Response("TOTP is already enabled",{status:409});let p=Kc(),m=new URL(n.url).hostname,h=Wc(p,f?.username||"user",m);return new Response(JSON.stringify({secret:p,uri:h}),{headers:{"Content-Type":"application/json"}})}if(u==="confirm"&&n.method==="POST"){let{secret:f,totpTokenHash:p,salt:m}=await n.json();if(!f||!p)return new Response("Missing secret or token",{status:400});if(!await Kr(f,p,m))return new Response("Invalid TOTP code",{status:400});let g=go(),b=await Promise.all(g.map(async w=>({hash:await Ge(w)})));return await o.updateTOTP(t.id,f,b),await o.updateTOTPSettings(t.id,!0),await i.record(t.id,"totp_setup",c,a,void 0,d),new Response(JSON.stringify({success:!0,recovery_keys:g}),{headers:{"Content-Type":"application/json"}})}if(u==="test"&&n.method==="POST"){let f=await o.getById(t.id);if(!f?.totp_enabled||!f?.totp_secret)return new Response(JSON.stringify({success:!1,message:"TOTP is not enabled"}),{status:400,headers:{"Content-Type":"application/json"}});let{token:p,totpTokenHash:m,salt:h}=await n.json(),g=m||p;return g?await Kr(f.totp_secret,g,h)?(await i.record(t.id,"totp_verify_success",c,a,{flow:"mfa_test"},d),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})):(await i.record(t.id,"totp_verify_fail",c,a,{flow:"mfa_test"},d),new Response(JSON.stringify({success:!1,message:"Invalid TOTP code"}),{status:400,headers:{"Content-Type":"application/json"}})):new Response(JSON.stringify({success:!1,message:"Missing token"}),{status:400,headers:{"Content-Type":"application/json"}})}if(u==="settings"&&n.method==="PATCH"){let f=await o.getById(t.id),m=await new ae(e.DB).listByUser(t.id);if(!(!!f?.totp_enabled||m.length>0))return new Response("MFA is not enabled",{status:400});let{skip_password:g}=await n.json();return await o.updateTOTPSettings(t.id,!!g),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}if(!u&&n.method==="DELETE"){let{password:f}=await n.json(),p=await o.getById(t.id);if(!p)return new Response("User not found",{status:404});if(!p.totp_skip_password&&(!f||!await yt(f,p.hashed_password,p.password_version??1)))return new Response("Incorrect password",{status:400});let g=(await new ae(e.DB).listByUser(t.id)).length>0;return await o.removeTOTP(t.id,g),await i.record(t.id,"totp_removed",c,a,void 0,d),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}}if(l==="mfa"&&r[3]==="settings"&&n.method==="PATCH"){let u=await o.getById(t.id),p=await new ae(e.DB).listByUser(t.id);if(!(!!u?.totp_enabled||p.length>0))return new Response("MFA is not enabled",{status:400});let{skip_password:h}=await n.json();return await o.updateTOTPSettings(t.id,!!h),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}return new Response("Not Found",{status:404})}async function fl(n,e,t,r,s){let o=new Y(e.DB,e),i=await o.getById(t.id);if(!i)return new Response("User not found",{status:404});let c=await n.json(),a=await ln(i,c,e,n);if(!a.success)return new Response(a.error||"Authentication failed",{status:400});if(n.method==="POST"){let{pinHash:l}=c;return!l||!/^[a-fA-F0-9]{64}$/.test(l)?new Response("Invalid PIN hash format",{status:400}):(await o.updatePinHash(t.id,l),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}}))}return n.method==="DELETE"?(await o.updatePinHash(t.id,null),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})):new Response("Method Not Allowed",{status:405})}Te();ge();async function ml(n,e,t,r,s){let o=new Y(e.DB,e),i=new ae(e.DB),c=new oe(e.DB),a=n.headers.get("CF-Connecting-IP")||"127.0.0.1",l=n.headers.get("User-Agent"),d=r[3],u=t.sessionId?await re(t.sessionId,t.id):null;if(!d&&n.method==="GET"){let f=await i.listByUser(t.id);return new Response(JSON.stringify(f),{headers:{"Content-Type":"application/json"}})}if(d==="auth-options"&&n.method==="POST"){let f=await i.listByUser(t.id);if(f.length===0)return new Response("No passkeys registered",{status:400});let p;try{n.headers.get("content-type")?.includes("application/json")&&(p=(await n.json())?.passkeyId)}catch{}let m=p?f.filter(E=>E.id===p):f;if(m.length===0)return new Response("Target passkey not found",{status:404});let h=cn(),b=new URL(n.url).hostname,w=caches.default;await P.set(w,`webauthn_auth_challenge:${t.id}`,{challenge:h,rpId:b},300);let y={challenge:h,rpId:b,timeout:6e4,userVerification:"preferred",allowCredentials:m.map(E=>({id:E.credential_id,passkey_id:E.id,type:"public-key",transports:E.transports?JSON.parse(E.transports):void 0}))};return new Response(JSON.stringify(y),{headers:{"Content-Type":"application/json"}})}if(d==="test"&&n.method==="POST"){let f=caches.default,p=await P.get(f,`webauthn_auth_challenge:${t.id}`);if(!p)return new Response("Test session expired, please try again",{status:400});let m=await n.json(),h=m.credential||m.passkeyAssertion||m;if(!h||!h.response||!h.id)return new Response("Invalid credential data",{status:400});let b=(await i.listByUser(t.id)).find(y=>y.credential_id===h.id);if(!b)return new Response("Passkey not recognized for this account",{status:404});let w=new URL(n.url);try{let{signCount:y}=await Nt({clientDataJSON:h.response.clientDataJSON,authenticatorData:h.response.authenticatorData,signature:h.response.signature,publicKeySpki:b.public_key,algorithm:b.algorithm,expectedChallenge:p.challenge,expectedOrigin:`${w.protocol}//${w.host}`,expectedRpId:p.rpId,previousSignCount:b.sign_count});return await i.updateUsage(b.id,y),await P.delete(f,`webauthn_auth_challenge:${t.id}`),await c.record(t.id,"passkey_verify_success",a,l,{flow:"mfa_test",name:b.name,id:b.id},u),new Response(JSON.stringify({success:!0,passkey:{id:b.id,name:b.name}}),{headers:{"Content-Type":"application/json"}})}catch(y){return await c.record(t.id,"passkey_verify_fail",a,l,{flow:"mfa_test",name:b.name,id:b.id,error:y.message||"failed"},u),console.warn("[Passkey Test] Verification failed:",y.message||y),new Response(y.message||"Passkey verification failed",{status:400})}}if(d==="register"&&r[4]==="options"&&n.method==="POST"){let f=await i.listByUser(t.id),p=cn(),h=new URL(n.url).hostname,g=caches.default;await P.set(g,`webauthn_reg_challenge:${t.id}`,{challenge:p,rpId:h},300);let w=(await o.getById(t.id))?.username||t.username||"",y=w?`${w} (${h})`:h,E={challenge:p,rp:{name:h,id:h},user:{id:ft(new TextEncoder().encode(t.id)),name:w||h,displayName:y},pubKeyCredParams:[{type:"public-key",alg:-7},{type:"public-key",alg:-257}],authenticatorSelection:{userVerification:"preferred",residentKey:"preferred"},timeout:6e4,excludeCredentials:f.map(_=>({id:_.credential_id,type:"public-key",transports:_.transports?JSON.parse(_.transports):void 0}))};return new Response(JSON.stringify(E),{headers:{"Content-Type":"application/json"}})}if(d==="register"&&r[4]==="verify"&&n.method==="POST"){let f=caches.default,p=await P.get(f,`webauthn_reg_challenge:${t.id}`);if(!p)return new Response("Registration session expired, please try again",{status:400});await P.delete(f,`webauthn_reg_challenge:${t.id}`);let m=await n.json(),{name:h,credential:g}=m;if(!g||!g.response)return new Response("Invalid credential data",{status:400});let b=new URL(n.url),w=`${b.protocol}//${b.host}`;try{let y=await Gc({clientDataJSON:g.response.clientDataJSON,attestationObject:g.response.attestationObject,expectedChallenge:p.challenge,expectedOrigin:w,expectedRpId:p.rpId});if(await i.getByCredentialId(y.credentialId))return new Response("This passkey is already registered",{status:409});let _=(h||"").trim();if(!Xo.test(_))return new Response("Invalid Passkey name format",{status:400});let S=Array.isArray(g.response.transports)?g.response.transports:void 0,x=await i.create({userId:t.id,name:_,credentialId:y.credentialId,publicKey:y.publicKeySpki,algorithm:y.algorithm,signCount:y.signCount,transports:S,aaguid:y.aaguid});await o.updateTOTPSettings(t.id,!0);let T=await o.getById(t.id),v=[];if(T){let C=!1;if(T.totp_recovery_keys)try{let L=typeof T.totp_recovery_keys=="string"?JSON.parse(T.totp_recovery_keys):T.totp_recovery_keys;Array.isArray(L)&&L.length>0&&(C=!0)}catch{T.totp_recovery_keys.length>0&&(C=!0)}else T.totp_recovery_keys_encrypted&&(C=!0);if(!C){let L=go(),H=await Promise.all(L.map(async V=>({hash:await Ge(V)})));await o.updateRecoveryKeys(t.id,H),v=L}}return await c.record(t.id,"passkey_registered",a,l,{name:_},u),new Response(JSON.stringify({...x,recovery_keys:v.length>0?v:void 0}),{status:201,headers:{"Content-Type":"application/json"}})}catch(y){return console.warn("[Passkey Registration] Verification failed:",y.message||y),new Response(y.message||"Passkey registration failed",{status:400})}}if(d&&n.method==="PATCH"){let f=d,{name:p}=await n.json(),m=(p||"").trim();if(!m||!Xo.test(m))return new Response("Invalid Passkey name format",{status:400});if(!await i.getById(f,t.id))return new Response("Passkey not found",{status:404});let g=await i.updateName(f,t.id,m);return new Response(JSON.stringify({success:g}),{headers:{"Content-Type":"application/json"}})}if(d&&n.method==="DELETE"){let f=d,p=await i.getById(f,t.id);if(!p)return new Response("Passkey not found",{status:404});await i.delete(f,t.id),await c.record(t.id,"passkey_deleted",a,l,{name:p.name},u);let m=await i.countByUser(t.id),h=await o.getById(t.id);return m===0&&!h?.totp_enabled&&await o.updateTOTPSettings(t.id,!1),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}return new Response("Not Found",{status:404})}Te();async function hl(n,e,t,r,s){let o=new Y(e.DB,e),i=new oe(e.DB),c=n.headers.get("CF-Connecting-IP")||"127.0.0.1",a=n.headers.get("User-Agent"),l=r[3],d=t.sessionId?await re(t.sessionId,t.id):null;if(l==="rotate"&&n.method==="POST"){let u=await n.json(),f=await o.getById(t.id);if(!f)return new Response("User not found",{status:404});let p=await ln(f,u,e,n);if(!p.success)return new Response(p.error||"Authentication failed",{status:400});if(p.method!=="passkey"&&p.method!=="recovery_key")return new Response("Recovery Key rotation only permits authentication via existing Passkey or original Recovery Key",{status:403});let m=an(),g=[{hash:await Ge(m)}];return await o.updateRecoveryKeys(t.id,g),await i.record(t.id,"recovery_key_rotated",c,a,{method:p.method},d),new Response(JSON.stringify({success:!0,recovery_key:m}),{headers:{"Content-Type":"application/json"}})}return new Response("Not Found",{status:404})}async function gl(n,e,t,r,s){switch(r[2]){case"password":case"migrate-password":return ul(n,e,t,r,s);case"totp":case"mfa":return pl(n,e,t,r,s);case"pin":return fl(n,e,t,r,s);case"passkeys":return ml(n,e,t,r,s);case"recovery-keys":return hl(n,e,t,r,s);default:return new Response("Not Found",{status:404})}}pe();async function yl(n,e,t,r,s){let o=new oe(e.DB),i=n.headers.get("CF-Connecting-IP")||"127.0.0.1",c=n.headers.get("User-Agent"),a=r[2];if(a==="activity"&&n.method==="GET"){let l=new URL(n.url).searchParams,d=Math.min(parseInt(l.get("limit")||"20",10),50),u=l.get("before")?parseInt(l.get("before"),10):void 0,f=await o.listByUser(t.id,d,u);return new Response(JSON.stringify(f),{headers:{"Content-Type":"application/json"}})}if(a==="sessions"){if(!r[3]&&n.method==="GET"){let{SessionModel:l}=await Promise.resolve().then(()=>(Be(),pr)),u=await new l(e.DB).getSessionsByUser(t.id),f=n.headers.get("Cookie")||"",p=Le(f),m=p&&ve(p)?.sid||null,h=await Promise.all(u.map(async g=>({...g,id:await re(g.id,t.id),is_current:g.id===m})));return new Response(JSON.stringify(h),{headers:{"Content-Type":"application/json"}})}if(r[3]==="others"&&n.method==="DELETE"){let{SessionModel:l}=await Promise.resolve().then(()=>(Be(),pr)),d=new l(e.DB),u=Le(n.headers.get("Cookie")||""),f=u&&ve(u)?.sid||null;if(!f)return new Response("Current session not found",{status:400});let m=(await d.getSessionsByUser(t.id)).filter(w=>w.id!==f),{invalidateSession:h}=await Promise.resolve().then(()=>(pe(),yr)),{invalidateAuthUserCache:g}=await Promise.resolve().then(()=>(Hr(),Hc));for(let w of m)await h(e,w.id),g(w.id);let b=await re(f,t.id);return await o.record(t.id,"session_revoked",i,c,{reason:"user_revoke_others",count:m.length},b),new Response(JSON.stringify({success:!0,revoked_count:m.length}),{headers:{"Content-Type":"application/json"}})}if(r[3]&&n.method==="DELETE"){let l=r[3],{SessionModel:d}=await Promise.resolve().then(()=>(Be(),pr)),f=await new d(e.DB).getSessionsByUser(t.id),p=null;for(let w of f)if(await re(w.id,t.id)===l){p=w.id;break}if(!p)return new Response("Not Found",{status:404});let{invalidateSession:m}=await Promise.resolve().then(()=>(pe(),yr));await m(e,p);let h=Le(n.headers.get("Cookie")||""),g=h&&ve(h)?.sid||null,b=g?await re(g,t.id):null;return await o.record(t.id,"session_revoked",i,c,{reason:"user_revoke",target_session:l},l),p===g?new Response(JSON.stringify({success:!0,is_current:!0}),{headers:{"Set-Cookie":Qe(),"Content-Type":"application/json"}}):new Response(JSON.stringify({success:!0,is_current:!1}),{headers:{"Content-Type":"application/json"}})}}return new Response("Not Found",{status:404})}async function wl(n,e,t,r,s){let o=new ae(e.DB),i=new q(e.DB),c=r[3];if(c==="status"&&n.method==="GET"){let[a,l]=await Promise.all([i.listByOwner(t.id),o.listByUser(t.id)]),d=null,u=[],f=null;if(a.length>0){let[p,m,h]=await Promise.all([e.DB.prepare("SELECT public_key, created_at, is_active FROM user_log_keys WHERE profile_id IN (SELECT id FROM profiles WHERE owner_id = ?) LIMIT 1").bind(t.id).first(),e.DB.prepare(`
433
433
  SELECT upwk.passkey_id
434
434
  FROM user_passkey_wrapped_keys upwk
435
435
  JOIN passkeys pk ON upwk.passkey_id = pk.id
436
436
  WHERE pk.user_id = ?
437
- `).bind(n.id).all(),e.DB.prepare("SELECT profile_id FROM user_recovery_wrapped_keys WHERE profile_id IN (SELECT id FROM profiles WHERE owner_id = ?) LIMIT 1").bind(n.id).first()]);d=p,u=m.results||[],f=h}return Response.json({hasKeys:!!d,enabled:!!(d&&(d.is_active===void 0||d.is_active===1)),publicKey:d?.public_key||null,wrappedPasskeys:u.map(p=>p.passkey_id),hasRecoveryKey:!!f,userPasskeyCount:l.length,createdAt:d?.created_at||null})}if(c==="wrapped-key"&&t.method==="GET"){let l=new URL(t.url).searchParams.get("passkey_id"),d=null;if(l){let u=await o.getByIdOrCredentialId(l,n.id);u&&(d=await e.DB.prepare("SELECT encrypted_sk, iv FROM user_passkey_wrapped_keys WHERE passkey_id = ?").bind(u.id).first())}return d||(d=await e.DB.prepare(`
437
+ `).bind(t.id).all(),e.DB.prepare("SELECT profile_id FROM user_recovery_wrapped_keys WHERE profile_id IN (SELECT id FROM profiles WHERE owner_id = ?) LIMIT 1").bind(t.id).first()]);d=p,u=m.results||[],f=h}return Response.json({hasKeys:!!d,enabled:!!(d&&(d.is_active===void 0||d.is_active===1)),publicKey:d?.public_key||null,wrappedPasskeys:u.map(p=>p.passkey_id),hasRecoveryKey:!!f,userPasskeyCount:l.length,createdAt:d?.created_at||null})}if(c==="wrapped-key"&&n.method==="GET"){let l=new URL(n.url).searchParams.get("passkey_id"),d=null;if(l){let u=await o.getByIdOrCredentialId(l,t.id);u&&(d=await e.DB.prepare("SELECT encrypted_sk, iv FROM user_passkey_wrapped_keys WHERE passkey_id = ?").bind(u.id).first())}return d||(d=await e.DB.prepare(`
438
438
  SELECT upwk.encrypted_sk, upwk.iv
439
439
  FROM user_passkey_wrapped_keys upwk
440
440
  JOIN passkeys pk ON upwk.passkey_id = pk.id
441
441
  WHERE pk.user_id = ?
442
442
  LIMIT 1
443
- `).bind(n.id).first()),d?Response.json({encryptedSk:d.encrypted_sk,iv:d.iv}):new Response("Wrapped key not found for this passkey",{status:404})}if(c==="recovery-wrapped-key"&&t.method==="GET"){let a=await e.DB.prepare("SELECT encrypted_sk, iv, salt FROM user_recovery_wrapped_keys WHERE profile_id IN (SELECT id FROM profiles WHERE owner_id = ?) LIMIT 1").bind(n.id).first();return a?Response.json({encryptedSk:a.encrypted_sk,iv:a.iv,salt:a.salt}):new Response("Recovery wrapped key not found",{status:404})}if(c==="init"&&t.method==="POST"){let a;try{a=await t.json()}catch{return new Response("Invalid JSON body",{status:400})}let{publicKey:l,passkeyId:d,encryptedSk:u,iv:f,recovery:p}=a;if(!l||!d&&!p)return new Response("Missing required fields (publicKey and either passkey or recovery)",{status:400});let m=null;if(d&&(m=await o.getByIdOrCredentialId(d,n.id),!m)){let E=await o.listByUser(n.id);E.length>0&&(m=E[0])}let h=await i.listByOwner(n.id),g=Math.floor(Date.now()/1e3),w=typeof l=="string"?l:JSON.stringify(l),b=[],y=h.length>0?h[0].id:null;if(y){m&&u&&f&&b.push(e.DB.prepare("INSERT INTO user_passkey_wrapped_keys (passkey_id, profile_id, encrypted_sk, iv, created_at) VALUES (?, ?, ?, ?, ?) ON CONFLICT(passkey_id) DO UPDATE SET encrypted_sk = excluded.encrypted_sk, iv = excluded.iv, created_at = excluded.created_at").bind(m.id,y,u,f,g));for(let E of h)b.push(e.DB.prepare("INSERT INTO user_log_keys (profile_id, public_key, created_at, is_active) VALUES (?, ?, ?, 1) ON CONFLICT(profile_id) DO UPDATE SET public_key = excluded.public_key, created_at = excluded.created_at, is_active = 1").bind(E.id,w,g)),p&&p.encryptedSk&&p.iv&&p.salt&&b.push(e.DB.prepare("INSERT INTO user_recovery_wrapped_keys (profile_id, encrypted_sk, iv, salt, created_at) VALUES (?, ?, ?, ?, ?) ON CONFLICT(profile_id) DO UPDATE SET encrypted_sk = excluded.encrypted_sk, iv = excluded.iv, salt = excluded.salt, created_at = excluded.created_at").bind(E.id,p.encryptedSk,p.iv,p.salt,g))}b.length>0&&await e.DB.batch(b);for(let E of h)Yt(E.id);return Response.json({success:!0})}if(c==="wrap"&&t.method==="POST"){let a;try{a=await t.json()}catch{return new Response("Invalid JSON body",{status:400})}let{passkeyId:l,encryptedSk:d,iv:u}=a;if(!l||!d||!u)return new Response("Missing required fields (passkeyId, encryptedSk, iv)",{status:400});let f=await o.getByIdOrCredentialId(l,n.id);if(!f){let g=await o.listByUser(n.id);g.length>0&&(f=g[0])}if(!f)return new Response("Passkey not found or unauthorized",{status:403});let p=await i.listByOwner(n.id),m=p.length>0?p[0].id:null;if(!m)return new Response("No profiles found for user",{status:400});let h=Math.floor(Date.now()/1e3);return await e.DB.prepare("INSERT INTO user_passkey_wrapped_keys (passkey_id, profile_id, encrypted_sk, iv, created_at) VALUES (?, ?, ?, ?, ?) ON CONFLICT(passkey_id) DO UPDATE SET encrypted_sk = excluded.encrypted_sk, iv = excluded.iv, created_at = excluded.created_at").bind(f.id,m,d,u,h).run(),Response.json({success:!0})}if(c==="wrap-recovery"&&t.method==="POST"){let a;try{a=await t.json()}catch{return new Response("Invalid JSON body",{status:400})}let{encryptedSk:l,iv:d,salt:u}=a;if(!l||!d||!u)return new Response("Missing required fields (encryptedSk, iv, salt)",{status:400});let f=await i.listByOwner(n.id),p=Math.floor(Date.now()/1e3),m=[];for(let h of f)m.push(e.DB.prepare("INSERT INTO user_recovery_wrapped_keys (profile_id, encrypted_sk, iv, salt, created_at) VALUES (?, ?, ?, ?, ?) ON CONFLICT(profile_id) DO UPDATE SET encrypted_sk = excluded.encrypted_sk, iv = excluded.iv, salt = excluded.salt, created_at = excluded.created_at").bind(h.id,l,d,u,p));return m.length>0&&await e.DB.batch(m),Response.json({success:!0})}if(c==="enable"&&t.method==="POST"){let a=await i.listByOwner(n.id);await e.DB.prepare("UPDATE user_log_keys SET is_active = 1 WHERE profile_id IN (SELECT id FROM profiles WHERE owner_id = ?)").bind(n.id).run();for(let l of a)Yt(l.id);return Response.json({success:!0,enabled:!0})}if(t.method==="DELETE"&&(!c||c==="keys")){let l=new URL(t.url).searchParams.get("purge")==="true",d=await i.listByOwner(n.id);l?await e.DB.batch([e.DB.prepare("DELETE FROM user_log_keys WHERE profile_id IN (SELECT id FROM profiles WHERE owner_id = ?)").bind(n.id),e.DB.prepare("DELETE FROM user_passkey_wrapped_keys WHERE passkey_id IN (SELECT id FROM passkeys WHERE user_id = ?)").bind(n.id),e.DB.prepare("DELETE FROM user_recovery_wrapped_keys WHERE profile_id IN (SELECT id FROM profiles WHERE owner_id = ?)").bind(n.id)]):await e.DB.prepare("UPDATE user_log_keys SET is_active = 0 WHERE profile_id IN (SELECT id FROM profiles WHERE owner_id = ?)").bind(n.id).run();for(let u of d)Yt(u.id);return Response.json({success:!0,purged:l,enabled:!1})}return new Response("Not Found",{status:404})}async function pl(t,e,n,r,s){let o=r[2];return o==="me"||o==="delete"||o==="logs"?rl(t,e,n,r,s):o==="password"||o==="totp"||o==="passkeys"||o==="mfa"||o==="migrate-password"||o==="pin"||o==="recovery-keys"?ll(t,e,n,r,s):o==="activity"||o==="sessions"?dl(t,e,n,r,s):o==="e2ee"?ul(t,e,n,r,s):new Response("Not Found",{status:404})}pe();Re();async function fl(t,e,n,r,s){let o=new Y(e.DB,e),i=new q(e.DB);if(r[2]==="users"){if(t.method==="GET"){let c=await o.listAll();return new Response(JSON.stringify(c),{headers:{"Content-Type":"application/json"}})}if(t.method==="POST"){let{username:c,password:a,role:l}=await t.json();if(!c||!Et.test(c))return new Response("Invalid username format",{status:400});if(!a||!bt.test(a))return new Response("Password format error",{status:400});let d=await et(a,2),u=j(15);try{return await o.create({id:u,username:c,passwordHash:d,role:l||"user",passwordVersion:2}),new Response(JSON.stringify({id:u}),{status:201})}catch(f){return new Response(f.message,{status:400})}}if(t.method==="DELETE"&&r[3]){let c=r[3];return c===n.id?new Response("Cannot delete yourself",{status:400}):(await i.deleteByOwner(c),await o.delete(c),new Response(null,{status:204}))}}if(r[2]==="settings"){let c=new he(e.DB);if(t.method==="GET"){let a=await c.getAll();return delete a.jwt_secret,new Response(JSON.stringify(a),{headers:{"Content-Type":"application/json"}})}if(t.method==="PATCH"){let a=await t.json();return delete a.jwt_secret,await c.setMany(a),new Response(JSON.stringify({success:!0}))}}return new Response("Not Found",{status:404})}async function ml(t,e,n,r){let o=new URL(t.url).pathname.split("/").filter(Boolean);return o[1]==="account"?pl(t,e,n,o,r):o[1]==="admin"?Wn.isAdmin(n)?fl(t,e,n,o,r):new Response("Forbidden",{status:403}):new Response("Not Found",{status:404})}ge();async function hl(t,e){let n=new URL(t.url),r=typeof caches<"u"?caches.default:null;if(n.pathname==="/api/clientinfo"){let s=t.headers.get("CF-Connecting-IP")||"127.0.0.1",o=await P.get(r,`active_dns:${s}`),i=t.cf,c=i?.country||t.headers.get("CF-IPCountry")||"UNKNOWN",a=i?.region||t.headers.get("CF-Region")||"UNKNOWN",l=i?.city||t.headers.get("CF-IPCity")||"UNKNOWN",d=i?.timezone||t.headers.get("CF-Timezone")||"UNKNOWN",u=i?.asn?Number(i.asn):t.headers.get("CF-ASN")?Number(t.headers.get("CF-ASN")):0,f=i?.asOrganization||t.headers.get("CF-AS-Org")||"UNKNOWN",p=e.SERVERFULL_DEFAULT_PROFILE_KEY!==void 0||e.SERVERFULL_HOST!==void 0||e.SERVERFULL_DOT_DOMAIN!==void 0||e.SERVERFULL_HTTP_PORT!==void 0||e.SERVERFULL_HTTPS_PORT!==void 0;return new Response(JSON.stringify({ip:s,country:c,region:a,city:l,timezone:d,asn:u,asOrganization:f,connectedProfileId:o||null,substituteDomain:e.SUBSTITUTE_DOMAIN||Yn,dotDomain:e.SERVERFULL_DOT_DOMAIN||e.DOT_DOMAIN||null,isServerfull:p,mode:p?"serverfull":"cloudflare"}),{headers:{"Content-Type":"application/json"}})}if(n.pathname==="/api/regions"){let s={};for(let[o,i]of Object.entries(e))if(o.startsWith("IP_REGION_")&&typeof i=="string")try{let c=o.replace("IP_REGION_",""),a=i.trim();a=a.replace(/^"""|"""$/g,"").replace(/^"|"$/g,"").replace(/^'|'$/g,"").trim(),s[c]=JSON.parse(a)}catch{}return Object.keys(s).length===0&&(s.CN=$r),new Response(JSON.stringify(s),{headers:{"Content-Type":"application/json"}})}if(n.pathname==="/api/substitute"){let s=e.SUBSTITUTE_DOMAIN||Yn,o=null,i=null,c=async a=>{let l=["https://cloudflare-dns.com/dns-query","https://1.1.1.1/dns-query"];for(let d of l)try{let u=await fetch(`${d}?name=${s}&type=${a}`,{headers:{Accept:"application/dns-json"},signal:AbortSignal.timeout(3e3)});if(u.ok){let f=await u.json();if(f?.Answer?.length>0){let p=f.Answer.find(m=>m.type===(a==="A"?1:28));if(p?.data)return p.data}}}catch(u){console.error(`[Substitute Resolve] Failed resolving ${a} via ${d}:`,u)}return null};try{let[a,l]=await Promise.all([c("A"),c("AAAA")]);o=a,i=l}catch(a){console.error("[Substitute API] Error resolving substitute domain:",a)}return new Response(JSON.stringify({ip:o,ipv6:i}),{headers:{"Content-Type":"application/json"}})}if(n.pathname==="/api/presets/upstreams"){let s=Fr;if(e.PRESET_UPSTREAMS)try{let o=JSON.parse(e.PRESET_UPSTREAMS);Array.isArray(o)&&o.length>0&&(s=o)}catch(o){console.warn("[System API] Failed to parse PRESET_UPSTREAMS from env:",o)}return new Response(JSON.stringify(s),{headers:{"Content-Type":"application/json"}})}if(n.pathname==="/api/presets/filters"){let s=Hr;if(e.PRESET_EXTERNAL_FILTERS)try{let o=JSON.parse(e.PRESET_EXTERNAL_FILTERS);Array.isArray(o)&&o.length>0&&(s=o)}catch(o){console.warn("[System API] Failed to parse PRESET_EXTERNAL_FILTERS from env:",o)}return new Response(JSON.stringify(s),{headers:{"Content-Type":"application/json"}})}if(n.pathname==="/api/presets/ech-fronting-domains"){let s=$i(e);return new Response(JSON.stringify(s),{headers:{"Content-Type":"application/json"}})}if(n.pathname.startsWith("/api/icon/")){let s=n.pathname.replace("/api/icon/","");if(!s)return new Response("Missing domain",{status:400});let o=`https://icons.duckduckgo.com/ip3/${s}`;try{let i=await fetch(o),c=new Headers(i.headers);return c.set("Cache-Control","public, max-age=2592000"),c.delete("Access-Control-Allow-Origin"),new Response(i.body,{status:i.status,statusText:i.statusText,headers:c})}catch{return new Response("Error fetching icon",{status:500})}}if(n.pathname==="/api/geoip"){let s=n.searchParams.get("ip"),o=t.headers.get("CF-Connecting-IP"),i=(s||o||"").trim();if(i==="127.0.0.1"||i==="localhost"||i==="::1"||i.startsWith("192.168.")||i.startsWith("10.")||/^172\.(1[6-9]|2\d|3[01])\./.test(i))return new Response(JSON.stringify({success:!0,ip:i,city:"Local",country:"Private Network",flag:{emoji:"\u{1F3E0}"}}),{headers:{"Content-Type":"application/json"}});try{let c=i?`https://ipwho.is/${encodeURIComponent(i)}`:"https://ipwho.is/",a=await fetch(c,{signal:AbortSignal.timeout(3500)});if(a.ok){let l=await a.json();return new Response(JSON.stringify(l),{headers:{"Content-Type":"application/json"}})}}catch(c){console.warn(`[System API] Failed resolving geoip for ${i||"server"}:`,c)}return new Response(JSON.stringify({success:!1,ip:i||"unknown"}),{headers:{"Content-Type":"application/json"}})}if(n.pathname==="/api/resolve"){let s=n.searchParams.get("name")||n.searchParams.get("domain");if(!s)return new Response(JSON.stringify({error:"Missing domain parameter"}),{status:400,headers:{"Content-Type":"application/json"}});if(/^(\d{1,3}\.){3}\d{1,3}$/.test(s))return new Response(JSON.stringify({ipv4:[s],ipv6:[]}),{headers:{"Content-Type":"application/json"}});if(/^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$/.test(s))return new Response(JSON.stringify({ipv4:[],ipv6:[s]}),{headers:{"Content-Type":"application/json"}});let o=async i=>{let c=["https://cloudflare-dns.com/dns-query","https://1.1.1.1/dns-query"];for(let a of c)try{let l=await fetch(`${a}?name=${encodeURIComponent(s)}&type=${i}`,{headers:{Accept:"application/dns-json"},signal:AbortSignal.timeout(3e3)});if(l.ok){let d=await l.json();if(Array.isArray(d?.Answer)&&d.Answer.length>0){let u=i==="A"?1:28;return d.Answer.filter(f=>f.type===u&&typeof f.data=="string").map(f=>f.data)}}}catch{}return[]};try{let[i,c]=await Promise.all([o("A"),o("AAAA")]);if(i.length===0&&c.length===0&&typeof process<"u"&&process.versions?.node)try{let a=await import("node:dns/promises"),[l,d]=await Promise.allSettled([a.resolve4(s),a.resolve6(s)]);l.status==="fulfilled"&&Array.isArray(l.value)&&(i=l.value),d.status==="fulfilled"&&Array.isArray(d.value)&&(c=d.value)}catch{}return new Response(JSON.stringify({ipv4:i,ipv6:c}),{headers:{"Content-Type":"application/json"}})}catch(i){return console.error("DNS resolve failed:",i),new Response(JSON.stringify({ipv4:[],ipv6:[],error:"Internal server error"}),{status:500,headers:{"Content-Type":"application/json"}})}}return new Response("Not Found",{status:404})}ge();async function gl(t,e,n){try{let r=caches.default,s=Math.floor(Date.now()/1e3),o="cron:last_cleanup_timestamp",i=await P.get(r,o);if(!i||s-i>=3600){try{let c=new Y(e.DB,e),{clearedProfiles:a,deletedUsers:l}=await c.applyInactivityPolicy(s);(a>0||l>0)&&console.log(`[Cron] Inactivity cleanup: cleared ${a} profile(s), deleted ${l} user(s).`)}catch(c){console.error("[Cron] Inactivity policy execution failed:",c)}try{let c=new Oe(e.DB),a=e.MAX_LOG_RETENTION_DAYS!==void 0&&e.MAX_LOG_RETENTION_DAYS!==""?Number(e.MAX_LOG_RETENTION_DAYS):30,l=e.LOG_CLEANUP_BATCH_LIMIT!==void 0&&e.LOG_CLEANUP_BATCH_LIMIT!==""?Number(e.LOG_CLEANUP_BATCH_LIMIT):1e3,d=e.LOG_CLEANUP_DAILY_BUDGET!==void 0&&e.LOG_CLEANUP_DAILY_BUDGET!==""?Number(e.LOG_CLEANUP_DAILY_BUDGET):2e4;await c.cleanupGlobal(a,l,d)}catch(c){console.error("[Cron] Global log cleanup failed:",c)}try{let{SessionModel:c}=await Promise.resolve().then(()=>(Ie(),ir)),a=new c(e.DB),{deletedSessions:l,deletedPending:d}=await a.deleteExpiredSessions(s);(l>0||d>0)&&console.log(`[Cron] Purged ${l} expired session(s) and ${d} pending token(s).`)}catch(c){console.error("[Cron] Session cleanup failed:",c)}await P.set(r,o,s,3600),console.log("[Cron] Cleanup phase completed at",new Date().toISOString())}try{await Lo(e.DB)}catch(c){console.error("[Cron] Cloudflare IP range sync failed:",c)}try{let c="cron:last_idle_sync_check",l=await P.get(r,c);if(!!!(l&&s-l<600)){let u=Number(e.SYNC_PROFILE_INTERVAL_SEC)||86400,f=s-u,p=new q(e.DB),m=Number(e.SYNC_BATCH_SIZE)||1,h=await p.getSyncTargets(f,m);if(h.length>0){await P.delete(r,c);for(let g of h)try{await jn(g.id,e,n)}catch(w){let b=w instanceof Error?w.message:String(w);console.error(`[Cron] Sync failed for profile ${g.id}:`,b)}console.log(`[Cron] Sync: processed ${h.length} profile(s).`)}else await P.set(r,c,s,600)}}catch(c){let a=c instanceof Error?c.message:String(c);console.error("[Cron] Sync phase failed:",a)}}catch(r){let s=r instanceof Error?r.message:String(r);console.error("[Cron] Critical Failure:",s)}}async function yl(t,e,n){let r=new Request(new URL("https://obex.local/world-110m-v2.json"),t),s=caches.default,o=await s.match(r);if(!o)try{let c=await fetch("https://openlayers.org/en/latest/examples/data/topojson/world-110m.json",{headers:{"User-Agent":"DNS Worker/1.0 (Cloudflare Worker Map Proxy)"}});if(!c.ok)throw new Error(`Failed to fetch map data from openlayers.org: ${c.status}`);let a=await c.json();if(a&&a.objects){let l={};a.objects.countries&&(l.countries=a.objects.countries),a.objects.land&&(l.land=a.objects.land),a.objects=l}a&&a.objects&&a.objects.countries&&Array.isArray(a.objects.countries.geometries)&&a.objects.countries.geometries.forEach(l=>{l.id!==void 0&&l.id!==null&&(l.id=String(l.id).padStart(3,"0"))}),o=new Response(JSON.stringify(a),{headers:{"Content-Type":"application/json; charset=utf-8","Cache-Control":"public, max-age=2592000","Access-Control-Allow-Origin":"*"}}),n.waitUntil(s.put(r,o.clone()))}catch(i){return console.error("[MapData API Proxy] Error fetching or transforming TopoJSON:",i),new Response(JSON.stringify({error:"Failed to fetch map data"}),{status:502,headers:{"Content-Type":"application/json"}})}return o}Ue();var ho={async fetch(t,e,n){let r=new Uint8Array(16);crypto.getRandomValues(r);let s=Array.from(r).map(l=>l.toString(16).padStart(2,"0")).join(""),o=null,c=await(async()=>{let l=new URL(t.url);if(l.pathname==="/world-110m.json")return yl(t,e,n);if(l.pathname.startsWith("/api/")){let p=!1;try{p=!e.DB}catch{p=!0}let m=!ke(e.JWT_SECRET);if(p||m)return new Response(JSON.stringify({error:"configuration_error",isDbMissing:p,isJwtSecretMissing:m,message:"DNS Worker is not fully configured. Please configure the D1 database binding and JWT_SECRET secret variable."}),{status:503,headers:{"Content-Type":"application/json","Access-Control-Allow-Origin":"*"}});o=await Ai(t,e,n);let h=["/api/auth/login","/api/auth/signup","/api/auth/prelogin","/api/auth/check-username","/api/auth/config","/api/auth/refresh","/api/auth/logout","/api/auth/unlock-session","/api/clientinfo","/api/regions","/api/substitute","/api/resolve","/api/geoip"].includes(l.pathname)||l.pathname.startsWith("/api/icon/")||l.pathname.startsWith("/api/presets/")||l.pathname.startsWith("/api/auth/forgot-password");return!o&&!h?new Response("Unauthorized",{status:401}):o&&o.isPaused&&!["/api/auth/unlock-session","/api/auth/logout","/api/auth/refresh"].includes(l.pathname)?new Response("session_paused",{status:403}):o&&["POST","PUT","PATCH","DELETE"].includes(t.method)&&!h&&!vi(t)?new Response("CSRF validation failed",{status:403}):l.pathname.startsWith("/api/auth/")?Jc(t,e):l.pathname==="/api/clientinfo"||l.pathname==="/api/regions"||l.pathname==="/api/substitute"||l.pathname==="/api/resolve"||l.pathname==="/api/geoip"||l.pathname.startsWith("/api/presets/")||l.pathname.startsWith("/api/icon/")?hl(t,e):l.pathname.startsWith("/api/profiles")?nl(t,e,o,n):l.pathname.startsWith("/api/account")||l.pathname.startsWith("/api/admin")?ml(t,e,o,n):new Response("API Not Found",{status:404})}if(l.pathname==="/setup.sh"){let p=l.searchParams.get("key");if(!p||!Ft.test(p))return new Response("Missing or invalid key parameter",{status:400});let m=Oc(l.origin,p);return new Response(m,{headers:{"Content-Type":"text/plain; charset=utf-8","Cache-Control":"no-cache"}})}let d=l.pathname.slice(1),u=Ft.test(d),f=t.method==="POST"||l.searchParams.has("dns")||t.headers.get("accept")?.includes("dns-message");if(u&&(f||t.method==="OPTIONS"))return t.method==="OPTIONS"?new Response(null,{status:204,headers:{"Access-Control-Allow-Origin":"*","Access-Control-Allow-Methods":"GET, POST, OPTIONS","Access-Control-Allow-Headers":"Content-Type, Accept","Access-Control-Max-Age":"86400"}}):Dc(t,e,n,d);try{let p=await e.ASSETS.fetch(t);if(p.status===404&&!l.pathname.startsWith("/assets/")&&(t.method==="GET"||t.method==="HEAD")&&(p=await e.ASSETS.fetch(new Request(l.origin+"/",{method:t.method,headers:t.headers}))),l.pathname.endsWith(".wasm")){let h=new Headers(p.headers);return h.set("Content-Type","application/wasm"),h.set("Cross-Origin-Resource-Policy","same-origin"),new Response(p.body,{status:p.status,statusText:p.statusText,headers:h})}if((p.headers.get("Content-Type")||"").includes("text/html")){let h=!1;try{h=!e.DB}catch{h=!0}let g=!ke(e.JWT_SECRET),w=e.SERVERFULL_DEFAULT_PROFILE_KEY!==void 0||e.SERVERFULL_HOST!==void 0||e.SERVERFULL_DOT_DOMAIN!==void 0||e.SERVERFULL_HTTP_PORT!==void 0||e.SERVERFULL_HTTPS_PORT!==void 0,b="{}";try{b=JSON.stringify({nonce:s,isDbMissing:h,isJwtSecretMissing:g,isServerfull:w,mode:w?"serverfull":"cloudflare"})}catch{}return new HTMLRewriter().on("head",{element(y){y.prepend(`<script nonce="${s}">window.DNS_WORKER_CONFIG = ${b};</script>`,{html:!0})}}).transform(p)}return p}catch{return new Response("Asset Fetch Error",{status:500})}})(),a=o;if(a&&!hn(t.headers.get("Cookie"))){let l=a.sessionId?.startsWith("k_");try{let d=j(32);c.headers.append("Set-Cookie",tt(d,e,l))}catch{let u=new Headers(c.headers),f=j(32);u.append("Set-Cookie",tt(f,e,l)),c=new Response(c.body,{status:c.status,statusText:c.statusText,headers:u})}}if(c.headers.get("Content-Type")?.includes("application/dns-message")){let l=new Headers(c.headers);return l.set("Access-Control-Allow-Origin","*"),l.set("Access-Control-Allow-Methods","GET, POST, OPTIONS"),l.set("Access-Control-Allow-Headers","Content-Type, Accept"),new Response(c.body,{status:c.status,statusText:c.statusText,headers:l})}return xi(c,s)},async scheduled(t,e,n){await gl(t,e,n)}};var Uu={".html":"text/html; charset=utf-8",".js":"application/javascript; charset=utf-8",".mjs":"application/javascript; charset=utf-8",".css":"text/css; charset=utf-8",".json":"application/json; charset=utf-8",".webp":"image/webp",".png":"image/png",".jpg":"image/jpeg",".svg":"image/svg+xml",".ico":"image/x-icon",".webmanifest":"application/manifest+json",".wasm":"application/wasm"};function bl(t,e){if(t.ASSETS)return;let n=e||go.join(Nt(),"static");t.ASSETS={fetch:async r=>{try{let s=new URL(r.url),o=decodeURIComponent(s.pathname);(o==="/"||o==="")&&(o="/index.html");let i=go.normalize(o).replace(/^(\.\.[\/\\])+/,""),c=go.join(n,i);if(Ir.existsSync(c)&&Ir.statSync(c).isFile()){let a=go.extname(c).toLowerCase(),l=Uu[a]||"application/octet-stream",d=Ir.readFileSync(c);return new Response(d,{status:200,headers:{"Content-Type":l,"Cache-Control":a===".html"?"no-cache":"public, max-age=31536000, immutable","Cross-Origin-Opener-Policy":"same-origin","Cross-Origin-Embedder-Policy":"credentialless","Cross-Origin-Resource-Policy":"same-origin"}})}return new Response("Not Found",{status:404})}catch{return new Response("Asset Error",{status:500})}}}}function El(t,e,n,r){return async(s,o)=>{try{let i=s.headers["x-forwarded-proto"]||e,c=s.headers.host||`${n}:${r}`,a=new URL(s.url||"/",`${i}://${c}`),l=new Headers;for(let[w,b]of Object.entries(s.headers))b&&(Array.isArray(b)?b.forEach(y=>l.append(w,y)):l.set(w,String(b)));if(!l.has("CF-Connecting-IP")){let w=s.socket.remoteAddress?.replace(/^::ffff:/,"")||"127.0.0.1";l.set("CF-Connecting-IP",w)}let d=l.get("CF-IPLatitude");(!d||d.trim()==="")&&l.set("CF-IPLatitude","0.0");let u=l.get("CF-IPLongitude");(!u||u.trim()==="")&&l.set("CF-IPLongitude","0.0");let f=null;if(s.method!=="GET"&&s.method!=="HEAD"){let w=[];for await(let b of s)w.push(typeof b=="string"?wl.from(b):b);f=wl.concat(w)}let p=new Request(a.toString(),{method:s.method,headers:l,body:f,duplex:"half"}),m={waitUntil(w){w.catch(b=>console.error(`[${e.toUpperCase()} Background Task Error]:`,b))},passThroughOnException(){}},h=await ho.fetch(p,t,m);o.statusCode=h.status,o.statusMessage=h.statusText;let g=typeof h.headers.getSetCookie=="function"?h.headers.getSetCookie():[];if(g.length===0&&h.headers.has("set-cookie")){let w=h.headers.get("set-cookie");w&&(g=[w])}if(h.headers.forEach((w,b)=>{let y=b.toLowerCase();y!=="set-cookie"&&(e==="https"&&y==="alt-svc"?o.setHeader("Alt-Svc",`h3=":${r}"; ma=86400, h3-29=":${r}"; ma=86400`):o.setHeader(b,w))}),g.length>0){let b=i==="http"?g.map(y=>y.replace(/;\s*Secure\b/gi,"")):g;o.setHeader("Set-Cookie",b)}if(e==="https"&&!o.hasHeader("Alt-Svc")&&o.setHeader("Alt-Svc",`h3=":${r}"; ma=86400, h3-29=":${r}"; ma=86400`),h.body){let w=h.body.getReader();for(;;){let{done:b,value:y}=await w.read();if(b)break;o.write(y)}}o.end()}catch(i){console.error(`[${e.toUpperCase()} Server] Request processing failed:`,i),o.headersSent||(o.statusCode=500,o.setHeader("Content-Type","application/json"),o.end(JSON.stringify({error:"Internal Server Error"})))}}}var yo=class{constructor(e){this.options=e;bl(this.options.env,this.options.staticDir)}options;server=null;isRunning=!1;start(){return new Promise((e,n)=>{let{port:r,host:s,env:o}=this.options,i=El(o,"http",s,r);this.server=Nu.createServer(i),this.server.keepAliveTimeout=65e3,this.server.headersTimeout=66e3,this.server.on("connection",a=>{a.setNoDelay(!0)});let c=a=>{this.server=null,console.error(qt({serviceName:"Web Dashboard & DoH (HTTP)",protocol:"HTTP",port:r,err:a,alternateOption:`--http-port <port> (e.g. --http-port ${r+1})`})),n(a)};this.server.once("error",c),this.server.listen(r,s,()=>{this.server?.removeListener("error",c),this.server?.on("error",a=>{console.error("[HTTP Server] Runtime error:",a)}),this.isRunning=!0,console.log(`[HTTP Server] Web Dashboard & DoH listening on http://${s}:${r}`),e()})})}stop(){return new Promise(e=>{this.server&&this.isRunning?this.server.close(()=>{this.isRunning=!1,console.log("[HTTP Server] Service stopped."),e()}):e()})}},wo=class{constructor(e){this.options=e;bl(this.options.env,this.options.staticDir)}options;server=null;isRunning=!1;start(){return new Promise((e,n)=>{let{port:r,host:s,certPath:o,keyPath:i,env:c}=this.options;try{let a=Ir.readFileSync(o),l=Ir.readFileSync(i),d=El(c,"https",s,r);this.server=Iu.createServer({cert:a,key:l},d),this.server.keepAliveTimeout=65e3,this.server.headersTimeout=66e3,this.server.on("connection",f=>{f.setNoDelay(!0)});let u=f=>{this.server=null,console.error(qt({serviceName:"Web Dashboard & DoH (HTTPS)",protocol:"HTTPS",port:r,err:f,alternateOption:`--https-port <port> (e.g. --https-port ${r+1})`})),n(f)};this.server.once("error",u),this.server.listen(r,s,()=>{this.server?.removeListener("error",u),this.server?.on("error",f=>{console.error("[HTTPS Server] Runtime error:",f)}),this.isRunning=!0,console.log(`[HTTPS Server] Web Dashboard & DoH listening on https://${s}:${r}`),e()})}catch(a){n(a)}})}stop(){return new Promise(e=>{this.server&&this.isRunning?this.server.close(()=>{this.isRunning=!1,console.log("[HTTPS Server] Service stopped."),e()}):e()})}};Ue();import _l from"node:fs";import Mu from"node:net";import Bu from"node:dgram";import{DatabaseSync as Fu}from"node:sqlite";Ue();function Li(t,e,n=300){return new Promise(r=>{let s=new Mu.Socket,o=!1,i=a=>{if(!o){o=!0;try{s.destroy()}catch{}r(a)}};s.setTimeout(n),s.once("connect",()=>i("active")),s.once("timeout",()=>i("free")),s.once("error",()=>i("free"));let c=e==="0.0.0.0"||e==="::"?"127.0.0.1":e;try{s.connect(t,c)}catch{i("free")}})}function Hu(t,e){return new Promise(n=>{let r=Bu.createSocket("udp4"),s=!1,o=i=>{if(!s){s=!0;try{r.close()}catch{}n(i)}};r.once("error",i=>{let c=i?.code;o(c==="EADDRINUSE"?"active":"free")});try{r.bind(t,e,()=>{o("free")})}catch{o("active")}})}function $u(t){if(!_l.existsSync(t))return{exists:!1,statusText:"Not Initialized (File does not exist yet; created on first start)"};try{let e=_l.statSync(t),n=e.size>1024*1024?`${(e.size/(1024*1024)).toFixed(2)} MB`:`${(e.size/1024).toFixed(1)} KB`,r=0,s=0,o=0;try{let c=new Fu(t,{readOnly:!0}),a=c.prepare("SELECT count(*) as cnt FROM sqlite_master WHERE type='table' AND name='d1_migrations'").get();a&&a.cnt>0&&(r=c.prepare("SELECT count(*) as count FROM d1_migrations").get()?.count||0);let l=c.prepare("SELECT count(*) as cnt FROM sqlite_master WHERE type='table' AND name='users'").get();l&&l.cnt>0&&(s=c.prepare("SELECT count(*) as count FROM users").get()?.count||0);let d=c.prepare("SELECT count(*) as cnt FROM sqlite_master WHERE type='table' AND name='profiles'").get();d&&d.cnt>0&&(o=c.prepare("SELECT count(*) as count FROM profiles").get()?.count||0),c.close()}catch{}let i=[n,r>0?`${r} migrations`:null,s>0?`${s} user(s)`:null,o>0?`${o} profile(s)`:null].filter(Boolean).join(", ");return{exists:!0,sizeFormatted:n,migrationsCount:r,usersCount:s,profilesCount:o,statusText:`Ready (${i})`}}catch(e){return{exists:!0,statusText:`Exists (Read warning: ${e instanceof Error?e.message:String(e)})`}}}async function Sl(t,e){let n=Bn(t.tlsCertPath,t.tlsKeyPath),r=!t.disableHttps&&n.configured&&n.filesExist,[s,o,i,c]=await Promise.all([Li(t.httpPort,t.host),r?Li(t.httpsPort,t.host):Promise.resolve("disabled"),t.disableUdp?Promise.resolve("disabled"):Hu(t.udpPort,t.host),t.disableDot?Promise.resolve("disabled"):Li(t.dotPort,t.host)]),a=$u(t.dbPath),l="Default (Insecure fallback, please configure JWT_SECRET)";ke(e)&&(l=gt(e)?"Configured (Strong, >= 32 characters)":"Configured (Warning: Shorter than 32 characters)");let d=s==="active"?Qt(t.httpPort,"TCP"):null,u=d?`: ${Zt(d)}`:"",f=s==="active"?`http://${t.host}:${t.httpPort} [Active / Listening${u}]`:`http://${t.host}:${t.httpPort} [Stopped / Port Available]`,p="";if(t.disableHttps)p="Disabled (--disable-https)";else if(!n.configured)p=`https://${t.host}:${t.httpsPort} [Disabled - TLS Certificates Not Configured]`;else if(!n.filesExist)p=`https://${t.host}:${t.httpsPort} [Warning - TLS Certificate Files Missing]`;else if(o==="active"){let ie=Qt(t.httpsPort,"TCP"),k=ie?`: ${Zt(ie)}`:"";p=`https://${t.host}:${t.httpsPort} [Active / Listening${k}]`}else p=`https://${t.host}:${t.httpsPort} [Stopped / Port Available]`;let m=!t.disableUdp&&i==="active"?Qt(t.udpPort,"UDP"):null,h=m?`: ${Zt(m)}`:"",g=t.disableUdp?"Disabled (--disable-udp)":i==="active"?`udp://${t.host}:${t.udpPort} [Active / In Use${h}]`:`udp://${t.host}:${t.udpPort} [Stopped / Port Available]`,w="",b=t.dotDomain?` (${t.dotDomain})`:"";if(t.disableDot)w="Disabled (--disable-dot)";else if(!n.configured)w=`tls://${t.host}:${t.dotPort}${b} [Disabled - TLS Certificates Not Configured]`;else if(!n.filesExist)w=`tls://${t.host}:${t.dotPort}${b} [Warning - TLS Certificate Files Missing]`;else if(!n.isWildcard)w=`tls://${t.host}:${t.dotPort}${b} [Paused - Requires Wildcard Certificate (*.domain)]`;else if(c==="active"){let ie=Qt(t.dotPort,"TCP"),k=ie?`: ${Zt(ie)}`:"";w=`tls://${t.host}:${t.dotPort}${b} [Active / Listening${k}]`}else w=`tls://${t.host}:${t.dotPort}${b} [Stopped / Port Available]`;let y=t.defaultProfileKey?`Explicit (${t.defaultProfileKey})`:"Auto (Database default profile)",E=We({title:"DNS Worker Runtime Status (Serverfull Mode)",borderChar:"=",bullet:"\u2022 "}),_=Ct({title:`
444
- Service Transports:`,items:[{label:"Web Dashboard (HTTP)",value:f},{label:"Web Dashboard (HTTPS)",value:p},{label:"Classic UDP DNS",value:g},{label:"DNS over TLS (DoT)",value:w}]}),S=Gr(),x=S.length>0?`${S.join(", ")} [Loaded]`:`None found (Using built-in presets & defaults; default path: ${ut()})`,T=Ct({title:`
445
- Database & Storage:`,items:[{label:"SQLite Path",value:t.dbPath},{label:"Database Status",value:a.statusText},{label:"Persistent Data Dir",value:dt()}]}),v="Not Configured (HTTP only, HTTPS & DoT disabled)";if(n.configured)if(!n.filesExist)v="Configured [Files Missing]";else if(n.error)v=`Configured [Invalid Certificate: ${n.error}]`;else{let ie=n.isWildcard?"Wildcard (*.domain)":"Single Domain",k=n.expiresAt?n.expiresAt.toISOString().split("T")[0]:"Unknown";v=`Valid (${ie}, Expires: ${k})`}let C=t.dotDomain?`${t.dotDomain} (Wildcard / Single-domain compatible)`:"Not Configured (Auto SNI prefix matching)",L=!t.disableHttps&&n.configured&&n.filesExist?`Enabled via Alt-Svc (UDP :${t.httpsPort}, RFC 9114)`:"Disabled (Requires active HTTPS with TLS certificate)",H=n.configured&&n.filesExist?`Compatible (RFC 9250 / RFC 9460 DDR, UDP :${t.dotPort})`:"Disabled (Requires TLS certificate)",V=t.echEnabled?`Enabled (RFC 9460, Outer SNI: ${t.echFrontingDomain||"cloudflare-ech.com"})`:"Disabled",Q=Ct({title:`
446
- Environment & Security:`,items:[{label:"Node.js Runtime",value:`v${process.versions.node} (${process.platform} ${process.arch})`},{label:"Config Directory",value:cn()},{label:"Config Source",value:x},{label:"TLS Certificate",value:v},{label:"JWT Secret",value:l},{label:"DoT Base Domain",value:C},{label:"HTTP/3 (h3)",value:L},{label:"DNS over QUIC (DoQ)",value:H},{label:"ECH (Encrypted Client Hello)",value:V},{label:"Default Profile Key",value:y}]}),Z=[];if(s==="free"&&(i==="free"||t.disableUdp)){let ie=process.platform==="win32"?"dns-worker service install (in Administrator terminal)":"sudo dns-worker service install";Z.push("Services are currently stopped."),Z.push(`To run continuously as a persistent background daemon: ${ie}`)}let _e=kr(t.dotDomain);!n.configured||!n.filesExist?(Z.push(`To enable secure HTTPS (port ${t.httpsPort}) and DoT (port ${t.dotPort}):`),Z.push(` ${_e}`)):n.isWildcard||(Z.push("Current certificate is single-domain. To support per-profile DoT (<profile>.domain):"),Z.push(` ${_e}`)),Z.push("Run 'dns-worker ech' to view active ECH configuration, outer SNI, and RFC 9460 DNS records.");let K=Z.length>0?Mn(Z):"",Se=[E,_,T,Q,K].filter(Boolean).join(`
447
- `);console.log(Se)}import Ku from"node:fs";import Wu from"node:path";import{execSync as ju}from"node:child_process";function Rl(){try{return ju("net session",{stdio:"ignore"}),!0}catch{return!1}}function Tl(){return typeof process.getuid=="function"&&process.getuid()===0}function Vn(t){let e=process.execPath,n=process.argv[1]?Wu.resolve(process.argv[1]):"",r=t||process.env.SERVERFULL_SERVICE_USER||process.env.SUDO_USER||process.env.USER||"root",s=r==="root"?"/root":process.env.SUDO_USER&&r===process.env.SUDO_USER?`/home/${process.env.SUDO_USER}`:process.env.HOME||process.cwd(),o="";return n&&Ku.existsSync(n)?o=`"${e}" "${n}"`:o="dns-worker",{execCmd:o,nodePath:e,scriptPath:n,workDir:process.platform==="win32"?process.cwd():s,user:r}}import sn from"node:fs";import Vu from"node:path";import{execSync as Ve}from"node:child_process";var ct="dns-worker",Ju=`${ct}.service`,Jn=`/etc/systemd/system/${Ju}`;function Oi(t){let{execCmd:e,workDir:n,user:r}=t;return`[Unit]
443
+ `).bind(t.id).first()),d?Response.json({encryptedSk:d.encrypted_sk,iv:d.iv}):new Response("Wrapped key not found for this passkey",{status:404})}if(c==="recovery-wrapped-key"&&n.method==="GET"){let a=await e.DB.prepare("SELECT encrypted_sk, iv, salt FROM user_recovery_wrapped_keys WHERE profile_id IN (SELECT id FROM profiles WHERE owner_id = ?) LIMIT 1").bind(t.id).first();return a?Response.json({encryptedSk:a.encrypted_sk,iv:a.iv,salt:a.salt}):new Response("Recovery wrapped key not found",{status:404})}if(c==="init"&&n.method==="POST"){let a;try{a=await n.json()}catch{return new Response("Invalid JSON body",{status:400})}let{publicKey:l,passkeyId:d,encryptedSk:u,iv:f,recovery:p}=a;if(!l||!d&&!p)return new Response("Missing required fields (publicKey and either passkey or recovery)",{status:400});let m=null;if(d&&(m=await o.getByIdOrCredentialId(d,t.id),!m)){let E=await o.listByUser(t.id);E.length>0&&(m=E[0])}let h=await i.listByOwner(t.id),g=Math.floor(Date.now()/1e3),b=typeof l=="string"?l:JSON.stringify(l),w=[],y=h.length>0?h[0].id:null;if(y){m&&u&&f&&w.push(e.DB.prepare("INSERT INTO user_passkey_wrapped_keys (passkey_id, profile_id, encrypted_sk, iv, created_at) VALUES (?, ?, ?, ?, ?) ON CONFLICT(passkey_id) DO UPDATE SET encrypted_sk = excluded.encrypted_sk, iv = excluded.iv, created_at = excluded.created_at").bind(m.id,y,u,f,g));for(let E of h)w.push(e.DB.prepare("INSERT INTO user_log_keys (profile_id, public_key, created_at, is_active) VALUES (?, ?, ?, 1) ON CONFLICT(profile_id) DO UPDATE SET public_key = excluded.public_key, created_at = excluded.created_at, is_active = 1").bind(E.id,b,g)),p&&p.encryptedSk&&p.iv&&p.salt&&w.push(e.DB.prepare("INSERT INTO user_recovery_wrapped_keys (profile_id, encrypted_sk, iv, salt, created_at) VALUES (?, ?, ?, ?, ?) ON CONFLICT(profile_id) DO UPDATE SET encrypted_sk = excluded.encrypted_sk, iv = excluded.iv, salt = excluded.salt, created_at = excluded.created_at").bind(E.id,p.encryptedSk,p.iv,p.salt,g))}w.length>0&&await e.DB.batch(w);for(let E of h)en(E.id);return Response.json({success:!0})}if(c==="wrap"&&n.method==="POST"){let a;try{a=await n.json()}catch{return new Response("Invalid JSON body",{status:400})}let{passkeyId:l,encryptedSk:d,iv:u}=a;if(!l||!d||!u)return new Response("Missing required fields (passkeyId, encryptedSk, iv)",{status:400});let f=await o.getByIdOrCredentialId(l,t.id);if(!f){let g=await o.listByUser(t.id);g.length>0&&(f=g[0])}if(!f)return new Response("Passkey not found or unauthorized",{status:403});let p=await i.listByOwner(t.id),m=p.length>0?p[0].id:null;if(!m)return new Response("No profiles found for user",{status:400});let h=Math.floor(Date.now()/1e3);return await e.DB.prepare("INSERT INTO user_passkey_wrapped_keys (passkey_id, profile_id, encrypted_sk, iv, created_at) VALUES (?, ?, ?, ?, ?) ON CONFLICT(passkey_id) DO UPDATE SET encrypted_sk = excluded.encrypted_sk, iv = excluded.iv, created_at = excluded.created_at").bind(f.id,m,d,u,h).run(),Response.json({success:!0})}if(c==="wrap-recovery"&&n.method==="POST"){let a;try{a=await n.json()}catch{return new Response("Invalid JSON body",{status:400})}let{encryptedSk:l,iv:d,salt:u}=a;if(!l||!d||!u)return new Response("Missing required fields (encryptedSk, iv, salt)",{status:400});let f=await i.listByOwner(t.id),p=Math.floor(Date.now()/1e3),m=[];for(let h of f)m.push(e.DB.prepare("INSERT INTO user_recovery_wrapped_keys (profile_id, encrypted_sk, iv, salt, created_at) VALUES (?, ?, ?, ?, ?) ON CONFLICT(profile_id) DO UPDATE SET encrypted_sk = excluded.encrypted_sk, iv = excluded.iv, salt = excluded.salt, created_at = excluded.created_at").bind(h.id,l,d,u,p));return m.length>0&&await e.DB.batch(m),Response.json({success:!0})}if(c==="enable"&&n.method==="POST"){let a=await i.listByOwner(t.id);await e.DB.prepare("UPDATE user_log_keys SET is_active = 1 WHERE profile_id IN (SELECT id FROM profiles WHERE owner_id = ?)").bind(t.id).run();for(let l of a)en(l.id);return Response.json({success:!0,enabled:!0})}if(n.method==="DELETE"&&(!c||c==="keys")){let l=new URL(n.url).searchParams.get("purge")==="true",d=await i.listByOwner(t.id);l?await e.DB.batch([e.DB.prepare("DELETE FROM user_log_keys WHERE profile_id IN (SELECT id FROM profiles WHERE owner_id = ?)").bind(t.id),e.DB.prepare("DELETE FROM user_passkey_wrapped_keys WHERE passkey_id IN (SELECT id FROM passkeys WHERE user_id = ?)").bind(t.id),e.DB.prepare("DELETE FROM user_recovery_wrapped_keys WHERE profile_id IN (SELECT id FROM profiles WHERE owner_id = ?)").bind(t.id)]):await e.DB.prepare("UPDATE user_log_keys SET is_active = 0 WHERE profile_id IN (SELECT id FROM profiles WHERE owner_id = ?)").bind(t.id).run();for(let u of d)en(u.id);return Response.json({success:!0,purged:l,enabled:!1})}return new Response("Not Found",{status:404})}async function bl(n,e,t,r,s){let o=r[2];return o==="me"||o==="delete"||o==="logs"||o==="db-size"?dl(n,e,t,r,s):o==="password"||o==="totp"||o==="passkeys"||o==="mfa"||o==="migrate-password"||o==="pin"||o==="recovery-keys"?gl(n,e,t,r,s):o==="activity"||o==="sessions"?yl(n,e,t,r,s):o==="e2ee"?wl(n,e,t,r,s):new Response("Not Found",{status:404})}pe();Te();async function El(n,e,t,r,s){let o=new Y(e.DB,e),i=new q(e.DB);if(r[2]==="users"){if(n.method==="GET"){let c=await o.listAll();return new Response(JSON.stringify(c),{headers:{"Content-Type":"application/json"}})}if(n.method==="POST"){let{username:c,password:a,role:l}=await n.json();if(!c||!Rt.test(c))return new Response("Invalid username format",{status:400});if(!a||!St.test(a))return new Response("Password format error",{status:400});let d=await ot(a,2),u=j(15);try{return await o.create({id:u,username:c,passwordHash:d,role:l||"user",passwordVersion:2}),new Response(JSON.stringify({id:u}),{status:201})}catch(f){return new Response(f.message,{status:400})}}if(n.method==="DELETE"&&r[3]){let c=r[3];return c===t.id?new Response("Cannot delete yourself",{status:400}):(await i.deleteByOwner(c),await o.delete(c),new Response(null,{status:204}))}}if(r[2]==="settings"){let c=new he(e.DB);if(n.method==="GET"){let a=await c.getAll();return delete a.jwt_secret,new Response(JSON.stringify(a),{headers:{"Content-Type":"application/json"}})}if(n.method==="PATCH"){let a=await n.json();return delete a.jwt_secret,await c.setMany(a),new Response(JSON.stringify({success:!0}))}}return new Response("Not Found",{status:404})}async function _l(n,e,t,r){let o=new URL(n.url).pathname.split("/").filter(Boolean);return o[1]==="account"?bl(n,e,t,o,r):o[1]==="admin"?Yn.isAdmin(t)?El(n,e,t,o,r):new Response("Forbidden",{status:403}):new Response("Not Found",{status:404})}ge();async function Sl(n,e){let t=new URL(n.url),r=typeof caches<"u"?caches.default:null;if(t.pathname==="/api/clientinfo"){let s=n.headers.get("CF-Connecting-IP")||"127.0.0.1",o=await P.get(r,`active_dns:${s}`),i=n.cf,c=i?.country||n.headers.get("CF-IPCountry")||"",a=c,l=i?.region||n.headers.get("CF-Region")||"",d=i?.city||n.headers.get("CF-IPCity")||"",u=i?.timezone||n.headers.get("CF-Timezone")||"",f=i?.asn?Number(i.asn):n.headers.get("CF-ASN")?Number(n.headers.get("CF-ASN")):0,p=i?.asOrganization||n.headers.get("CF-AS-Org")||"";if(!c||c==="UNKNOWN"||c==="UN"||c==="XX")if(!qe(s))c="Private Network",a="LAN",l="LAN",d="Local",u="UNKNOWN",p="Private Network";else try{let h=await Er(s);if(h&&(c=h.country||h.country_code||"UNKNOWN",a=h.country_code||"UNKNOWN",l=h.region||"UNKNOWN",d=h.city||"UNKNOWN",u=h.timezone||"UNKNOWN",p=h.org||h.isp||"UNKNOWN",!f&&h.as)){let g=h.as.match(/^AS(\d+)/i);g&&(f=Number(g[1]))}}catch(h){console.warn(`[ClientInfo] Failed resolving geoip for ${s}:`,h)}let m=e.SERVERFULL_DEFAULT_PROFILE_KEY!==void 0||e.SERVERFULL_HOST!==void 0||e.SERVERFULL_DOT_DOMAIN!==void 0||e.SERVERFULL_HTTP_PORT!==void 0||e.SERVERFULL_HTTPS_PORT!==void 0;return new Response(JSON.stringify({ip:s,country:c||"UNKNOWN",countryCode:a||void 0,region:l||"UNKNOWN",city:d||"UNKNOWN",timezone:u||"UNKNOWN",asn:f||0,asOrganization:p||"UNKNOWN",connectedProfileId:o||null,substituteDomain:e.SUBSTITUTE_DOMAIN||tr,dotDomain:e.SERVERFULL_DOT_DOMAIN||e.DOT_DOMAIN||null,isServerfull:m,mode:m?"serverfull":"cloudflare"}),{headers:{"Content-Type":"application/json"}})}if(t.pathname==="/api/regions"){let s={};for(let[o,i]of Object.entries(e))if(o.startsWith("IP_REGION_")&&typeof i=="string")try{let c=o.replace("IP_REGION_",""),a=i.trim();a=a.replace(/^"""|"""$/g,"").replace(/^"|"$/g,"").replace(/^'|'$/g,"").trim(),s[c]=JSON.parse(a)}catch{}return Object.keys(s).length===0&&(s.CN=Xr),new Response(JSON.stringify(s),{headers:{"Content-Type":"application/json"}})}if(t.pathname==="/api/substitute"){let s=e.SUBSTITUTE_DOMAIN||tr,o=null,i=null,c=async a=>{let l=["https://cloudflare-dns.com/dns-query","https://1.1.1.1/dns-query"];for(let d of l)try{let u=await fetch(`${d}?name=${s}&type=${a}`,{headers:{Accept:"application/dns-json"},signal:AbortSignal.timeout(3e3)});if(u.ok){let f=await u.json();if(f?.Answer?.length>0){let p=f.Answer.find(m=>m.type===(a==="A"?1:28));if(p?.data)return p.data}}}catch(u){console.error(`[Substitute Resolve] Failed resolving ${a} via ${d}:`,u)}return null};try{let[a,l]=await Promise.all([c("A"),c("AAAA")]);o=a,i=l}catch(a){console.error("[Substitute API] Error resolving substitute domain:",a)}return new Response(JSON.stringify({ip:o,ipv6:i}),{headers:{"Content-Type":"application/json"}})}if(t.pathname==="/api/presets/upstreams"){let s=Yr;if(e.PRESET_UPSTREAMS)try{let o=JSON.parse(e.PRESET_UPSTREAMS);Array.isArray(o)&&o.length>0&&(s=o)}catch(o){console.warn("[System API] Failed to parse PRESET_UPSTREAMS from env:",o)}return new Response(JSON.stringify(s),{headers:{"Content-Type":"application/json"}})}if(t.pathname==="/api/presets/filters"){let s=zr;if(e.PRESET_EXTERNAL_FILTERS)try{let o=JSON.parse(e.PRESET_EXTERNAL_FILTERS);Array.isArray(o)&&o.length>0&&(s=o)}catch(o){console.warn("[System API] Failed to parse PRESET_EXTERNAL_FILTERS from env:",o)}return new Response(JSON.stringify(s),{headers:{"Content-Type":"application/json"}})}if(t.pathname==="/api/presets/ech-fronting-domains"){let s=Ji(e);return new Response(JSON.stringify(s),{headers:{"Content-Type":"application/json"}})}if(t.pathname.startsWith("/api/icon/")){let s=t.pathname.replace("/api/icon/","");if(!s||!/^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(s)||s.includes("..")||s.includes("/")||s.includes("\\"))return new Response("Invalid domain format",{status:400});let o=`https://icons.duckduckgo.com/ip3/${s}`;try{let i=await fetch(o),c=new Headers(i.headers);return c.set("Cache-Control","public, max-age=2592000"),c.delete("Access-Control-Allow-Origin"),new Response(i.body,{status:i.status,statusText:i.statusText,headers:c})}catch{return new Response("Error fetching icon",{status:500})}}if(t.pathname==="/api/geoip"){let s=t.searchParams.get("ip"),o=n.headers.get("CF-Connecting-IP"),i=(s||o||"").trim();if(i==="127.0.0.1"||i==="localhost"||i==="::1"||i.startsWith("192.168.")||i.startsWith("10.")||/^172\.(1[6-9]|2\d|3[01])\./.test(i))return new Response(JSON.stringify({success:!0,ip:i,city:"Local",country:"Private Network",flag:{emoji:"\u{1F3E0}"}}),{headers:{"Content-Type":"application/json"}});try{let c=i?`https://ipwho.is/${encodeURIComponent(i)}`:"https://ipwho.is/",a=await fetch(c,{signal:AbortSignal.timeout(3500)});if(a.ok){let l=await a.json();return new Response(JSON.stringify(l),{headers:{"Content-Type":"application/json"}})}}catch(c){console.warn(`[System API] Failed resolving geoip for ${i||"server"}:`,c)}return new Response(JSON.stringify({success:!1,ip:i||"unknown"}),{headers:{"Content-Type":"application/json"}})}if(t.pathname==="/api/resolve"){let s=t.searchParams.get("name")||t.searchParams.get("domain");if(!s)return new Response(JSON.stringify({error:"Missing domain parameter"}),{status:400,headers:{"Content-Type":"application/json"}});if(/^(\d{1,3}\.){3}\d{1,3}$/.test(s))return new Response(JSON.stringify({ipv4:[s],ipv6:[]}),{headers:{"Content-Type":"application/json"}});if(/^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$/.test(s))return new Response(JSON.stringify({ipv4:[],ipv6:[s]}),{headers:{"Content-Type":"application/json"}});let o=async i=>{let c=["https://cloudflare-dns.com/dns-query","https://1.1.1.1/dns-query"];for(let a of c)try{let l=await fetch(`${a}?name=${encodeURIComponent(s)}&type=${i}`,{headers:{Accept:"application/dns-json"},signal:AbortSignal.timeout(3e3)});if(l.ok){let d=await l.json();if(Array.isArray(d?.Answer)&&d.Answer.length>0){let u=i==="A"?1:28;return d.Answer.filter(f=>f.type===u&&typeof f.data=="string").map(f=>f.data)}}}catch{}return[]};try{let[i,c]=await Promise.all([o("A"),o("AAAA")]);if(i.length===0&&c.length===0&&typeof process<"u"&&process.versions?.node)try{let a=await import("node:dns/promises"),[l,d]=await Promise.allSettled([a.resolve4(s),a.resolve6(s)]);l.status==="fulfilled"&&Array.isArray(l.value)&&(i=l.value),d.status==="fulfilled"&&Array.isArray(d.value)&&(c=d.value)}catch{}return new Response(JSON.stringify({ipv4:i,ipv6:c}),{headers:{"Content-Type":"application/json"}})}catch(i){return console.error("DNS resolve failed:",i),new Response(JSON.stringify({ipv4:[],ipv6:[],error:"Internal server error"}),{status:500,headers:{"Content-Type":"application/json"}})}}return new Response("Not Found",{status:404})}ge();async function Rl(n,e,t){try{let r=caches.default,s=Math.floor(Date.now()/1e3),o="cron:last_cleanup_timestamp",i=await P.get(r,o);if(!i||s-i>=3600){try{let c=new Y(e.DB,e),{clearedProfiles:a,deletedUsers:l}=await c.applyInactivityPolicy(s);(a>0||l>0)&&console.log(`[Cron] Inactivity cleanup: cleared ${a} profile(s), deleted ${l} user(s).`)}catch(c){console.error("[Cron] Inactivity policy execution failed:",c)}try{let c=new Ie(e.DB),a=e.MAX_LOG_RETENTION_DAYS!==void 0&&e.MAX_LOG_RETENTION_DAYS!==""?Number(e.MAX_LOG_RETENTION_DAYS):30,l=e.LOG_CLEANUP_BATCH_LIMIT!==void 0&&e.LOG_CLEANUP_BATCH_LIMIT!==""?Number(e.LOG_CLEANUP_BATCH_LIMIT):1e3,d=e.LOG_CLEANUP_DAILY_BUDGET!==void 0&&e.LOG_CLEANUP_DAILY_BUDGET!==""?Number(e.LOG_CLEANUP_DAILY_BUDGET):2e4;await c.cleanupGlobal(a,l,d)}catch(c){console.error("[Cron] Global log cleanup failed:",c)}try{let{SessionModel:c}=await Promise.resolve().then(()=>(Be(),pr)),a=new c(e.DB),{deletedSessions:l,deletedPending:d}=await a.deleteExpiredSessions(s);(l>0||d>0)&&console.log(`[Cron] Purged ${l} expired session(s) and ${d} pending token(s).`)}catch(c){console.error("[Cron] Session cleanup failed:",c)}await P.set(r,o,s,3600),console.log("[Cron] Cleanup phase completed at",new Date().toISOString())}try{await Bo(e.DB)}catch(c){console.error("[Cron] Cloudflare IP range sync failed:",c)}try{let c="cron:last_idle_sync_check",l=await P.get(r,c);if(!!!(l&&s-l<600)){let u=Number(e.SYNC_PROFILE_INTERVAL_SEC)||86400,f=s-u,p=new q(e.DB),m=Number(e.SYNC_BATCH_SIZE)||1,h=await p.getSyncTargets(f,m);if(h.length>0){await P.delete(r,c);for(let g of h)try{await zn(g.id,e,t)}catch(b){let w=b instanceof Error?b.message:String(b);console.error(`[Cron] Sync failed for profile ${g.id}:`,w)}console.log(`[Cron] Sync: processed ${h.length} profile(s).`)}else await P.set(r,c,s,600)}}catch(c){let a=c instanceof Error?c.message:String(c);console.error("[Cron] Sync phase failed:",a)}}catch(r){let s=r instanceof Error?r.message:String(r);console.error("[Cron] Critical Failure:",s)}}async function Tl(n,e,t){let r=new Request(new URL("https://obex.local/world-110m-v2.json"),n),s=caches.default,o=await s.match(r);if(!o)try{let c=await fetch("https://openlayers.org/en/latest/examples/data/topojson/world-110m.json",{headers:{"User-Agent":"DNS Worker/1.0 (Cloudflare Worker Map Proxy)"}});if(!c.ok)throw new Error(`Failed to fetch map data from openlayers.org: ${c.status}`);let a=await c.json();if(a&&a.objects){let l={};a.objects.countries&&(l.countries=a.objects.countries),a.objects.land&&(l.land=a.objects.land),a.objects=l}a&&a.objects&&a.objects.countries&&Array.isArray(a.objects.countries.geometries)&&a.objects.countries.geometries.forEach(l=>{l.id!==void 0&&l.id!==null&&(l.id=String(l.id).padStart(3,"0"))}),o=new Response(JSON.stringify(a),{headers:{"Content-Type":"application/json; charset=utf-8","Cache-Control":"public, max-age=2592000","Access-Control-Allow-Origin":"*"}}),t.waitUntil(s.put(r,o.clone()))}catch(i){return console.error("[MapData API Proxy] Error fetching or transforming TopoJSON:",i),new Response(JSON.stringify({error:"Failed to fetch map data"}),{status:502,headers:{"Content-Type":"application/json"}})}return o}Fe();var Eo={async fetch(n,e,t){let r=new Uint8Array(16);crypto.getRandomValues(r);let s=Array.from(r).map(l=>l.toString(16).padStart(2,"0")).join(""),o=null,c=await(async()=>{let l=new URL(n.url);if(l.pathname==="/world-110m.json")return Tl(n,e,t);if(l.pathname.startsWith("/api/")){let p=!1;try{p=!e.DB}catch{p=!0}let m=!Oe(e.JWT_SECRET);if(p||m)return new Response(JSON.stringify({error:"configuration_error",isDbMissing:p,isJwtSecretMissing:m,message:"DNS Worker is not fully configured. Please configure the D1 database binding and JWT_SECRET secret variable."}),{status:503,headers:{"Content-Type":"application/json","Access-Control-Allow-Origin":"*"}});o=await Li(n,e,t);let h=["/api/auth/login","/api/auth/signup","/api/auth/prelogin","/api/auth/check-username","/api/auth/config","/api/auth/refresh","/api/auth/logout","/api/auth/unlock-session","/api/clientinfo","/api/regions","/api/substitute","/api/resolve","/api/geoip"].includes(l.pathname)||l.pathname.startsWith("/api/icon/")||l.pathname.startsWith("/api/presets/")||l.pathname.startsWith("/api/auth/forgot-password");return!o&&!h?new Response("Unauthorized",{status:401}):o&&o.isPaused&&!["/api/auth/unlock-session","/api/auth/logout","/api/auth/refresh"].includes(l.pathname)?new Response("session_paused",{status:403}):o&&["POST","PUT","PATCH","DELETE"].includes(n.method)&&!h&&!Oi(n)?new Response("CSRF validation failed",{status:403}):l.pathname.startsWith("/api/auth/")?Zc(n,e):l.pathname==="/api/clientinfo"||l.pathname==="/api/regions"||l.pathname==="/api/substitute"||l.pathname==="/api/resolve"||l.pathname==="/api/geoip"||l.pathname.startsWith("/api/presets/")||l.pathname.startsWith("/api/icon/")?Sl(n,e):l.pathname.startsWith("/api/profiles")?cl(n,e,o,t):l.pathname.startsWith("/api/account")||l.pathname.startsWith("/api/admin")?_l(n,e,o,t):new Response("API Not Found",{status:404})}if(l.pathname==="/setup.sh"){let p=l.searchParams.get("key");if(!p||!Wt.test(p))return new Response("Missing or invalid key parameter",{status:400});let m=Fc(l.origin,p);return new Response(m,{headers:{"Content-Type":"text/plain; charset=utf-8","Cache-Control":"no-cache"}})}let d=l.pathname.slice(1),u=Wt.test(d),f=n.method==="POST"||l.searchParams.has("dns")||n.headers.get("accept")?.includes("dns-message");if(u&&(f||n.method==="OPTIONS"))return n.method==="OPTIONS"?new Response(null,{status:204,headers:{"Access-Control-Allow-Origin":"*","Access-Control-Allow-Methods":"GET, POST, OPTIONS","Access-Control-Allow-Headers":"Content-Type, Accept","Access-Control-Max-Age":"86400"}}):Uc(n,e,t,d);try{let p=await e.ASSETS.fetch(n);if(p.status===404&&!l.pathname.startsWith("/assets/")&&(n.method==="GET"||n.method==="HEAD")&&(p=await e.ASSETS.fetch(new Request(l.origin+"/",{method:n.method,headers:n.headers}))),l.pathname.endsWith(".wasm")){let h=new Headers(p.headers);return h.set("Content-Type","application/wasm"),h.set("Cross-Origin-Resource-Policy","same-origin"),new Response(p.body,{status:p.status,statusText:p.statusText,headers:h})}if((p.headers.get("Content-Type")||"").includes("text/html")){let h=!1;try{h=!e.DB}catch{h=!0}let g=!Oe(e.JWT_SECRET),b=e.SERVERFULL_DEFAULT_PROFILE_KEY!==void 0||e.SERVERFULL_HOST!==void 0||e.SERVERFULL_DOT_DOMAIN!==void 0||e.SERVERFULL_HTTP_PORT!==void 0||e.SERVERFULL_HTTPS_PORT!==void 0,w="{}";try{w=JSON.stringify({nonce:s,isDbMissing:h,isJwtSecretMissing:g,isServerfull:b,mode:b?"serverfull":"cloudflare"})}catch{}return new HTMLRewriter().on("head",{element(y){y.prepend(`<script nonce="${s}">window.DNS_WORKER_CONFIG = ${w};</script>`,{html:!0})}}).transform(p)}return p}catch{return new Response("Asset Fetch Error",{status:500})}})(),a=o;if(a&&!_n(n.headers.get("Cookie"))){let l=a.sessionId?.startsWith("k_");try{let d=j(32);c.headers.append("Set-Cookie",it(d,e,l))}catch{let u=new Headers(c.headers),f=j(32);u.append("Set-Cookie",it(f,e,l)),c=new Response(c.body,{status:c.status,statusText:c.statusText,headers:u})}}if(c.headers.get("Content-Type")?.includes("application/dns-message")){let l=new Headers(c.headers);return l.set("Access-Control-Allow-Origin","*"),l.set("Access-Control-Allow-Methods","GET, POST, OPTIONS"),l.set("Access-Control-Allow-Headers","Content-Type, Accept"),new Response(c.body,{status:c.status,statusText:c.statusText,headers:l})}return ki(c,s)},async scheduled(n,e,t){await Rl(n,e,t)}};var Vu={".html":"text/html; charset=utf-8",".js":"application/javascript; charset=utf-8",".mjs":"application/javascript; charset=utf-8",".css":"text/css; charset=utf-8",".json":"application/json; charset=utf-8",".webp":"image/webp",".png":"image/png",".jpg":"image/jpeg",".svg":"image/svg+xml",".ico":"image/x-icon",".webmanifest":"application/manifest+json",".wasm":"application/wasm"};function Al(n,e){if(n.ASSETS)return;let t=e||_o.join(Mt(),"static");n.ASSETS={fetch:async r=>{try{let s=new URL(r.url),o=decodeURIComponent(s.pathname);(o==="/"||o==="")&&(o="/index.html");let i=_o.normalize(o).replace(/^(\.\.[\/\\])+/,""),c=_o.join(t,i);if(jr.existsSync(c)&&jr.statSync(c).isFile()){let a=_o.extname(c).toLowerCase(),l=Vu[a]||"application/octet-stream",d=jr.readFileSync(c);return new Response(d,{status:200,headers:{"Content-Type":l,"Cache-Control":a===".html"?"no-cache":"public, max-age=31536000, immutable","Cross-Origin-Opener-Policy":"same-origin","Cross-Origin-Embedder-Policy":"credentialless","Cross-Origin-Resource-Policy":"same-origin"}})}return new Response("Not Found",{status:404})}catch{return new Response("Asset Error",{status:500})}}}}function So(n){if(!n||typeof n!="string")return null;let e=n.trim();if(!e)return null;if(e.startsWith("[")){let t=e.indexOf("]");t>1&&(e=e.substring(1,t))}else if(e.includes(":")&&e.indexOf(":")===e.lastIndexOf(":")){let[t,r]=e.split(":");r&&/^\d+$/.test(r)&&st(t)&&(e=t)}return e.startsWith("::ffff:")&&(e=e.substring(7)),st(e)||Ft(e)?e:null}function Gu(n,e){return e?(Array.isArray(e)?e:e.split(",").map(r=>r.trim()).filter(Boolean)).includes(n):!1}function Ju(n,e,t){let r=So(e);if(r&&qe(r)&&!Gu(r,t))return r;let s=So(n.get("CF-Connecting-IP"));if(s)return s;let o=So(n.get("X-Real-IP"));if(o)return o;let i=n.get("X-Forwarded-For");if(i){let c=i.split(",");for(let a of c){let l=So(a);if(l)return l}}return r||"127.0.0.1"}function vl(n,e,t,r){return async(s,o)=>{try{let i=s.headers["x-forwarded-proto"]||e,c=s.headers.host||`${t}:${r}`,a=new URL(s.url||"/",`${i}://${c}`),l=new Headers;for(let[w,y]of Object.entries(s.headers))y&&(Array.isArray(y)?y.forEach(E=>l.append(w,E)):l.set(w,String(y)));let d=Ju(l,s.socket.remoteAddress,n.TRUSTED_PROXIES);l.set("CF-Connecting-IP",d);let u=l.get("CF-IPLatitude");(!u||u.trim()==="")&&l.set("CF-IPLatitude","0.0");let f=l.get("CF-IPLongitude");(!f||f.trim()==="")&&l.set("CF-IPLongitude","0.0");let p=null;if(s.method!=="GET"&&s.method!=="HEAD"){let w=[];for await(let y of s)w.push(typeof y=="string"?xl.from(y):y);p=xl.concat(w)}let m=new Request(a.toString(),{method:s.method,headers:l,body:p,duplex:"half"}),h={waitUntil(w){w.catch(y=>console.error(`[${e.toUpperCase()} Background Task Error]:`,y))},passThroughOnException(){}},g=await Eo.fetch(m,n,h);o.statusCode=g.status,o.statusMessage=g.statusText;let b=typeof g.headers.getSetCookie=="function"?g.headers.getSetCookie():[];if(b.length===0&&g.headers.has("set-cookie")){let w=g.headers.get("set-cookie");w&&(b=[w])}if(g.headers.forEach((w,y)=>{let E=y.toLowerCase();E!=="set-cookie"&&(e==="https"&&E==="alt-svc"?o.setHeader("Alt-Svc",`h3=":${r}"; ma=86400, h3-29=":${r}"; ma=86400`):o.setHeader(y,w))}),b.length>0){let y=i==="http"?b.map(E=>E.replace(/;\s*Secure\b/gi,"")):b;o.setHeader("Set-Cookie",y)}if(e==="https"&&!o.hasHeader("Alt-Svc")&&o.setHeader("Alt-Svc",`h3=":${r}"; ma=86400, h3-29=":${r}"; ma=86400`),g.body){let w=g.body.getReader();for(;;){let{done:y,value:E}=await w.read();if(y)break;o.write(E)}}o.end()}catch(i){console.error(`[${e.toUpperCase()} Server] Request processing failed:`,i),o.headersSent||(o.statusCode=500,o.setHeader("Content-Type","application/json"),o.end(JSON.stringify({error:"Internal Server Error"})))}}}var Ro=class{constructor(e){this.options=e;Al(this.options.env,this.options.staticDir)}options;server=null;isRunning=!1;start(){return new Promise((e,t)=>{let{port:r,host:s,env:o}=this.options,i=vl(o,"http",s,r);this.server=Wu.createServer(i),this.server.keepAliveTimeout=65e3,this.server.headersTimeout=66e3,this.server.on("connection",a=>{a.setNoDelay(!0)});let c=a=>{this.server=null,console.error(sn({serviceName:"Web Dashboard & DoH (HTTP)",protocol:"HTTP",port:r,err:a,alternateOption:`--http-port <port> (e.g. --http-port ${r+1})`})),t(a)};this.server.once("error",c),this.server.listen(r,s,()=>{this.server?.removeListener("error",c),this.server?.on("error",a=>{console.error("[HTTP Server] Runtime error:",a)}),this.isRunning=!0,console.log(`[HTTP Server] Web Dashboard & DoH listening on http://${s}:${r}`),e()})})}stop(){return new Promise(e=>{this.server&&this.isRunning?this.server.close(()=>{this.isRunning=!1,console.log("[HTTP Server] Service stopped."),e()}):e()})}},To=class{constructor(e){this.options=e;Al(this.options.env,this.options.staticDir)}options;server=null;isRunning=!1;start(){return new Promise((e,t)=>{let{port:r,host:s,certPath:o,keyPath:i,env:c}=this.options;try{let a=jr.readFileSync(o),l=jr.readFileSync(i),d=vl(c,"https",s,r);this.server=ju.createServer({cert:a,key:l},d),this.server.keepAliveTimeout=65e3,this.server.headersTimeout=66e3,this.server.on("connection",f=>{f.setNoDelay(!0)});let u=f=>{this.server=null,console.error(sn({serviceName:"Web Dashboard & DoH (HTTPS)",protocol:"HTTPS",port:r,err:f,alternateOption:`--https-port <port> (e.g. --https-port ${r+1})`})),t(f)};this.server.once("error",u),this.server.listen(r,s,()=>{this.server?.removeListener("error",u),this.server?.on("error",f=>{console.error("[HTTPS Server] Runtime error:",f)}),this.isRunning=!0,console.log(`[HTTPS Server] Web Dashboard & DoH listening on https://${s}:${r}`),e()})}catch(a){t(a)}})}stop(){return new Promise(e=>{this.server&&this.isRunning?this.server.close(()=>{this.isRunning=!1,console.log("[HTTPS Server] Service stopped."),e()}):e()})}};Fe();import Pl from"node:fs";import Yu from"node:net";import zu from"node:dgram";import{DatabaseSync as Xu}from"node:sqlite";Fe();function Fi(n,e,t=300){return new Promise(r=>{let s=new Yu.Socket,o=!1,i=a=>{if(!o){o=!0;try{s.destroy()}catch{}r(a)}};s.setTimeout(t),s.once("connect",()=>i("active")),s.once("timeout",()=>i("free")),s.once("error",()=>i("free"));let c=e==="0.0.0.0"||e==="::"?"127.0.0.1":e;try{s.connect(n,c)}catch{i("free")}})}function Qu(n,e){return new Promise(t=>{let r=zu.createSocket("udp4"),s=!1,o=i=>{if(!s){s=!0;try{r.close()}catch{}t(i)}};r.once("error",i=>{let c=i?.code;o(c==="EADDRINUSE"?"active":"free")});try{r.bind(n,e,()=>{o("free")})}catch{o("active")}})}function Zu(n){if(!Pl.existsSync(n))return{exists:!1,statusText:"Not Initialized (File does not exist yet; created on first start)"};try{let e=Pl.statSync(n),t=e.size>1024*1024?`${(e.size/(1024*1024)).toFixed(2)} MB`:`${(e.size/1024).toFixed(1)} KB`,r=0,s=0,o=0;try{let c=new Xu(n,{readOnly:!0}),a=c.prepare("SELECT count(*) as cnt FROM sqlite_master WHERE type='table' AND name='d1_migrations'").get();a&&a.cnt>0&&(r=c.prepare("SELECT count(*) as count FROM d1_migrations").get()?.count||0);let l=c.prepare("SELECT count(*) as cnt FROM sqlite_master WHERE type='table' AND name='users'").get();l&&l.cnt>0&&(s=c.prepare("SELECT count(*) as count FROM users").get()?.count||0);let d=c.prepare("SELECT count(*) as cnt FROM sqlite_master WHERE type='table' AND name='profiles'").get();d&&d.cnt>0&&(o=c.prepare("SELECT count(*) as count FROM profiles").get()?.count||0),c.close()}catch{}let i=[t,r>0?`${r} migrations`:null,s>0?`${s} user(s)`:null,o>0?`${o} profile(s)`:null].filter(Boolean).join(", ");return{exists:!0,sizeFormatted:t,migrationsCount:r,usersCount:s,profilesCount:o,statusText:`Ready (${i})`}}catch(e){return{exists:!0,statusText:`Exists (Read warning: ${e instanceof Error?e.message:String(e)})`}}}async function Cl(n,e){let t=jn(n.tlsCertPath,n.tlsKeyPath),r=!n.disableHttps&&t.configured&&t.filesExist,[s,o,i,c]=await Promise.all([Fi(n.httpPort,n.host),r?Fi(n.httpsPort,n.host):Promise.resolve("disabled"),n.disableUdp?Promise.resolve("disabled"):Qu(n.udpPort,n.host),n.disableDot?Promise.resolve("disabled"):Fi(n.dotPort,n.host)]),a=Zu(n.dbPath),l="Default (Insecure fallback, please configure JWT_SECRET)";Oe(e)&&(l=bt(e)?"Configured (Strong, >= 32 characters)":"Configured (Warning: Shorter than 32 characters)");let d=s==="active"?nn(n.httpPort,"TCP"):null,u=d?`: ${rn(d)}`:"",f=s==="active"?`http://${n.host}:${n.httpPort} [Active / Listening${u}]`:`http://${n.host}:${n.httpPort} [Stopped / Port Available]`,p="";if(n.disableHttps)p="Disabled (--disable-https)";else if(!t.configured)p=`https://${n.host}:${n.httpsPort} [Disabled - TLS Certificates Not Configured]`;else if(!t.filesExist)p=`https://${n.host}:${n.httpsPort} [Warning - TLS Certificate Files Missing]`;else if(o==="active"){let ie=nn(n.httpsPort,"TCP"),k=ie?`: ${rn(ie)}`:"";p=`https://${n.host}:${n.httpsPort} [Active / Listening${k}]`}else p=`https://${n.host}:${n.httpsPort} [Stopped / Port Available]`;let m=!n.disableUdp&&i==="active"?nn(n.udpPort,"UDP"):null,h=m?`: ${rn(m)}`:"",g=n.disableUdp?"Disabled (--disable-udp)":i==="active"?`udp://${n.host}:${n.udpPort} [Active / In Use${h}]`:`udp://${n.host}:${n.udpPort} [Stopped / Port Available]`,b="",w=n.dotDomain?` (${n.dotDomain})`:"";if(n.disableDot)b="Disabled (--disable-dot)";else if(!t.configured)b=`tls://${n.host}:${n.dotPort}${w} [Disabled - TLS Certificates Not Configured]`;else if(!t.filesExist)b=`tls://${n.host}:${n.dotPort}${w} [Warning - TLS Certificate Files Missing]`;else if(!t.isWildcard)b=`tls://${n.host}:${n.dotPort}${w} [Paused - Requires Wildcard Certificate (*.domain)]`;else if(c==="active"){let ie=nn(n.dotPort,"TCP"),k=ie?`: ${rn(ie)}`:"";b=`tls://${n.host}:${n.dotPort}${w} [Active / Listening${k}]`}else b=`tls://${n.host}:${n.dotPort}${w} [Stopped / Port Available]`;let y=n.defaultProfileKey?`Explicit (${n.defaultProfileKey})`:"Auto (Database default profile)",E=Ce({title:"DNS Worker Runtime Status (Serverfull Mode)",borderChar:"=",bullet:"\u2022 "}),_=nt({title:`
444
+ Service Transports:`,items:[{label:"Web Dashboard (HTTP)",value:f},{label:"Web Dashboard (HTTPS)",value:p},{label:"Classic UDP DNS",value:g},{label:"DNS over TLS (DoT)",value:b}]}),S=ts(),x=S.length>0?`${S.join(", ")} [Loaded]`:`None found (Using built-in presets & defaults; default path: ${Xe()})`,T=nt({title:`
445
+ Database & Storage:`,items:[{label:"SQLite Path",value:n.dbPath},{label:"Database Status",value:a.statusText},{label:"Persistent Data Dir",value:ht()}]}),v="Not Configured (HTTP only, HTTPS & DoT disabled)";if(t.configured)if(!t.filesExist)v="Configured [Files Missing]";else if(t.error)v=`Configured [Invalid Certificate: ${t.error}]`;else{let ie=t.isWildcard?"Wildcard (*.domain)":"Single Domain",k=t.expiresAt?t.expiresAt.toISOString().split("T")[0]:"Unknown";v=`Valid (${ie}, Expires: ${k})`}let C=n.dotDomain?`${n.dotDomain} (Wildcard / Single-domain compatible)`:"Not Configured (Auto SNI prefix matching)",L=!n.disableHttps&&t.configured&&t.filesExist?`Enabled via Alt-Svc (UDP :${n.httpsPort}, RFC 9114)`:"Disabled (Requires active HTTPS with TLS certificate)",H=t.configured&&t.filesExist?`Compatible (RFC 9250 / RFC 9460 DDR, UDP :${n.dotPort})`:"Disabled (Requires TLS certificate)",V=n.echEnabled?`Enabled (RFC 9460, Outer SNI: ${n.echFrontingDomain||"cloudflare-ech.com"})`:"Disabled",Q=nt({title:`
446
+ Environment & Security:`,items:[{label:"Node.js Runtime",value:`v${process.versions.node} (${process.platform} ${process.arch})`},{label:"Config Directory",value:mn()},{label:"Config Source",value:x},{label:"TLS Certificate",value:v},{label:"JWT Secret",value:l},{label:"DoT Base Domain",value:C},{label:"HTTP/3 (h3)",value:L},{label:"DNS over QUIC (DoQ)",value:H},{label:"ECH (Encrypted Client Hello)",value:V},{label:"Default Profile Key",value:y}]}),Z=[];if(s==="free"&&(i==="free"||n.disableUdp)){let ie=process.platform==="win32"?"dns-worker service install (in Administrator terminal)":"sudo dns-worker service install";Z.push("Services are currently stopped."),Z.push(`To run continuously as a persistent background daemon: ${ie}`)}let _e=Fr(n.dotDomain);!t.configured||!t.filesExist?(Z.push(`To enable secure HTTPS (port ${n.httpsPort}) and DoT (port ${n.dotPort}):`),Z.push(` ${_e}`)):t.isWildcard||(Z.push("Current certificate is single-domain. To support per-profile DoT (<profile>.domain):"),Z.push(` ${_e}`)),Z.push("Run 'dns-worker ech' to view active ECH configuration, outer SNI, and RFC 9460 DNS records.");let K=Z.length>0?Wn(Z):"",Se=[E,_,T,Q,K].filter(Boolean).join(`
447
+ `);console.log(Se)}import qu from"node:fs";import ep from"node:path";import{execSync as tp}from"node:child_process";function Dl(){try{return tp("net session",{stdio:"ignore"}),!0}catch{return!1}}function kl(){return typeof process.getuid=="function"&&process.getuid()===0}function Xn(n){let e=process.execPath,t=process.argv[1]?ep.resolve(process.argv[1]):"",r=n||process.env.SERVERFULL_SERVICE_USER||process.env.SUDO_USER||process.env.USER||"root",s=r==="root"?"/root":process.env.SUDO_USER&&r===process.env.SUDO_USER?`/home/${process.env.SUDO_USER}`:process.env.HOME||process.cwd(),o="";return t&&qu.existsSync(t)?o=`"${e}" "${t}"`:o="dns-worker",{execCmd:o,nodePath:e,scriptPath:t,workDir:process.platform==="win32"?process.cwd():s,user:r}}import dn from"node:fs";import np from"node:path";import{execSync as Je}from"node:child_process";var mt="dns-worker",rp=`${mt}.service`,Qn=`/etc/systemd/system/${rp}`;function Hi(n){let{execCmd:e,workDir:t,user:r}=n;return`[Unit]
448
448
  Description=DNS Worker Serverfull Service (UDP DNS, DoT & Web Dashboard)
449
449
  After=network.target
450
450
 
451
451
  [Service]
452
452
  Type=simple
453
453
  User=${r}
454
- WorkingDirectory=${n}
454
+ WorkingDirectory=${t}
455
455
  ExecStart=${e}
456
456
  Restart=always
457
457
  RestartSec=5
@@ -477,28 +477,32 @@ SyslogIdentifier=dns-worker
477
477
 
478
478
  [Install]
479
479
  WantedBy=multi-user.target
480
- `}async function xl(t,e){let n=Tl();switch(t){case"install":{n||(console.error(M({level:"error",title:"Permission Denied",message:"Installing a systemd service requires elevated privileges (root).",solutions:["Run the command with sudo: sudo dns-worker service install"]})),process.exit(1));let r=Vn(e),s=Oi(r);try{let o="/var/lib/dns-worker",i="/etc/dns-worker",c=Vu.join(i,".env");try{if(sn.existsSync(o)||sn.mkdirSync(o,{recursive:!0,mode:493}),sn.existsSync(i)||sn.mkdirSync(i,{recursive:!0,mode:493}),lt(c,!1),r.user&&r.user!=="root"){try{Ve(`chown -R ${r.user} ${o}`)}catch{}try{Ve(`chown -R ${r.user} ${i}`)}catch{}}}catch{}sn.writeFileSync(Jn,s,"utf-8"),Ve("systemctl daemon-reload",{stdio:"inherit"}),Ve(`systemctl enable ${ct}`,{stdio:"inherit"}),Ve(`systemctl restart ${ct}`,{stdio:"inherit"});let a=We({title:"DNS Worker Linux Service Installed & Started",borderChar:"=",bullet:"\u2022 ",items:[{label:"Service File",value:Jn},{label:"Running As User",value:`${r.user} (CAP_NET_BIND_SERVICE)`},{label:"Persistent Data Dir",value:o},{label:"Config Directory",value:i},{label:"Config File",value:c},{label:"Privileged Ports",value:"Port 53 & 853 enabled without root"},{label:"Auto-restart",value:"Enabled on system boot (Restart=always)"}]}),l=ro({title:"Useful service management commands:",items:[{command:"dns-worker service status",desc:"Check live status"},{command:"dns-worker service logs",desc:"Tail live syslog / journal logs"},{command:"sudo dns-worker service restart",desc:"Restart service"},{command:"sudo dns-worker service enable",desc:"Enable autostart on boot"},{command:"sudo dns-worker service disable",desc:"Disable autostart on boot"},{command:"sudo dns-worker service stop",desc:"Stop service"},{command:"sudo dns-worker service uninstall",desc:"Remove service"}]});console.log(`
480
+ `}async function Ll(n,e){let t=kl();switch(n){case"install":{t||(console.error(O({level:"error",title:"Permission Denied",message:"Installing a systemd service requires elevated privileges (root).",solutions:["Run the command with sudo: sudo dns-worker service install"]})),process.exit(1));let r=Xn(e),s=Hi(r);try{let o="/var/lib/dns-worker",i="/etc/dns-worker",c=np.join(i,".env");try{if(dn.existsSync(o)||dn.mkdirSync(o,{recursive:!0,mode:493}),dn.existsSync(i)||dn.mkdirSync(i,{recursive:!0,mode:493}),Me(c,!1),r.user&&r.user!=="root"){try{Je(`chown -R ${r.user} ${o}`)}catch{}try{Je(`chown -R ${r.user} ${i}`)}catch{}}}catch{}dn.writeFileSync(Qn,s,"utf-8"),Je("systemctl daemon-reload",{stdio:"inherit"}),Je(`systemctl enable ${mt}`,{stdio:"inherit"}),Je(`systemctl restart ${mt}`,{stdio:"inherit"});let a=Ce({title:"DNS Worker Linux Service Installed & Started",borderChar:"=",bullet:"\u2022 ",items:[{label:"Service File",value:Qn},{label:"Running As User",value:`${r.user} (CAP_NET_BIND_SERVICE)`},{label:"Persistent Data Dir",value:o},{label:"Config Directory",value:i},{label:"Config File",value:c},{label:"Privileged Ports",value:"Port 53 & 853 enabled without root"},{label:"Auto-restart",value:"Enabled on system boot (Restart=always)"}]}),l=lo({title:"Useful service management commands:",items:[{command:"dns-worker service status",desc:"Check live status"},{command:"dns-worker service logs",desc:"Tail live syslog / journal logs"},{command:"sudo dns-worker service restart",desc:"Restart service"},{command:"sudo dns-worker service enable",desc:"Enable autostart on boot"},{command:"sudo dns-worker service disable",desc:"Disable autostart on boot"},{command:"sudo dns-worker service stop",desc:"Stop service"},{command:"sudo dns-worker service uninstall",desc:"Remove service"}]});console.log(`
481
481
  `+a+`
482
482
 
483
- `+l)}catch(o){let i=o instanceof Error?o.message:String(o);console.error(M({level:"error",title:"Service Installation Failed",message:i,solutions:["Ensure systemd is running as PID 1 on your Linux distribution.",`Verify permissions to write to ${Jn}.`]})),process.exit(1)}break}case"uninstall":{n||(console.error(M({level:"error",title:"Permission Denied",message:"Uninstalling a systemd service requires elevated privileges (root).",solutions:["Run the command with sudo: sudo dns-worker service uninstall"]})),process.exit(1));try{try{Ve(`systemctl stop ${ct}`,{stdio:"ignore"})}catch{}try{Ve(`systemctl disable ${ct}`,{stdio:"ignore"})}catch{}sn.existsSync(Jn)&&sn.unlinkSync(Jn),Ve("systemctl daemon-reload",{stdio:"inherit"}),console.log(M({level:"success",title:"Service Removed",message:`DNS Worker systemd service removed from ${Jn}.`}))}catch(r){let s=r instanceof Error?r.message:String(r);console.error(M({level:"error",title:"Service Uninstall Failed",message:s})),process.exit(1)}break}case"start":case"stop":case"restart":case"enable":case"disable":{n||(console.error(M({level:"error",title:"Permission Denied",message:`Managing systemd service (${t}) requires elevated privileges.`,solutions:[`Run with sudo: sudo dns-worker service ${t}`]})),process.exit(1));try{Ve(`systemctl ${t} ${ct}`,{stdio:"inherit"}),console.log(M({level:"success",title:"Service Action Executed",message:`systemctl ${t} ${ct}`}))}catch(r){let s=r instanceof Error?r.message:String(r);console.error(M({level:"error",title:`Service ${t} Failed`,message:s})),process.exit(1)}break}case"status":{try{Ve(`systemctl status ${ct}`,{stdio:"inherit"})}catch{}break}case"logs":{try{Ve(`journalctl -u ${ct} -f -n 50`,{stdio:"inherit"})}catch(r){let s=r instanceof Error?r.message:String(r);console.error(M({level:"error",title:"Service Logs Error",message:`journalctl exited: ${s}`}))}break}default:console.error(M({level:"error",title:"Service Command Error",message:`Unknown service action "${t}".`,solutions:["Supported actions: install, start, stop, restart, enable, disable, status, logs, uninstall","Example: sudo dns-worker service install"]})),process.exit(1)}}import on from"node:fs";import bo from"node:path";import{execSync as Je}from"node:child_process";var me="DNS-Worker",Mr=bo.join(process.env.ProgramData||"C:\\ProgramData","DNS-Worker"),an=bo.join(Mr,"service.log"),Ur=bo.join(Mr,"run-service.bat");function Gu(t){return`@echo off\r
483
+ `+l)}catch(o){let i=o instanceof Error?o.message:String(o);console.error(O({level:"error",title:"Service Installation Failed",message:i,solutions:["Ensure systemd is running as PID 1 on your Linux distribution.",`Verify permissions to write to ${Qn}.`]})),process.exit(1)}break}case"uninstall":{t||(console.error(O({level:"error",title:"Permission Denied",message:"Uninstalling a systemd service requires elevated privileges (root).",solutions:["Run the command with sudo: sudo dns-worker service uninstall"]})),process.exit(1));try{try{Je(`systemctl stop ${mt}`,{stdio:"ignore"})}catch{}try{Je(`systemctl disable ${mt}`,{stdio:"ignore"})}catch{}dn.existsSync(Qn)&&dn.unlinkSync(Qn),Je("systemctl daemon-reload",{stdio:"inherit"}),console.log(O({level:"success",title:"Service Removed",message:`DNS Worker systemd service removed from ${Qn}.`}))}catch(r){let s=r instanceof Error?r.message:String(r);console.error(O({level:"error",title:"Service Uninstall Failed",message:s})),process.exit(1)}break}case"start":case"stop":case"restart":case"enable":case"disable":{t||(console.error(O({level:"error",title:"Permission Denied",message:`Managing systemd service (${n}) requires elevated privileges.`,solutions:[`Run with sudo: sudo dns-worker service ${n}`]})),process.exit(1));try{Je(`systemctl ${n} ${mt}`,{stdio:"inherit"}),console.log(O({level:"success",title:"Service Action Executed",message:`systemctl ${n} ${mt}`}))}catch(r){let s=r instanceof Error?r.message:String(r);console.error(O({level:"error",title:`Service ${n} Failed`,message:s})),process.exit(1)}break}case"status":{try{Je(`systemctl status ${mt}`,{stdio:"inherit"})}catch{}break}case"logs":{try{Je(`journalctl -u ${mt} -f -n 50`,{stdio:"inherit"})}catch(r){let s=r instanceof Error?r.message:String(r);console.error(O({level:"error",title:"Service Logs Error",message:`journalctl exited: ${s}`}))}break}default:console.error(O({level:"error",title:"Service Command Error",message:`Unknown service action "${n}".`,solutions:["Supported actions: install, start, stop, restart, enable, disable, status, logs, uninstall","Example: sudo dns-worker service install"]})),process.exit(1)}}import un from"node:fs";import xo from"node:path";import{execSync as Ye}from"node:child_process";var me="DNS-Worker",Gr=xo.join(process.env.ProgramData||"C:\\ProgramData","DNS-Worker"),pn=xo.join(Gr,"service.log"),Vr=xo.join(Gr,"run-service.bat");function sp(n){return`@echo off\r
484
484
  setlocal\r
485
- cd /d "${t.workDir}"\r
486
- "${t.nodePath}" "${t.scriptPath}" >> "${an}" 2>&1\r
487
- `}async function Al(t){let e=Rl();switch(t){case"install":{e||(console.error(M({level:"error",title:"Permission Denied",message:"Registering a Windows background service (scheduled task) requires Administrator privileges.",solutions:['Please open PowerShell or Command Prompt as Administrator ("Run as Administrator").',"Then re-run: dns-worker service install"]})),process.exit(1));let n=Vn();try{on.existsSync(Mr)||on.mkdirSync(Mr,{recursive:!0});let r=bo.join(Mr,".env");lt(r,!1);let s=Gu(n);on.writeFileSync(Ur,s,"utf-8");let o=`schtasks /create /tn "${me}" /tr "\\"${Ur}\\"" /sc onstart /ru "SYSTEM" /rl HIGHEST /f`;Je(o,{stdio:"inherit"});try{Je(`schtasks /run /tn "${me}"`,{stdio:"inherit"})}catch{}let i=We({title:"DNS Worker Windows Service Installed & Started",borderChar:"=",bullet:"\u2022 ",items:[{label:"Task Name",value:me},{label:"Account",value:"NT AUTHORITY\\SYSTEM (Highest Privileges)"},{label:"Auto-Start",value:"On system startup (/sc onstart)"},{label:"Config File",value:r},{label:"Launcher Script",value:Ur},{label:"Log Output",value:an}]}),c=ro({title:"Useful Windows service management commands:",items:[{command:"dns-worker service status",desc:"View task status"},{command:"dns-worker service logs",desc:"View recent service logs"},{command:"dns-worker service restart",desc:"Restart background task"},{command:"dns-worker service enable",desc:"Enable background task"},{command:"dns-worker service disable",desc:"Disable background task"},{command:"dns-worker service stop",desc:"Stop background task"},{command:"dns-worker service uninstall",desc:"Remove background task"}]});console.log(`
485
+ cd /d "${n.workDir}"\r
486
+ "${n.nodePath}" "${n.scriptPath}" >> "${pn}" 2>&1\r
487
+ `}async function Ol(n){let e=Dl();switch(n){case"install":{e||(console.error(O({level:"error",title:"Permission Denied",message:"Registering a Windows background service (scheduled task) requires Administrator privileges.",solutions:['Please open PowerShell or Command Prompt as Administrator ("Run as Administrator").',"Then re-run: dns-worker service install"]})),process.exit(1));let t=Xn();try{un.existsSync(Gr)||un.mkdirSync(Gr,{recursive:!0});let r=xo.join(Gr,".env");Me(r,!1);let s=sp(t);un.writeFileSync(Vr,s,"utf-8");let o=`schtasks /create /tn "${me}" /tr "\\"${Vr}\\"" /sc onstart /ru "SYSTEM" /rl HIGHEST /f`;Ye(o,{stdio:"inherit"});try{Ye(`schtasks /run /tn "${me}"`,{stdio:"inherit"})}catch{}let i=Ce({title:"DNS Worker Windows Service Installed & Started",borderChar:"=",bullet:"\u2022 ",items:[{label:"Task Name",value:me},{label:"Account",value:"NT AUTHORITY\\SYSTEM (Highest Privileges)"},{label:"Auto-Start",value:"On system startup (/sc onstart)"},{label:"Config File",value:r},{label:"Launcher Script",value:Vr},{label:"Log Output",value:pn}]}),c=lo({title:"Useful Windows service management commands:",items:[{command:"dns-worker service status",desc:"View task status"},{command:"dns-worker service logs",desc:"View recent service logs"},{command:"dns-worker service restart",desc:"Restart background task"},{command:"dns-worker service enable",desc:"Enable background task"},{command:"dns-worker service disable",desc:"Disable background task"},{command:"dns-worker service stop",desc:"Stop background task"},{command:"dns-worker service uninstall",desc:"Remove background task"}]});console.log(`
488
488
  `+i+`
489
489
 
490
- `+c)}catch(r){let s=r instanceof Error?r.message:String(r);console.error(M({level:"error",title:"Windows Service Installation Failed",message:s,solutions:["Ensure you are running the terminal as Administrator.","Verify that the Windows Task Scheduler service is active."]})),process.exit(1)}break}case"uninstall":{e||(console.error(M({level:"error",title:"Permission Denied",message:"Removing a Windows background service requires Administrator privileges.",solutions:["Run in an Administrator terminal: dns-worker service uninstall"]})),process.exit(1));try{try{Je(`schtasks /end /tn "${me}"`,{stdio:"ignore"})}catch{}Je(`schtasks /delete /tn "${me}" /f`,{stdio:"inherit"}),on.existsSync(Ur)&&on.unlinkSync(Ur),console.log(M({level:"success",title:"Service Removed",message:`Windows background task "${me}" removed successfully.`}))}catch(n){let r=n instanceof Error?n.message:String(n);console.error(M({level:"error",title:"Windows Service Removal Failed",message:r})),process.exit(1)}break}case"start":{try{Je(`schtasks /run /tn "${me}"`,{stdio:"inherit"}),console.log(M({level:"success",title:"Service Started",message:`Started Windows background task: ${me}`}))}catch(n){let r=n instanceof Error?n.message:String(n);console.error(M({level:"error",title:"Task Start Failed",message:r,solutions:["Verify the task exists with 'dns-worker service status'.","Or reinstall with 'dns-worker service install' in Administrator terminal."]})),process.exit(1)}break}case"stop":{try{Je(`schtasks /end /tn "${me}"`,{stdio:"inherit"}),console.log(M({level:"success",title:"Service Stopped",message:`Stopped Windows background task: ${me}`}))}catch(n){let r=n instanceof Error?n.message:String(n);console.error(M({level:"error",title:"Task Stop Failed",message:r})),process.exit(1)}break}case"restart":{try{try{Je(`schtasks /end /tn "${me}"`,{stdio:"ignore"})}catch{}Je(`schtasks /run /tn "${me}"`,{stdio:"inherit"}),console.log(M({level:"success",title:"Service Restarted",message:`Restarted Windows background task: ${me}`}))}catch(n){let r=n instanceof Error?n.message:String(n);console.error(M({level:"error",title:"Task Restart Failed",message:r})),process.exit(1)}break}case"enable":{e||(console.error(M({level:"error",title:"Permission Denied",message:"Enabling a Windows background service requires Administrator privileges.",solutions:["Run in an Administrator terminal: dns-worker service enable"]})),process.exit(1));try{Je(`schtasks /change /tn "${me}" /enable`,{stdio:"inherit"}),console.log(M({level:"success",title:"Service Enabled",message:`Windows background task "${me}" enabled.`}))}catch(n){let r=n instanceof Error?n.message:String(n);console.error(M({level:"error",title:"Task Enable Failed",message:r,solutions:["Verify the task exists with 'dns-worker service status'.","Or reinstall with 'dns-worker service install' in Administrator terminal."]})),process.exit(1)}break}case"disable":{e||(console.error(M({level:"error",title:"Permission Denied",message:"Disabling a Windows background service requires Administrator privileges.",solutions:["Run in an Administrator terminal: dns-worker service disable"]})),process.exit(1));try{Je(`schtasks /change /tn "${me}" /disable`,{stdio:"inherit"}),console.log(M({level:"success",title:"Service Disabled",message:`Windows background task "${me}" disabled.`}))}catch(n){let r=n instanceof Error?n.message:String(n);console.error(M({level:"error",title:"Task Disable Failed",message:r})),process.exit(1)}break}case"status":{try{Je(`schtasks /query /tn "${me}" /fo LIST /v`,{stdio:"inherit"})}catch{console.log(M({level:"info",title:"Windows Task Status",message:`Task "${me}" is not currently registered in Windows Task Scheduler.`,solutions:['Run "dns-worker service install" in an Administrator terminal to register and run it.']}))}break}case"logs":{if(!on.existsSync(an)){console.log(M({level:"info",title:"Service Logs Notice",message:`No log file found at ${an} yet.`,details:["The background service has not produced any log output or has not been started yet."]}));return}try{let s=on.readFileSync(an,"utf-8").trim().split(/\r?\n/).slice(-50).join(`
491
- `);console.log(so({title:`Recent 50 Service Log Lines: ${an}`,content:s,borderChar:"-",tip:`In PowerShell, run: Get-Content "${an}" -Tail 50 -Wait`}))}catch(n){let r=n instanceof Error?n.message:String(n);console.error(M({level:"error",title:"Service Logs Error",message:`Error reading log file: ${r}`}))}break}default:console.error(M({level:"error",title:"Service Command Error",message:`Unknown service action "${t}".`,solutions:["Supported actions: install, start, stop, restart, enable, disable, status, logs, uninstall","Example: dns-worker service install"]})),process.exit(1)}}async function vl(t,e){if(process.platform==="win32")await Al(t);else if(process.platform==="linux")await xl(t,e);else{let n=Vn(),r=Oi(n);console.log(M({level:"info",title:"Platform Service Notice",message:`Automatic service management is supported on Linux (systemd) and Windows (schtasks). Current platform: ${process.platform}.`,details:["A systemd service unit template is provided below for manual reference:"]})),console.log(so({title:"systemd service unit template",content:r.trim(),borderChar:"-"}))}}function zu(){let[t,e]=process.versions.node.split(".").map(Number);(t<22||t===22&&e<5)&&(console.error(M({level:"error",title:"DNS Worker - Environment Error",message:`Node.js >= 22.5.0 is required (found v${process.versions.node}).`,solutions:["Please upgrade Node.js to version 22.5.0 or higher to use built-in SQLite (node:sqlite)."]})),process.exit(1))}function Qu(t,e){if(t==="path"){console.log(ut());return}if(t==="template"){process.stdout.write(So);return}if(t==="init"){let c=process.argv.includes("--force")||e==="--force",a=e&&e!=="--force"?Yu.resolve(e):ut(),l=lt(a,c);l.created?console.log(M({level:"success",title:c?"Configuration File Overwritten":"Configuration File Initialized",message:`Successfully wrote default .env configuration template to: ${l.path}`,solutions:["Edit this file to customize ports, TLS paths, and DNS settings.","Run 'dns-worker status' to verify loaded configuration."]})):console.log(M({level:"warning",title:"Configuration File Already Exists (Untouched)",message:`An existing configuration file was detected and preserved at: ${l.path}`,solutions:["Your existing settings and secrets remain completely intact.","Edit the existing file directly to modify options.","To view the new version's full template, run: dns-worker config template","To force overwrite with the latest default template, run: dns-worker config init --force"]}));return}Ro();let n=Gr(),r=n.length>0?n.join(`
492
- `):"None (Using built-in presets & defaults)",s=We({title:"DNS Worker Configuration Summary",borderChar:"=",bullet:"\u2022 "}),o=Ct({title:`
493
- Active Configuration Paths:`,items:[{label:"Persistent Data Dir",value:dt()},{label:"Config Directory",value:cn()},{label:"Default Config Path",value:ut()},{label:"Default SQLite Path",value:Vr()},{label:"Loaded Config Files",value:r}]}),i=Mn(["To generate a clean .env template file: dns-worker config init","To print the configuration file path: dns-worker config path","To view the raw template: dns-worker config template"]);console.log([s,o,i].join(`
494
- `))}function Zu(t){let{config:e}=Yr(t),n=e.echFrontingDomain||"cloudflare-ech.com",r=e.echConfig||zn(n),s=e.dotDomain||"dns.example.com",o=We({title:"Encrypted Client Hello (ECH) & DNS Service Records",borderChar:"=",bullet:"\u2022 "}),i=Ct({title:`
495
- Active ECH Configuration & Outer SNI:`,items:[{label:"ECH Status",value:e.echEnabled?"Enabled (Active)":"Disabled"},{label:"Fronting Domain (Outer SNI)",value:n},{label:"ECHConfigList (Base64)",value:r},{label:"Target Base Domain",value:s},{label:"HTTPS (H3) Port",value:String(e.httpsPort)},{label:"DoT / DoQ Port",value:String(e.dotPort)}]}),c=`_dns.${s}. 300 IN SVCB 1 . alpn="doq,dot" port=${e.dotPort} ech="${r}"`,a=`${s}. 300 IN HTTPS 1 . alpn="h3,h2" port=${e.httpsPort} ech="${r}"`,l=`
490
+ `+c)}catch(r){let s=r instanceof Error?r.message:String(r);console.error(O({level:"error",title:"Windows Service Installation Failed",message:s,solutions:["Ensure you are running the terminal as Administrator.","Verify that the Windows Task Scheduler service is active."]})),process.exit(1)}break}case"uninstall":{e||(console.error(O({level:"error",title:"Permission Denied",message:"Removing a Windows background service requires Administrator privileges.",solutions:["Run in an Administrator terminal: dns-worker service uninstall"]})),process.exit(1));try{try{Ye(`schtasks /end /tn "${me}"`,{stdio:"ignore"})}catch{}Ye(`schtasks /delete /tn "${me}" /f`,{stdio:"inherit"}),un.existsSync(Vr)&&un.unlinkSync(Vr),console.log(O({level:"success",title:"Service Removed",message:`Windows background task "${me}" removed successfully.`}))}catch(t){let r=t instanceof Error?t.message:String(t);console.error(O({level:"error",title:"Windows Service Removal Failed",message:r})),process.exit(1)}break}case"start":{try{Ye(`schtasks /run /tn "${me}"`,{stdio:"inherit"}),console.log(O({level:"success",title:"Service Started",message:`Started Windows background task: ${me}`}))}catch(t){let r=t instanceof Error?t.message:String(t);console.error(O({level:"error",title:"Task Start Failed",message:r,solutions:["Verify the task exists with 'dns-worker service status'.","Or reinstall with 'dns-worker service install' in Administrator terminal."]})),process.exit(1)}break}case"stop":{try{Ye(`schtasks /end /tn "${me}"`,{stdio:"inherit"}),console.log(O({level:"success",title:"Service Stopped",message:`Stopped Windows background task: ${me}`}))}catch(t){let r=t instanceof Error?t.message:String(t);console.error(O({level:"error",title:"Task Stop Failed",message:r})),process.exit(1)}break}case"restart":{try{try{Ye(`schtasks /end /tn "${me}"`,{stdio:"ignore"})}catch{}Ye(`schtasks /run /tn "${me}"`,{stdio:"inherit"}),console.log(O({level:"success",title:"Service Restarted",message:`Restarted Windows background task: ${me}`}))}catch(t){let r=t instanceof Error?t.message:String(t);console.error(O({level:"error",title:"Task Restart Failed",message:r})),process.exit(1)}break}case"enable":{e||(console.error(O({level:"error",title:"Permission Denied",message:"Enabling a Windows background service requires Administrator privileges.",solutions:["Run in an Administrator terminal: dns-worker service enable"]})),process.exit(1));try{Ye(`schtasks /change /tn "${me}" /enable`,{stdio:"inherit"}),console.log(O({level:"success",title:"Service Enabled",message:`Windows background task "${me}" enabled.`}))}catch(t){let r=t instanceof Error?t.message:String(t);console.error(O({level:"error",title:"Task Enable Failed",message:r,solutions:["Verify the task exists with 'dns-worker service status'.","Or reinstall with 'dns-worker service install' in Administrator terminal."]})),process.exit(1)}break}case"disable":{e||(console.error(O({level:"error",title:"Permission Denied",message:"Disabling a Windows background service requires Administrator privileges.",solutions:["Run in an Administrator terminal: dns-worker service disable"]})),process.exit(1));try{Ye(`schtasks /change /tn "${me}" /disable`,{stdio:"inherit"}),console.log(O({level:"success",title:"Service Disabled",message:`Windows background task "${me}" disabled.`}))}catch(t){let r=t instanceof Error?t.message:String(t);console.error(O({level:"error",title:"Task Disable Failed",message:r})),process.exit(1)}break}case"status":{try{Ye(`schtasks /query /tn "${me}" /fo LIST /v`,{stdio:"inherit"})}catch{console.log(O({level:"info",title:"Windows Task Status",message:`Task "${me}" is not currently registered in Windows Task Scheduler.`,solutions:['Run "dns-worker service install" in an Administrator terminal to register and run it.']}))}break}case"logs":{if(!un.existsSync(pn)){console.log(O({level:"info",title:"Service Logs Notice",message:`No log file found at ${pn} yet.`,details:["The background service has not produced any log output or has not been started yet."]}));return}try{let s=un.readFileSync(pn,"utf-8").trim().split(/\r?\n/).slice(-50).join(`
491
+ `);console.log(uo({title:`Recent 50 Service Log Lines: ${pn}`,content:s,borderChar:"-",tip:`In PowerShell, run: Get-Content "${pn}" -Tail 50 -Wait`}))}catch(t){let r=t instanceof Error?t.message:String(t);console.error(O({level:"error",title:"Service Logs Error",message:`Error reading log file: ${r}`}))}break}default:console.error(O({level:"error",title:"Service Command Error",message:`Unknown service action "${n}".`,solutions:["Supported actions: install, start, stop, restart, enable, disable, status, logs, uninstall","Example: dns-worker service install"]})),process.exit(1)}}async function Nl(n,e){if(process.platform==="win32")await Ol(n);else if(process.platform==="linux")await Ll(n,e);else{let t=Xn(),r=Hi(t);console.log(O({level:"info",title:"Platform Service Notice",message:`Automatic service management is supported on Linux (systemd) and Windows (schtasks). Current platform: ${process.platform}.`,details:["A systemd service unit template is provided below for manual reference:"]})),console.log(uo({title:"systemd service unit template",content:r.trim(),borderChar:"-"}))}}import Zn from"node:fs";import qn from"node:path";import op from"node:readline/promises";import{stdin as Il,stdout as ip}from"node:process";import{DatabaseSync as ap}from"node:sqlite";async function Ul(n={}){let e=Xe(),t=fn(),r=qn.join(process.cwd(),".env");if(!n.force){Il.isTTY||(console.error(O({level:"error",title:"DNS Worker - Confirmation Required",message:"The reset command wipes all database records and resets configuration files.",solutions:["In non-interactive environments, provide the --force or -y flag: dns-worker reset --force","Or run interactively in a terminal to confirm the operation."]})),process.exit(1));let i=Ce({title:"\u26A0\uFE0F CAUTION: FACTORY RESET (DATA DESTRUCTION)",borderChar:"!",bullet:"\u2022 "}),c=[{label:"Configuration File",value:e},{label:"SQLite Database",value:t}];Zn.existsSync(r)&&c.push({label:"Local .env File",value:r});let a=nt({title:`
492
+ Target Resources to be Reset:`,items:c});console.log([i,a,`
493
+ This operation will:`," 1. Overwrite configuration files with the factory default .env template."," 2. Permanently delete all query logs, user accounts, access points, and custom rules.",` 3. Recreate a clean database with fresh schema migrations.
494
+ `].join(`
495
+ `));let l=op.createInterface({input:Il,output:ip});try{let u=(await l.question("Are you sure you want to proceed with factory reset? (yes/no): ")).trim().toLowerCase();if(u!=="yes"&&u!=="y"){console.log(O({level:"info",title:"Operation Cancelled",message:"Factory reset cancelled by user. No files or database records were modified."}));return}}finally{l.close()}}let s=i=>{if(Zn.existsSync(i))try{let a=new ap(i);a.exec("PRAGMA foreign_keys = OFF;");let l=a.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'").all();for(let{name:d}of l)a.exec(`DROP TABLE IF EXISTS "${d}";`);a.exec("PRAGMA wal_checkpoint(TRUNCATE);"),a.exec("VACUUM;"),a.close()}catch(a){console.warn(`[Reset] Could not cleanly drop tables in ${i}:`,a)}let c=[i,`${i}-wal`,`${i}-shm`];for(let a of c)if(Zn.existsSync(a))try{Zn.unlinkSync(a)}catch{}};s(t);let o=qn.join(process.cwd(),"data","dns_worker.sqlite");Zn.existsSync(o)&&qn.resolve(o)!==qn.resolve(t)&&s(o),console.log("[Reset] Rebuilding fresh database schema..."),rs(t),Me(e,!0),Zn.existsSync(r)&&qn.resolve(r)!==qn.resolve(e)&&Me(r,!0),console.log(O({level:"success",title:"DNS Worker - Factory Reset Completed",message:"System configuration restored to default template and database re-initialized.",solutions:[`Default configuration written to: ${e}`,`Pristine database created at: ${t}`,"Run 'dns-worker status' to inspect system status.","Run 'dns-worker' to start the service."]}))}function dp(){let n=process.versions.bun;if(n){let[r,s]=n.split(".").map(Number);(r<1||r===1&&s<4)&&(console.error(O({level:"error",title:"DNS Worker - Environment Error",message:`Bun >= 1.4.0 is required for built-in node:sqlite support (found Bun v${n}).`,solutions:["Please upgrade Bun to version 1.4.0 or higher.","Alternatively, run with Node.js >= 22.5.0 (Recommended)."]})),process.exit(1));return}let[e,t]=process.versions.node.split(".").map(Number);(e<22||e===22&&t<5)&&(console.error(O({level:"error",title:"DNS Worker - Environment Error",message:`Node.js >= 22.5.0 is required (found v${process.versions.node}).`,solutions:["Please upgrade Node.js to version 22.5.0 or higher to use built-in SQLite (node:sqlite)."]})),process.exit(1))}function up(n,e){if(n==="path"){console.log(Xe());return}if(n==="template"){process.stdout.write(Po);return}if(n==="init"){let c=process.argv.includes("--force")||e==="--force",a=e&&e!=="--force"?cp.resolve(e):Xe(),l=Me(a,c);l.created?console.log(O({level:"success",title:c?"Configuration File Overwritten":"Configuration File Initialized",message:`Successfully wrote default .env configuration template to: ${l.path}`,solutions:["Edit this file to customize ports, TLS paths, and DNS settings.","Run 'dns-worker status' to verify loaded configuration."]})):console.log(O({level:"warning",title:"Configuration File Already Exists (Untouched)",message:`An existing configuration file was detected and preserved at: ${l.path}`,solutions:["Your existing settings and secrets remain completely intact.","Edit the existing file directly to modify options.","To view the new version's full template, run: dns-worker config template","To force overwrite with the latest default template, run: dns-worker config init --force"]}));return}Co();let t=ts(),r=t.length>0?t.join(`
496
+ `):"None (Using built-in presets & defaults)",s=Ce({title:"DNS Worker Configuration Summary",borderChar:"=",bullet:"\u2022 "}),o=nt({title:`
497
+ Active Configuration Paths:`,items:[{label:"Persistent Data Dir",value:ht()},{label:"Config Directory",value:mn()},{label:"Default Config Path",value:Xe()},{label:"Default SQLite Path",value:fn()},{label:"Loaded Config Files",value:r}]}),i=Wn(["To generate a clean .env template file: dns-worker config init","To print the configuration file path: dns-worker config path","To view the raw template: dns-worker config template"]);console.log([s,o,i].join(`
498
+ `))}function pp(n){let{config:e}=ns(n),t=e.echFrontingDomain||"cloudflare-ech.com",r=e.echConfig||rr(t),s=e.dotDomain||"dns.example.com",o=Ce({title:"Encrypted Client Hello (ECH) & DNS Service Records",borderChar:"=",bullet:"\u2022 "}),i=nt({title:`
499
+ Active ECH Configuration & Outer SNI:`,items:[{label:"ECH Status",value:e.echEnabled?"Enabled (Active)":"Disabled"},{label:"Fronting Domain (Outer SNI)",value:t},{label:"ECHConfigList (Base64)",value:r},{label:"Target Base Domain",value:s},{label:"HTTPS (H3) Port",value:String(e.httpsPort)},{label:"DoT / DoQ Port",value:String(e.dotPort)}]}),c=`_dns.${s}. 300 IN SVCB 1 . alpn="doq,dot" port=${e.dotPort} ech="${r}"`,a=`${s}. 300 IN HTTPS 1 . alpn="h3,h2" port=${e.httpsPort} ech="${r}"`,l=`
496
500
  Standard DNS Service Binding Records (RFC 9460 & RFC 9460 Section 8 DDR):
497
501
  \u2022 DDR SVCB Record (DoQ/DoT auto-discovery):
498
502
  ${c}
499
503
 
500
504
  \u2022 HTTPS Service Record (HTTP/3 & ECH):
501
- ${a}`,d=Mn(["Publish the DDR SVCB record in your authoritative DNS zone to enable automatic DoQ & DoT discovery.","Publish the HTTPS record to enable browser HTTP/3 (h3) and ECH negotiation without SNI leakage.",`Test client ECH support with: curl --ech true https://${s}`]);console.log([o,i,l,d].join(`
502
- `))}function Ni(){let t=jr(),e=Lc({name:`DNS Worker v${t} (Serverfull Mode)`,description:"Privacy-first DNS & DoH Resolver",usage:["dns-worker [options]","dns-worker status [options]","dns-worker ech [options]","dns-worker config [action]","dns-worker service <action>","npx dns-worker [options]"],commands:[{label:"status",desc:"Inspect service runtime status and database health"},{label:"ech",desc:"Display active ECH configuration, outer SNI, and DNS RR records"},{label:"config [action]",desc:"Manage configuration (show, path, init, template)"},{label:"service <action>",desc:"Manage background service (install, start, stop, restart, enable, disable, status, logs, uninstall)"}],options:[{label:"-s, --status",desc:"Display service and database runtime status"},{label:"-p, --port, --http-port <number>",desc:"Plain HTTP Web Dashboard & DoH port (default: 10080)"},{label:"--https-port <number>",desc:"Secure HTTPS Web Dashboard & DoH port (default: 10443)"},{label:"--disable-https",desc:"Disable HTTPS Web Dashboard server"},{label:"--dns-port <number>",desc:"Classic UDP DNS port (default: 53)"},{label:"--dot-port <number>",desc:"DoT (DNS over TLS) port (default: 853)"},{label:"--dot-domain <domain>",desc:"Base domain name for DoT & HTTPS service (e.g. dns.example.com)"},{label:"--ech-enabled <boolean>",desc:"Enable or disable ECH broadcast (true/false, default: true)"},{label:"--ech-config <base64>",desc:"Custom Base64-encoded ECHConfigList"},{label:"--ech-fronting-domain <domain>",desc:"ECH outer SNI fronting domain (default: cloudflare-ech.com)"},{label:"-h, --host <address>",desc:"Network address to bind (default: 0.0.0.0)"},{label:"--db <path>",desc:`SQLite database file path (default: ${Vr()})`},{label:"--default-profile <key>",desc:"Default Profile Key or Access Point Token for standard queries"},{label:"--disable-udp",desc:"Disable Classic UDP DNS server"},{label:"--disable-dot",desc:"Disable DoT server"},{label:"-u, --user <username>",desc:"User account to run background service as (default: current invoking user)"},{label:"-v, --version",desc:"Display version number"},{label:"--help",desc:"Display this help message"}],envVars:[{label:"PORT / HTTP_PORT / SERVERFULL_HTTP_PORT",desc:"Plain HTTP Web Dashboard & DoH port"},{label:"HTTPS_PORT / SERVERFULL_HTTPS_PORT",desc:"Secure HTTPS Web Dashboard & DoH port"},{label:"SERVERFULL_DISABLE_HTTPS",desc:"Disable HTTPS Web Dashboard server"},{label:"DNS_PORT / SERVERFULL_UDP_PORT",desc:"Classic UDP DNS port"},{label:"DOT_PORT / SERVERFULL_DOT_PORT",desc:"DoT port"},{label:"SERVERFULL_DOT_DOMAIN / DOT_DOMAIN",desc:"Base domain name for DoT & HTTPS service"},{label:"SERVERFULL_ECH_ENABLED",desc:"Enable or disable ECH (true/false)"},{label:"SERVERFULL_ECH_CONFIG",desc:"Custom Base64-encoded ECHConfigList"},{label:"SERVERFULL_ECH_FRONTING_DOMAIN",desc:"Fronting domain for ECH outer SNI"},{label:"DB_PATH / SERVERFULL_DB_PATH",desc:"SQLite database file path"},{label:"JWT_SECRET",desc:"JWT secret key (recommended >= 32 characters)"},{label:"SERVERFULL_TLS_KEY_PATH",desc:"Path to TLS private key for HTTPS & DoT"},{label:"SERVERFULL_TLS_CERT_PATH",desc:"Path to TLS certificate for HTTPS & DoT"}],tip:["Run 'dns-worker status' to inspect active runtime status, port availability, and database health.","Run 'dns-worker ech' to view active ECH configuration, outer SNI, and RFC 9460 DNS records.","Run 'dns-worker config init' to create an editable .env configuration file.",process.platform==="win32"?"Run 'dns-worker service install' (in Administrator terminal) to run as a persistent Windows background service.":"Run 'sudo dns-worker service install' to run as a persistent background Linux systemd service."]});console.log(e)}async function qu(){try{let{values:t,positionals:e}=Xu({options:{port:{type:"string",short:"p"},"http-port":{type:"string"},"https-port":{type:"string"},"disable-https":{type:"boolean"},"dns-port":{type:"string"},"dot-port":{type:"string"},"dot-domain":{type:"string"},host:{type:"string",short:"h"},db:{type:"string"},"default-profile":{type:"string"},"disable-udp":{type:"boolean"},"disable-dot":{type:"boolean"},"ech-enabled":{type:"boolean"},"ech-config":{type:"string"},"ech-fronting-domain":{type:"string"},user:{type:"string",short:"u"},status:{type:"boolean",short:"s"},help:{type:"boolean"},version:{type:"boolean",short:"v"}},allowPositionals:!0});if((t.help||e[0]?.toLowerCase()==="help")&&(Ni(),process.exit(0)),t.version&&(console.log(`dns-worker v${jr()}`),process.exit(0)),t.status||e[0]?.toLowerCase()==="status"){let{config:r,env:s}=Yr(t);await Sl(r,s.JWT_SECRET),process.exit(0)}if(e[0]?.toLowerCase()==="ech"&&(Zu(t),process.exit(0)),e[0]?.toLowerCase()==="config"){let r=e[1]?.toLowerCase()||"show",s=e[2];Qu(r,s),process.exit(0)}if(e[0]?.toLowerCase()==="service"){let r=e[1]?.toLowerCase()||"status",s=t.user;await vl(r,s),process.exit(0)}if(e[0]?.toLowerCase()==="postinstall"){try{let{dataDir:r,configFile:s}=Jr(!0);console.log(`[dns-worker] Initialized data directory: ${r}`),console.log(`[dns-worker] Initialized configuration file: ${s}`)}catch{}process.exit(0)}let n=process.platform==="win32"?"Run 'dns-worker service install' in Administrator terminal to install Windows service.":"Run 'sudo dns-worker service install' to install as a Linux systemd service.";return e.length>0&&(console.error(M({level:"error",title:"DNS Worker - CLI Argument Error",message:`Unrecognized command or argument "${e.join(" ")}".`,solutions:["Run 'dns-worker status' to view runtime status.",n,"Run 'dns-worker --help' to inspect supported options and usage."]})),Ni(),process.exit(1)),t}catch(t){let e=t instanceof Error?t.message:String(t),n=process.platform==="win32"?"Run 'dns-worker service install' in Administrator terminal to install Windows service.":"Run 'sudo dns-worker service install' to install as a Linux systemd service.";console.error(M({level:"error",title:"DNS Worker - CLI Argument Error",message:e,solutions:["Run 'dns-worker status' to view runtime status.",n,"Run 'dns-worker --help' to inspect supported options and usage."]})),Ni(),process.exit(1)}}async function ep(){zu();let t=await qu();console.log(We({title:`Initializing DNS Worker v${jr()} (Serverfull)`,borderChar:"-"})),Ui();let{config:e,env:n}=Yr(t),r=Bn(e.tlsCertPath,e.tlsKeyPath),s=r.configured&&r.filesExist&&!e.disableHttps,o=!e.disableDot&&r.configured&&r.filesExist&&r.isWildcard;r.configured?r.filesExist?r.isWildcard||console.log(M(Ti("non_wildcard",e.dotDomain))):console.log(M({level:"warning",title:"TLS Certificate Files Inaccessible",message:r.error||"Configured TLS certificate or private key files could not be read on disk.",details:[`Cert path configured: ${e.tlsCertPath?"yes":"no"}`,`Key path configured : ${e.tlsKeyPath?"yes":"no"}`,"Running user details are omitted for security."],solutions:["Check that the paths configured in .env exist and are accessible.","If using Let's Encrypt (/etc/letsencrypt/), grant read permissions to the service user (e.g. chmod 755 /etc/letsencrypt/{live,archive} and chmod 644 on keys)."]})):console.log(M(Ti("missing",e.dotDomain)));let i=e.disableHttps?"Disabled (--disable-https)":s?`https://${e.host}:${e.httpsPort}`:r.configured?`Disabled (Files Inaccessible: ${r.error||"Check Permissions"})`:"Disabled (TLS Certificates Not Configured)",c=e.disableDot?"Disabled (--disable-dot)":r.configured?r.filesExist?r.isWildcard?`tls://${e.host}:${e.dotPort}`:"Paused (Requires Wildcard Certificate *.domain)":`Disabled (Files Inaccessible: ${r.error||"Check Permissions"})`:"Disabled (TLS Certificates Not Configured)";console.log(Ct({title:"[Services] Configured Ports & Transports:",items:[{label:"Web Dashboard & DoH (HTTP)",value:`http://${e.host}:${e.httpPort}`},{label:"Web Dashboard & DoH (HTTPS)",value:i},{label:"Classic UDP DNS",value:e.disableUdp?"Disabled":`udp://${e.host}:${e.udpPort}`},{label:"DNS over TLS (DoT)",value:c}]})),ke(n.JWT_SECRET)&&!gt(n.JWT_SECRET)&&console.warn(M({level:"warning",title:"SECURITY WARNING",message:"JWT_SECRET is shorter than 32 characters.",solutions:["Please configure KEK_v1 in your environment before rotating JWT_SECRET to prevent existing encrypted credentials from becoming unrecoverable."]}));let a=Fi(e.dbPath);n.DB=a;let l=e.disableUdp?null:new oo({port:e.udpPort,host:e.host,defaultProfileKey:e.defaultProfileKey,env:n}),d=o?new co({port:e.dotPort,host:e.host,tlsKeyPath:e.tlsKeyPath,tlsCertPath:e.tlsCertPath,dotDomain:e.dotDomain,defaultProfileKey:e.defaultProfileKey,env:n}):null,u=new yo({port:e.httpPort,host:e.host,env:n}),f=s?new wo({port:e.httpsPort,host:e.host,certPath:e.tlsCertPath,keyPath:e.tlsKeyPath,env:n}):null;l&&await l.start(),d&&await d.start(),await u.start(),f&&await f.start();let p=setInterval(async()=>{try{let g={cron:"* * * * *",scheduledTime:Date.now(),type:"scheduled",noRetry(){}},w={waitUntil(b){b.catch(y=>console.error("[Cron Task Error]:",y))},passThroughOnException(){}};await ho.scheduled(g,n,w)}catch(g){console.error("[Cron Scheduler Error]:",g)}},6e4),m=!!(r.configured&&r.filesExist);console.log(We({title:"DNS Worker (Serverfull Mode) Started Successfully",borderChar:"=",bullet:"\u2022 ",items:[{label:"Classic UDP DNS",value:l?`udp://${e.host}:${e.udpPort}`:"Disabled (--disable-udp)"},{label:"DoT (TLS DNS)",value:d&&m?`tls://${e.dotDomain||e.host}:${e.dotPort}`:r.configured?r.filesExist?r.isWildcard?"Disabled":"Paused (Requires Wildcard Certificate *.domain)":`Disabled (Files Inaccessible: ${r.error||"Check Permissions"})`:"Disabled / Not Configured"},{label:"Web UI & DoH (HTTP)",value:`http://${e.host}:${e.httpPort}`},{label:"Web UI & DoH (HTTPS)",value:f?`https://${e.dotDomain||e.host}:${e.httpsPort}`:r.configured?r.filesExist?"Disabled":`Disabled (Files Inaccessible: ${r.error||"Check Permissions"})`:"Disabled / Not Configured"},{label:"SQLite Database",value:e.dbPath}]}));let h=async g=>{console.log(`
503
- [Serverfull] Received ${g}. Shutting down gracefully...`),clearInterval(p),await Promise.all([l?.stop(),d?.stop(),u.stop(),f?.stop()]);try{await Xs(n)}catch{}try{a.rawDb.close(),console.log("[Serverfull] Database connection closed.")}catch{}console.log("[Serverfull] All services stopped. Goodbye."),process.exit(0)};process.on("SIGINT",()=>h("SIGINT")),process.on("SIGTERM",()=>h("SIGTERM"))}ep().catch(t=>{let e=t?.code;if(e!=="EACCES"&&e!=="EADDRINUSE"){let n=t instanceof Error?t.message:String(t);console.error(M({level:"error",title:"Serverfull - Fatal Startup Error",message:n}))}process.exit(1)});
505
+ ${a}`,d=Wn(["Publish the DDR SVCB record in your authoritative DNS zone to enable automatic DoQ & DoT discovery.","Publish the HTTPS record to enable browser HTTP/3 (h3) and ECH negotiation without SNI leakage.",`Test client ECH support with: curl --ech true https://${s}`]);console.log([o,i,l,d].join(`
506
+ `))}function $i(){let n=qr(),e=Bc({name:`DNS Worker v${n} (Serverfull Mode)`,description:"Privacy-first DNS & DoH Resolver",usage:["dns-worker [options]","dns-worker status [options]","dns-worker ech [options]","dns-worker config [action]","dns-worker reset [options]","dns-worker service <action>","npx dns-worker [options]"],commands:[{label:"status",desc:"Inspect service runtime status and database health"},{label:"ech",desc:"Display active ECH configuration, outer SNI, and DNS RR records"},{label:"config [action]",desc:"Manage configuration (show, path, init, template)"},{label:"reset",desc:"Restore default .env configuration and wipe database (requires confirmation)"},{label:"service <action>",desc:"Manage background service (install, start, stop, restart, enable, disable, status, logs, uninstall)"}],options:[{label:"-s, --status",desc:"Display service and database runtime status"},{label:"-f, --force, -y, --yes",desc:"Bypass interactive confirmation prompt for reset command"},{label:"-p, --port, --http-port <number>",desc:"Plain HTTP Web Dashboard & DoH port (default: 10080)"},{label:"--https-port <number>",desc:"Secure HTTPS Web Dashboard & DoH port (default: 10443)"},{label:"--disable-https",desc:"Disable HTTPS Web Dashboard server"},{label:"--dns-port <number>",desc:"Classic UDP DNS port (default: 53)"},{label:"--dot-port <number>",desc:"DoT (DNS over TLS) port (default: 853)"},{label:"--dot-domain <domain>",desc:"Base domain name for DoT & HTTPS service (e.g. dns.example.com)"},{label:"--ech-enabled <boolean>",desc:"Enable or disable ECH broadcast (true/false, default: true)"},{label:"--ech-config <base64>",desc:"Custom Base64-encoded ECHConfigList"},{label:"--ech-fronting-domain <domain>",desc:"ECH outer SNI fronting domain (default: cloudflare-ech.com)"},{label:"-h, --host <address>",desc:"Network address to bind (default: 0.0.0.0)"},{label:"--db <path>",desc:`SQLite database file path (default: ${fn()})`},{label:"--default-profile <key>",desc:"Default Profile Key or Access Point Token for standard queries"},{label:"--disable-udp",desc:"Disable Classic UDP DNS server"},{label:"--disable-dot",desc:"Disable DoT server"},{label:"-u, --user <username>",desc:"User account to run background service as (default: current invoking user)"},{label:"-v, --version",desc:"Display version number"},{label:"--help",desc:"Display this help message"}],envVars:[{label:"PORT / HTTP_PORT / SERVERFULL_HTTP_PORT",desc:"Plain HTTP Web Dashboard & DoH port"},{label:"HTTPS_PORT / SERVERFULL_HTTPS_PORT",desc:"Secure HTTPS Web Dashboard & DoH port"},{label:"SERVERFULL_DISABLE_HTTPS",desc:"Disable HTTPS Web Dashboard server"},{label:"DNS_PORT / SERVERFULL_UDP_PORT",desc:"Classic UDP DNS port"},{label:"DOT_PORT / SERVERFULL_DOT_PORT",desc:"DoT port"},{label:"SERVERFULL_DOT_DOMAIN / DOT_DOMAIN",desc:"Base domain name for DoT & HTTPS service"},{label:"SERVERFULL_ECH_ENABLED",desc:"Enable or disable ECH (true/false)"},{label:"SERVERFULL_ECH_CONFIG",desc:"Custom Base64-encoded ECHConfigList"},{label:"SERVERFULL_ECH_FRONTING_DOMAIN",desc:"Fronting domain for ECH outer SNI"},{label:"DB_PATH / SERVERFULL_DB_PATH",desc:"SQLite database file path"},{label:"JWT_SECRET",desc:"JWT secret key (recommended >= 32 characters)"},{label:"SERVERFULL_TLS_KEY_PATH",desc:"Path to TLS private key for HTTPS & DoT"},{label:"SERVERFULL_TLS_CERT_PATH",desc:"Path to TLS certificate for HTTPS & DoT"}],tip:["Run 'dns-worker status' to inspect active runtime status, port availability, and database health.","Run 'dns-worker ech' to view active ECH configuration, outer SNI, and RFC 9460 DNS records.","Run 'dns-worker config init' to create an editable .env configuration file.",process.platform==="win32"?"Run 'dns-worker service install' (in Administrator terminal) to run as a persistent Windows background service.":"Run 'sudo dns-worker service install' to run as a persistent background Linux systemd service."]});console.log(e)}async function fp(){try{let{values:n,positionals:e}=lp({options:{port:{type:"string",short:"p"},"http-port":{type:"string"},"https-port":{type:"string"},"disable-https":{type:"boolean"},"dns-port":{type:"string"},"dot-port":{type:"string"},"dot-domain":{type:"string"},host:{type:"string",short:"h"},db:{type:"string"},"default-profile":{type:"string"},"disable-udp":{type:"boolean"},"disable-dot":{type:"boolean"},"ech-enabled":{type:"boolean"},"ech-config":{type:"string"},"ech-fronting-domain":{type:"string"},user:{type:"string",short:"u"},status:{type:"boolean",short:"s"},force:{type:"boolean",short:"f"},yes:{type:"boolean",short:"y"},help:{type:"boolean"},version:{type:"boolean",short:"v"}},allowPositionals:!0});if((n.help||e[0]?.toLowerCase()==="help")&&($i(),process.exit(0)),n.version&&(console.log(`dns-worker v${qr()}`),process.exit(0)),n.status||e[0]?.toLowerCase()==="status"){let{config:r,env:s}=ns(n);await Cl(r,s.JWT_SECRET),process.exit(0)}if(e[0]?.toLowerCase()==="reset"){let r=!!(n.force||n.yes||process.argv.includes("--force")||process.argv.includes("-f")||process.argv.includes("-y")||process.argv.includes("--yes"));await Ul({force:r}),process.exit(0)}if(e[0]?.toLowerCase()==="ech"&&(pp(n),process.exit(0)),e[0]?.toLowerCase()==="config"){let r=e[1]?.toLowerCase()||"show",s=e[2];up(r,s),process.exit(0)}if(e[0]?.toLowerCase()==="service"){let r=e[1]?.toLowerCase()||"status",s=n.user;await Nl(r,s),process.exit(0)}if(e[0]?.toLowerCase()==="postinstall"){try{let{dataDir:r,configFile:s}=es(!0);console.log(`[dns-worker] Initialized data directory: ${r}`),console.log(`[dns-worker] Initialized configuration file: ${s}`)}catch{}process.exit(0)}let t=process.platform==="win32"?"Run 'dns-worker service install' in Administrator terminal to install Windows service.":"Run 'sudo dns-worker service install' to install as a Linux systemd service.";return e.length>0&&(console.error(O({level:"error",title:"DNS Worker - CLI Argument Error",message:`Unrecognized command or argument "${e.join(" ")}".`,solutions:["Run 'dns-worker status' to view runtime status.",t,"Run 'dns-worker --help' to inspect supported options and usage."]})),$i(),process.exit(1)),n}catch(n){let e=n instanceof Error?n.message:String(n),t=process.platform==="win32"?"Run 'dns-worker service install' in Administrator terminal to install Windows service.":"Run 'sudo dns-worker service install' to install as a Linux systemd service.";console.error(O({level:"error",title:"DNS Worker - CLI Argument Error",message:e,solutions:["Run 'dns-worker status' to view runtime status.",t,"Run 'dns-worker --help' to inspect supported options and usage."]})),$i(),process.exit(1)}}async function mp(){dp();let n=await fp();console.log(Ce({title:`Initializing DNS Worker v${qr()} (Serverfull)`,borderChar:"-"})),Wi();let{config:e,env:t}=ns(n),r=jn(e.tlsCertPath,e.tlsKeyPath),s=r.configured&&r.filesExist&&!e.disableHttps,o=!e.disableDot&&r.configured&&r.filesExist&&r.isWildcard;r.configured?r.filesExist?r.isWildcard||console.log(O(Di("non_wildcard",e.dotDomain))):console.log(O({level:"warning",title:"TLS Certificate Files Inaccessible",message:r.error||"Configured TLS certificate or private key files could not be read on disk.",details:[`Cert path configured: ${e.tlsCertPath?"yes":"no"}`,`Key path configured : ${e.tlsKeyPath?"yes":"no"}`,"Running user details are omitted for security."],solutions:["Check that the paths configured in .env exist and are accessible.","If using Let's Encrypt (/etc/letsencrypt/), grant read permissions to the service user (e.g. chmod 755 /etc/letsencrypt/{live,archive} and chmod 644 on keys)."]})):console.log(O(Di("missing",e.dotDomain)));let i=e.disableHttps?"Disabled (--disable-https)":s?`https://${e.host}:${e.httpsPort}`:r.configured?`Disabled (Files Inaccessible: ${r.error||"Check Permissions"})`:"Disabled (TLS Certificates Not Configured)",c=e.disableDot?"Disabled (--disable-dot)":r.configured?r.filesExist?r.isWildcard?`tls://${e.host}:${e.dotPort}`:"Paused (Requires Wildcard Certificate *.domain)":`Disabled (Files Inaccessible: ${r.error||"Check Permissions"})`:"Disabled (TLS Certificates Not Configured)";console.log(nt({title:"[Services] Configured Ports & Transports:",items:[{label:"Web Dashboard & DoH (HTTP)",value:`http://${e.host}:${e.httpPort}`},{label:"Web Dashboard & DoH (HTTPS)",value:i},{label:"Classic UDP DNS",value:e.disableUdp?"Disabled":`udp://${e.host}:${e.udpPort}`},{label:"DNS over TLS (DoT)",value:c}]})),Oe(t.JWT_SECRET)&&!bt(t.JWT_SECRET)&&console.warn(O({level:"warning",title:"SECURITY WARNING",message:"JWT_SECRET is shorter than 32 characters.",solutions:["Please configure KEK_v1 in your environment before rotating JWT_SECRET to prevent existing encrypted credentials from becoming unrecoverable."]}));let a=rs(e.dbPath);t.DB=a;let l=e.disableUdp?null:new po({port:e.udpPort,host:e.host,defaultProfileKey:e.defaultProfileKey,env:t}),d=o?new ho({port:e.dotPort,host:e.host,tlsKeyPath:e.tlsKeyPath,tlsCertPath:e.tlsCertPath,dotDomain:e.dotDomain,defaultProfileKey:e.defaultProfileKey,env:t}):null,u=new Ro({port:e.httpPort,host:e.host,env:t}),f=s?new To({port:e.httpsPort,host:e.host,certPath:e.tlsCertPath,keyPath:e.tlsKeyPath,env:t}):null;l&&await l.start(),d&&await d.start(),await u.start(),f&&await f.start();let p=setInterval(async()=>{try{let g={cron:"* * * * *",scheduledTime:Date.now(),type:"scheduled",noRetry(){}},b={waitUntil(w){w.catch(y=>console.error("[Cron Task Error]:",y))},passThroughOnException(){}};await Eo.scheduled(g,t,b)}catch(g){console.error("[Cron Scheduler Error]:",g)}},6e4),m=!!(r.configured&&r.filesExist);console.log(Ce({title:"DNS Worker (Serverfull Mode) Started Successfully",borderChar:"=",bullet:"\u2022 ",items:[{label:"Classic UDP DNS",value:l?`udp://${e.host}:${e.udpPort}`:"Disabled (--disable-udp)"},{label:"DoT (TLS DNS)",value:d&&m?`tls://${e.dotDomain||e.host}:${e.dotPort}`:r.configured?r.filesExist?r.isWildcard?"Disabled":"Paused (Requires Wildcard Certificate *.domain)":`Disabled (Files Inaccessible: ${r.error||"Check Permissions"})`:"Disabled / Not Configured"},{label:"Web UI & DoH (HTTP)",value:`http://${e.host}:${e.httpPort}`},{label:"Web UI & DoH (HTTPS)",value:f?`https://${e.dotDomain||e.host}:${e.httpsPort}`:r.configured?r.filesExist?"Disabled":`Disabled (Files Inaccessible: ${r.error||"Check Permissions"})`:"Disabled / Not Configured"},{label:"SQLite Database",value:e.dbPath}]}));let h=async g=>{console.log(`
507
+ [Serverfull] Received ${g}. Shutting down gracefully...`),clearInterval(p),await Promise.all([l?.stop(),d?.stop(),u.stop(),f?.stop()]);try{await to(t)}catch{}try{a.rawDb.close(),console.log("[Serverfull] Database connection closed.")}catch{}console.log("[Serverfull] All services stopped. Goodbye."),process.exit(0)};process.on("SIGINT",()=>h("SIGINT")),process.on("SIGTERM",()=>h("SIGTERM"))}mp().catch(n=>{let e=n?.code;if(e!=="EACCES"&&e!=="EADDRINUSE"){let t=n instanceof Error?n.message:String(n);console.error(O({level:"error",title:"Serverfull - Fatal Startup Error",message:t}))}process.exit(1)});
504
508
  //# sourceMappingURL=serverfull.mjs.map