dns-worker 1.1.5 → 1.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +154 -155
- package/README.md +1 -3
- package/dist/serverfull.mjs +49 -49
- package/dist/serverfull.mjs.map +4 -4
- package/package.json +7 -3
- package/static/assets/AccountView-DIeqrGlp.js +4 -0
- package/static/assets/AnalyticsView-BzZ61m0y.js +2 -0
- package/static/assets/{DestinationMap-Bwv9zW4k.js → DestinationMap-DAk0zqdP.js} +1 -1
- package/static/assets/{FilteringView-hYm_mlJ0.js → FilteringView-CkcgGa7_.js} +1 -1
- package/static/assets/LogsView-Bb2JGWSY.js +5 -0
- package/static/assets/{RulesView-DLhxdWLq.js → RulesView-BKZXclmK.js} +1 -1
- package/static/assets/{SettingsView-VR3JolCU.js → SettingsView-BIUiIVIC.js} +1 -1
- package/static/assets/SetupView-MjSOUYm0.js +1 -0
- package/static/assets/{TrendChart-wcrIRt7R.js → TrendChart-CDyqUTCQ.js} +1 -1
- package/static/assets/date-D8IlsmbP.js +1 -0
- package/static/assets/de-DE-BXtoHcnB.js +12 -0
- package/static/assets/es-ES-HzsKZWQV.js +12 -0
- package/static/assets/fr-FR-cS1x6c9J.js +12 -0
- package/static/assets/index-BJJdTKLc.css +2 -0
- package/static/assets/index-C5rHE6WK.js +17 -0
- package/static/assets/ja-JP-Dxk2el-P.js +12 -0
- package/static/assets/ko-KR-Bj56Fs_D.js +12 -0
- package/static/assets/ru-RU-D1z3XQQZ.js +12 -0
- package/static/assets/{services-BYhiWUn8.js → services-B-OKDv75.js} +1 -1
- package/static/assets/useLogsE2ee-Crd_rHKZ.js +1 -0
- package/static/assets/vi-VN-YQQX1woE.js +12 -0
- package/static/assets/zh-CN-B0jDBZPP.js +12 -0
- package/static/assets/zh-TW-DOnIGWL3.js +12 -0
- package/static/index.html +2 -2
- package/static/sw.js +1 -1
- package/static/assets/AccountView-t2HnohwK.js +0 -4
- package/static/assets/AnalyticsView-DDNyezYl.js +0 -2
- package/static/assets/LogsView-BSRCO63V.js +0 -5
- package/static/assets/SetupView-BEaDE8T8.js +0 -1
- package/static/assets/date-DG8jTrEB.js +0 -1
- package/static/assets/de-DE-BiPVfS40.js +0 -12
- package/static/assets/es-ES-CM9mOh6j.js +0 -12
- package/static/assets/fr-FR-_-PAIgSj.js +0 -12
- package/static/assets/index-CrB_HdIL.js +0 -17
- package/static/assets/index-DZNm9qiP.css +0 -2
- package/static/assets/ja-JP-CYATQiqp.js +0 -12
- package/static/assets/ko-KR-DCPI1Twu.js +0 -12
- package/static/assets/ru-RU-D5bj5X0j.js +0 -12
- package/static/assets/vi-VN-D1YSdAMz.js +0 -12
- package/static/assets/zh-CN-Dhtte9ac.js +0 -12
- package/static/assets/zh-TW-CiUsmXXj.js +0 -12
- /package/static/assets/{SwipeableDrawer-DkPacJ1O.js → SwipeableDrawer-BrlOF_Xg.js} +0 -0
package/dist/serverfull.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
2
|
+
var Eu=Object.defineProperty;var Ze=(r,e,t)=>()=>{if(t)throw t[0];try{return r&&(e=r(r=0)),e}catch(n){throw t=[n],n}};var Fo=(r,e)=>{for(var t in e)Eu(r,t,{get:e[t],enumerable:!0})};var va,v,ge=Ze(()=>{"use strict";va="https://obex-dns.internal",v={setOrigin(r){r&&(r.startsWith("http://")||r.startsWith("https://"))&&(va=r.replace(/\/+$/,""))},generateCacheUrl(r){return`${va}/__cache__/${encodeURIComponent(r)}`},async get(r,e){if(!r)return null;let t=this.generateCacheUrl(e),n=await r.match(t);return n?n.json():null},async set(r,e,t,n,s=[]){if(!r)return;let o=this.generateCacheUrl(e),i={"Content-Type":"application/json","Cache-Control":`public, max-age=${n}`};s&&s.length>0&&(i["Cache-Tag"]=s.join(","));let c=new Response(JSON.stringify(t),{headers:i});return r.put(o,c)},async delete(r,e){if(!r)return!1;let t=this.generateCacheUrl(e);return r.delete(t)},async isRateLimited(r,e,t,n){if(!r)return!1;let s=`ratelimit:${e}`,o=await this.get(r,s),i=Math.floor(Date.now()/1e3);return!o||i>o.reset?(await this.set(r,s,{count:1,reset:i+n},n),!1):o.count>=t?!0:(await this.set(r,s,{count:o.count+1,reset:o.reset},Math.max(1,o.reset-i)),!1)}}});function Tr(r){let e=r.cf;if(e&&e.latitude&&e.longitude){let o=parseFloat(e.latitude),i=parseFloat(e.longitude);if(!isNaN(o)&&!isNaN(i))return{latitude:o,longitude:i}}let t=r.headers.get("CF-IPLatitude"),n=r.headers.get("CF-IPLongitude");if(t&&n){let o=parseFloat(t),i=parseFloat(n);if(!isNaN(o)&&!isNaN(i))return{latitude:o,longitude:i}}let s=r.headers.get("CF-Connecting-IP")||"";try{let o=new URL(r.url);if(o.hostname==="127.0.0.1"||o.hostname==="localhost"||s==="127.0.0.1"||s==="::1")return{latitude:null,longitude:null}}catch{}return{latitude:null,longitude:null}}function Ss(r,e,t,n){let o=(t-r)*Math.PI/180,i=(n-e)*Math.PI/180,c=Math.sin(o/2)*Math.sin(o/2)+Math.cos(r*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 ai=Ze(()=>{"use strict"});async function Ts(r,e,t,n=256){let o=new TextEncoder().encode(r),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,n);return new Uint8Array(c)}async function Bu(r,e,t=1e5,n=256){let s=e??crypto.getRandomValues(new Uint8Array(16)),o=await Ts(r,s,t,n);return Array.from(o).map(i=>i.toString(16).padStart(2,"0")).join("")}async function ct(r,e=1){let t=crypto.getRandomValues(new Uint8Array(16)),s=await Ts(r,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 Rr(r,e,t=1){let n=new Uint8Array(atob(e).split("").map(l=>l.charCodeAt(0))),s=n.slice(0,16),o=n.slice(16),c=await Ts(r,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 Wt(r=5){let e=new Uint8Array(r);crypto.getRandomValues(e);let t="";for(let n=0;n<r;n++)t+=ci[e[n]&31];return t}function j(r){let e=Math.ceil(r/2),t=new Uint8Array(e);return crypto.getRandomValues(t),Array.from(t).map(n=>n.toString(16).padStart(2,"0")).join("").slice(0,r)}function Rs(r){let t=new Uint8Array(atob(r).split("").map(n=>n.charCodeAt(0))).slice(0,16);return Array.from(t).map(n=>n.toString(16).padStart(2,"0")).join("")}async function xs(r,e){let t=new TextEncoder,n=typeof r=="string"?t.encode(r):r,s=typeof e=="string"?t.encode(e):e,o=await crypto.subtle.importKey("raw",n,{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 ee(r,e){let t=new TextEncoder().encode(e);return Bu(r,t,100,256)}async function Pa(r,e){let t=new TextEncoder().encode(e.toLowerCase()),n=await Ts(r,t,1e4,256);return Array.from(n).map(s=>s.toString(16).padStart(2,"0")).join("")}var ci,Se=Ze(()=>{"use strict";ci="ybndrfg8ejkmcpqxot1uwisza345h769"});function Et(r,e,t){let n;return t?n=(Number(e.OPTIONAL_SESSION_EXPIRATION_DAYS)||7)*24*60*60:n=(Number(e.DEFAULT_SESSION_EXPIRATION_MINUTES)||1440)*60,`${Sn}=${r}; HttpOnly; SameSite=Lax; Path=/; Max-Age=${n}; Secure`}function et(){return`${Sn}=; HttpOnly; SameSite=Lax; Path=/; Max-Age=0; Secure`}function Oe(r){if(!r)return null;let e=r.match(new RegExp(`(?:^|;\\s*)${Sn}=([^;]*)`));return e?e[1]:null}function lt(r,e,t){let n;return t&&e?n=(Number(e.OPTIONAL_SESSION_EXPIRATION_DAYS)||7)*24*60*60:n=(Number(e?.DEFAULT_SESSION_EXPIRATION_MINUTES)||1440)*60,`csrf_token=${r}; SameSite=Lax; Path=/; Max-Age=${n}; Secure`}function xr(r){if(!r)return null;let e=r.match(/(?:^|;\s*)csrf_token=([^;]*)/);return e?e[1]:null}function As(r,e){let t=Number(e.PREAUTH_TTL_SECONDS)||300;return`${Tn}=${r}; HttpOnly; SameSite=Lax; Path=/; Max-Age=${t}; Secure`}function Ds(){return`${Tn}=; HttpOnly; SameSite=Lax; Path=/; Max-Age=0; Secure`}function vs(r){if(!r)return null;let e=r.match(new RegExp(`(?:^|;\\s*)${Tn}=([^;]*)`));return e?e[1]:null}var Sn,Tn,Ca=Ze(()=>{"use strict";Sn="auth_refresh",Tn="preauth_session"});var Rn={};Fo(Rn,{SessionModel:()=>ae});var ae,He=Ze(()=>{"use strict";ae=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
|
|
@@ -10,21 +10,21 @@ var _u=Object.defineProperty;var Qe=(r,e,t)=>()=>{if(t)throw t[0];try{return r&&
|
|
|
10
10
|
FROM sessions
|
|
11
11
|
WHERE user_id = ? AND expires_at > ?
|
|
12
12
|
ORDER BY expires_at DESC
|
|
13
|
-
`).bind(e,t).all();return n}async deleteExpiredSessions(e=Math.floor(Date.now()/1e3)){let t=await this.db.prepare("DELETE FROM sessions WHERE expires_at <= ?").bind(e).run(),n=await this.db.prepare("DELETE FROM pending_totp_sessions WHERE expires_at <= ?").bind(e).run();return{deletedSessions:t.meta?.changes||0,deletedPending:n.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,n){return(await this.db.prepare("INSERT INTO pending_totp_sessions (id, user_id, expires_at) VALUES (?, ?, ?)").bind(e,t,n).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 xn(r){let e="";if(typeof r=="string")e=r;else{let t=new Uint8Array(r);for(let n=0;n<t.byteLength;n++)e+=String.fromCharCode(t[n])}return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function Ps(r){let e=r.replace(/-/g,"+").replace(/_/g,"/");for(;e.length%4;)e+="=";let t=atob(e),n=new Uint8Array(t.length);for(let s=0;s<t.length;s++)n[s]=t.charCodeAt(s);return n}function ka(r){return new TextEncoder().encode(r)}function di(r){return typeof r!="string"?!0:r.trim().length===0}function pi(r){return typeof r!="string"?!1:Hu.has(r.trim())}function Ar(r){return di(r)?"missing":pi(r)?"preset":"valid"}function Oe(r){return Ar(r)==="valid"}function _t(r){return Oe(r)?r.trim().length>=ui:!1}async function Ne(r){let e=new TextEncoder().encode(`${r}:${$u}`),t=await crypto.subtle.digest("SHA-256",e);return crypto.subtle.importKey("raw",t,{name:"HMAC",hash:"SHA-512"},!1,["sign","verify"])}async function Dr(r,e){let n=xn(JSON.stringify({alg:"HS512",typ:"JWT"})),s=xn(JSON.stringify(r)),o=`${n}.${s}`,i=await crypto.subtle.sign("HMAC",e,ka(o)),c=xn(i);return`${o}.${c}`}async function vr(r,e){let t=r.split(".");if(t.length!==3)return null;let[n,s,o]=t,i=`${n}.${s}`,c=Ps(o);if(!await crypto.subtle.verify("HMAC",e,c,ka(i)))return null;try{let l=Ps(s),u=new TextDecoder().decode(l),d=JSON.parse(u);return d.exp&&Math.floor(Date.now()/1e3)>d.exp?null:d}catch{return null}}var ui,Hu,$u,He=Qe(()=>{"use strict";ui=32,Hu=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"]);$u="DNS_WORKER_JWT_KEY_SALT_v1"});function An(r,e){let t={sid:r,v:e,ts:Date.now()};return xn(JSON.stringify(t))}function ve(r){try{let e=new TextDecoder().decode(Ps(r));return JSON.parse(e)}catch{return null}}async function Pr(r,e,t=null,n=null,s=null,o=null,i){let a=(i?"k_":"s_")+j(Dn-2),l=Math.floor(Date.now()/1e3),u;if(i){let m=Number(r.OPTIONAL_SESSION_EXPIRATION_DAYS)||7;u=l+m*24*60*60}else{let m=Number(r.DEFAULT_SESSION_EXPIRATION_MINUTES)||1440;u=l+m*60}let d={id:a,user_id:e,created_at:l,expires_at:u,ip_address:t,user_agent:n,latitude:s,longitude:o,last_active_at:l};await new ae(r.DB).createSession(d.id,d.user_id,d.created_at,d.expires_at,d.ip_address,d.user_agent,d.latitude,d.longitude,d.last_active_at);let f=An(d.id,0);return{session:d,refreshToken:f}}async function Cs(r,e,t=null,n=null){let s=ve(e);if(!s)return{session:null,user:null,newRefreshToken:null,reason:"invalid_token"};let o=new ae(r.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 St(r,c.id),{session:null,user:a,newRefreshToken:null,reason:"expired"};let u=c.rotation_counter===s.v,d=c.rotation_counter!==void 0&&s.v===c.rotation_counter-1,p=c.last_active_at||c.created_at,f=15;if(!u){if(d&&l-p<=f){let S=An(c.id,c.rotation_counter||1);return{session:c,user:a,newRefreshToken:S}}return await St(r,c.id),{session:null,user:a,newRefreshToken:null,reason:"token_reuse"}}let m=r.SERVERFULL_DEFAULT_PROFILE_KEY!==void 0||r.SERVERFULL_HOST!==void 0||r.SERVERFULL_DOT_DOMAIN!==void 0||r.SERVERFULL_HTTP_PORT!==void 0||r.SERVERFULL_HTTPS_PORT!==void 0,h=c.latitude===0&&c.longitude===0||t===0&&n===0;if(!m&&!h){if(c.latitude===null||c.latitude===void 0||c.longitude===null||c.longitude===void 0||t===null||n===null)return await St(r,c.id),{session:null,user:a,newRefreshToken:null,reason:"geolocation_missing"};let S=Ss(c.latitude,c.longitude,t,n),x=Number(r.SESSION_GEO_DISTANCE_KM)||50;if(S>x)return await St(r,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-p>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(r.OPTIONAL_SESSION_EXPIRATION_DAYS)||7)*24*60*60:(Number(r.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,_=An(c.id,E);return{session:c,user:a,newRefreshToken:_}}async function St(r,e){await new ae(r.DB).deleteSession(e)}var Dn,fi=Qe(()=>{"use strict";Fe();Se();He();ci();Dn=80});async function ks(r,e){let t=j(Dn),n=Number(r.PREAUTH_TTL_SECONDS)||300,s=Math.floor(Date.now()/1e3)+n;return await new ae(r.DB).createPendingTotpSession(t,e,s),t}async function Ls(r,e){let t=new ae(r.DB),n=await t.getPendingTotpSession(e);return n?Math.floor(Date.now()/1e3)>=n.expires_at?(await t.deletePendingTotpSession(e),null):n.user_id:null}async function vn(r,e){await new ae(r.DB).deletePendingTotpSession(e)}async function et(r,e,t){let n=`preauth_state:${e}`,s=await v.get(r,n);if(!s)return 0;let o=(s.failedAttempts||0)+1;if(o>=3)return await new ae(t.DB).deletePendingTotpSession(e),await v.delete(r,n),0;let i=Number(t.PREAUTH_TTL_SECONDS)||300;return await v.set(r,n,{...s,failedAttempts:o},i),3-o}var La=Qe(()=>{"use strict";Fe();Se();fi();ge()});var Pn={};Ho(Pn,{MIN_JWT_SECRET_LENGTH:()=>ui,PREAUTH_COOKIE_NAME:()=>Tn,REFRESH_TOKEN_COOKIE_NAME:()=>Sn,SESSION_ID_LENGTH:()=>Dn,ZBASE32_ALPHABET:()=>li,calculateDistanceInKm:()=>Ss,clearPreauthCookie:()=>Ds,createBlankRefreshTokenCookie:()=>qe,createCsrfCookie:()=>ct,createPreauthCookie:()=>As,createPreauthSession:()=>ks,createRefreshTokenCookie:()=>Et,createRefreshTokenString:()=>An,createSession:()=>Pr,extractSaltHex:()=>Rs,generateId:()=>j,generateSessionHash:()=>ee,generateZBase32Token:()=>Wt,getJwtSecretStatus:()=>Ar,getOrCreateJwtSecret:()=>$e,getRequestCoordinates:()=>Rr,hmacSha256:()=>xs,invalidatePreauthSession:()=>vn,invalidateSession:()=>St,isMissingJwtSecret:()=>di,isPresetJwtSecret:()=>pi,isStrongJwtSecret:()=>_t,isUsableJwtSecret:()=>Oe,parseRefreshTokenString:()=>ve,readCsrfCookie:()=>xr,readPreauthCookie:()=>vs,readRefreshTokenCookie:()=>Le,recordFailedPreauthAttempt:()=>et,rotateSession:()=>Cs,validatePreauthSession:()=>Ls});async function $e(r){let e=Ar(r.JWT_SECRET);if(e==="missing")throw new Error("jwt_secret_missing");if(e==="preset")throw new Error("jwt_secret_preset");return r.JWT_SECRET}var pe=Qe(()=>{"use strict";ci();Se();Ca();fi();La();He()});var yl={};Ho(yl,{applySecurityHeaders:()=>ea,getCurrentUser:()=>ta,invalidateAuthUserCache:()=>Xr,validateCsrf:()=>ra});function ea(r,e){let t=new Headers(r.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(r.body,{status:r.status,statusText:r.statusText,headers:t})}function Xr(r){cr.delete(r),Nt.delete(r)}async function ta(r,e,t){let n=r.headers.get("Authorization")||"",s="";if(n.startsWith("Bearer "))s=n.slice(7);else if(r.headers.get("Upgrade")?.toLowerCase().includes("websocket")||new URL(r.url).pathname.endsWith("/ws")){let o=new URL(r.url);s=o.searchParams.get("token")||o.searchParams.get("access_token")||""}if(!s)return null;try{let o=await $e(e),i=await Ne(o),c=await vr(s,i);if(c){let a=cr.get(c.sessionId);if(a&&a.expiresAt>Date.now()){let _=Nt.get(c.sessionId);return _&&(_.lastObserved=Math.floor(Date.now()/1e3)),a.user}let l=new ae(e.DB),u=await l.getSessionWithUser(c.sessionId);if(!u)return cr.delete(c.sessionId),Nt.delete(c.sessionId),null;let d=u.id||u.session_id||c.sessionId,p=Math.floor(Date.now()/1e3),f=u.last_active_at||u.created_at,m=Nt.get(c.sessionId),h=Math.max(f,m?.lastObserved??0);if(u.pin_hash&&!u.is_paused){let _=(u.session_lock_timeout||15)*60;if(p-h>_){try{await l.pauseSession(d)}catch(S){console.error("[Auth] Failed to update pauseSession in D1:",S)}u.is_paused=1}}if(u.is_paused)return{id:c.userId,username:u.username||"",role:u.role||c.role,isPaused:!0,sessionId:c.sessionId};let g=m?.lastWriteAttempt??f,b=parseInt(String(e.SESSION_LAST_ACTIVE_UPDATE_INTERVAL||"60"),10)||60,w=g;if(p-g>b){w=p;let _=l.updateLastActive(d,p).catch(S=>console.error("[Auth] session last-active write failed:",S));t&&typeof t.waitUntil=="function"&&t.waitUntil(_)}if(Nt.size>1e3){let _=Nt.keys().next().value;_&&Nt.delete(_)}Nt.set(c.sessionId,{lastObserved:p,lastWriteAttempt:w});let y={id:c.userId,username:u.username||"",role:u.role||c.role,sessionId:c.sessionId},E=parseInt(String(e.AUTH_CACHE_TTL_SEC||"30"),10)||30;if(cr.size>100){let _=cr.keys().next().value;_&&cr.delete(_)}return cr.set(c.sessionId,{user:y,expiresAt:Date.now()+E*1e3}),y}}catch{}return null}function ra(r){let e=r.headers.get("Cookie")||"",t=xr(e),n=r.headers.get("X-CSRF-Token");return!!t&&!!n&&t===n}var cr,Nt,Zn=Qe(()=>{"use strict";pe();He();Fe();cr=new Map,Nt=new Map});import Jp from"node:path";var os=class{store=new Map;maxEntries;constructor(e=5e3){this.maxEntries=e}async match(e){let t=typeof e=="string"?e:e.url,n=this.store.get(t);if(n){if(Date.now()>n.expires){this.store.delete(t);return}return this.store.delete(t),this.store.set(t,n),new Response(n.body,{status:n.status,statusText:n.statusText,headers:new Headers(n.headers)})}}async put(e,t){let n=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(),a=Date.now();if(!this.store.has(n)&&this.store.size>=this.maxEntries){for(let[l,u]of this.store)a>u.expires&&this.store.delete(l);for(;this.store.size>=this.maxEntries;){let l=this.store.keys().next().value;if(l===void 0)break;this.store.delete(l)}}this.store.delete(n),this.store.set(n,{body:new Uint8Array(c),headers:new Headers(t.headers),status:t.status,statusText:t.statusText,expires:a+i*1e3})}async delete(e){let t=typeof e=="string"?e:e.url;return this.store.delete(t)}};function da(){if(typeof globalThis.caches>"u"){let r=new os;globalThis.caches={default:r,open:async()=>new os}}typeof globalThis.HTMLRewriter>"u"&&(globalThis.HTMLRewriter=class{handlers=[];on(r,e){return e.element&&this.handlers.push({selector:r,fn:e.element}),this}transform(r){let e=this.handlers,t=r.text(),n=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(r.headers);return s.delete("content-length"),new Response(n,{status:r.status,statusText:r.statusText,headers:s})}})}import _a from"node:fs";var is=[{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"}],as=[{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"}],on="www.okx.com",De="https://freedns.controld.com/no-ads-malware-typo";import{Buffer as $o}from"node:buffer";function Ko(r){return r==null?{type:"null"}:typeof r=="boolean"?{type:"integer",value:r?"1":"0"}:typeof r=="number"?Number.isInteger(r)?{type:"integer",value:String(r)}:{type:"float",value:r}:typeof r=="bigint"?{type:"integer",value:r.toString()}:typeof r=="string"?{type:"text",value:r}:r instanceof ArrayBuffer?{type:"blob",base64:$o.from(r).toString("base64")}:ArrayBuffer.isView(r)?{type:"blob",base64:$o.from(r.buffer,r.byteOffset,r.byteLength).toString("base64")}:{type:"text",value:String(r)}}function cs(r){if(!r||r.type==="null")return null;if(r.type==="integer"){let e=Number(r.value);return Number.isSafeInteger(e)?e:BigInt(r.value)}if(r.type==="float")return Number(r.value);if(r.type==="text")return r.value;if(r.type==="blob"){let e=r.base64||r.value||"",t=$o.from(e,"base64"),n=new ArrayBuffer(t.length);return new Uint8Array(n).set(t),n}return r.value??r}function Wo(r){let e=r.trim();return e.startsWith("libsql://")?e="https://"+e.slice(9):!e.startsWith("http://")&&!e.startsWith("https://")&&(e="https://"+e),e.replace(/\/+$/,"")}function an(r){try{let e=Wo(r),t=new URL(e);return`${t.protocol}//${t.host}`}catch{return r.slice(0,16)+"..."}}function hr(r){if(!r)return!1;let e=(r.TURSO_DATABASE_URL||r.TURSO_URL)?.trim(),t=r.TURSO_AUTH_TOKEN?.trim();return!!(e&&t)}function cn(r,e=!1){let t=(r?.DATABASE_SERVICE||r?.DB_SERVICE)?.trim().toLowerCase();return t==="turso"?"Turso":t==="d1"?"D1":t==="file"?"File":hr(r)?"Turso":e?"File":"D1"}function pa(r){let e=[],t="",n=!1,s=!1,o=!1;for(let c=0;c<r.length;c++){let a=r[c],l=r[c+1];if(s){a===`
|
|
14
|
-
`&&(s=!1);continue}if(o){a==="*"&&l==="/"&&(o=!1,c++);continue}if(n){t+=a,a===n&&(l===n?(t+=l,c++):n=!1);continue}if(a==="-"&&l==="-"){s=!0,c++;continue}if(a==="/"&&l==="*"){o=!0,c++;continue}if(a==="'"||a==='"'){n=a,t+=a;continue}if(a===";"){let u=t.trim();u&&e.push(u),t="";continue}t+=a}let i=t.trim();return i&&e.push(i),e}var
|
|
13
|
+
`).bind(e,t).all();return n}async deleteExpiredSessions(e=Math.floor(Date.now()/1e3)){let t=await this.db.prepare("DELETE FROM sessions WHERE expires_at <= ?").bind(e).run(),n=await this.db.prepare("DELETE FROM pending_totp_sessions WHERE expires_at <= ?").bind(e).run();return{deletedSessions:t.meta?.changes||0,deletedPending:n.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,n){return(await this.db.prepare("INSERT INTO pending_totp_sessions (id, user_id, expires_at) VALUES (?, ?, ?)").bind(e,t,n).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 xn(r){let e="";if(typeof r=="string")e=r;else{let t=new Uint8Array(r);for(let n=0;n<t.byteLength;n++)e+=String.fromCharCode(t[n])}return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function Ps(r){let e=r.replace(/-/g,"+").replace(/_/g,"/");for(;e.length%4;)e+="=";let t=atob(e),n=new Uint8Array(t.length);for(let s=0;s<t.length;s++)n[s]=t.charCodeAt(s);return n}function ka(r){return new TextEncoder().encode(r)}function ui(r){return typeof r!="string"?!0:r.trim().length===0}function di(r){return typeof r!="string"?!1:Fu.has(r.trim())}function Ar(r){return ui(r)?"missing":di(r)?"preset":"valid"}function Ne(r){return Ar(r)==="valid"}function _t(r){return Ne(r)?r.trim().length>=li:!1}async function Ie(r){let e=new TextEncoder().encode(`${r}:${Hu}`),t=await crypto.subtle.digest("SHA-256",e);return crypto.subtle.importKey("raw",t,{name:"HMAC",hash:"SHA-512"},!1,["sign","verify"])}async function Dr(r,e){let n=xn(JSON.stringify({alg:"HS512",typ:"JWT"})),s=xn(JSON.stringify(r)),o=`${n}.${s}`,i=await crypto.subtle.sign("HMAC",e,ka(o)),c=xn(i);return`${o}.${c}`}async function vr(r,e){let t=r.split(".");if(t.length!==3)return null;let[n,s,o]=t,i=`${n}.${s}`,c=Ps(o);if(!await crypto.subtle.verify("HMAC",e,c,ka(i)))return null;try{let l=Ps(s),u=new TextDecoder().decode(l),d=JSON.parse(u);return d.exp&&Math.floor(Date.now()/1e3)>d.exp?null:d}catch{return null}}var li,Fu,Hu,$e=Ze(()=>{"use strict";li=32,Fu=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"]);Hu="DNS_WORKER_JWT_KEY_SALT_v1"});function An(r,e){let t={sid:r,v:e,ts:Date.now()};return xn(JSON.stringify(t))}function ve(r){try{let e=new TextDecoder().decode(Ps(r));return JSON.parse(e)}catch{return null}}async function Pr(r,e,t=null,n=null,s=null,o=null,i){let a=(i?"k_":"s_")+j(Dn-2),l=Math.floor(Date.now()/1e3),u;if(i){let m=Number(r.OPTIONAL_SESSION_EXPIRATION_DAYS)||7;u=l+m*24*60*60}else{let m=Number(r.DEFAULT_SESSION_EXPIRATION_MINUTES)||1440;u=l+m*60}let d={id:a,user_id:e,created_at:l,expires_at:u,ip_address:t,user_agent:n,latitude:s,longitude:o,last_active_at:l};await new ae(r.DB).createSession(d.id,d.user_id,d.created_at,d.expires_at,d.ip_address,d.user_agent,d.latitude,d.longitude,d.last_active_at);let f=An(d.id,0);return{session:d,refreshToken:f}}async function Cs(r,e,t=null,n=null){let s=ve(e);if(!s)return{session:null,user:null,newRefreshToken:null,reason:"invalid_token"};let o=new ae(r.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 St(r,c.id),{session:null,user:a,newRefreshToken:null,reason:"expired"};let u=c.rotation_counter===s.v,d=c.rotation_counter!==void 0&&s.v===c.rotation_counter-1,p=c.last_active_at||c.created_at,f=15;if(!u){if(d&&l-p<=f){let S=An(c.id,c.rotation_counter||1);return{session:c,user:a,newRefreshToken:S}}return await St(r,c.id),{session:null,user:a,newRefreshToken:null,reason:"token_reuse"}}let m=r.SERVERFULL_DEFAULT_PROFILE_KEY!==void 0||r.SERVERFULL_HOST!==void 0||r.SERVERFULL_DOT_DOMAIN!==void 0||r.SERVERFULL_HTTP_PORT!==void 0||r.SERVERFULL_HTTPS_PORT!==void 0,h=c.latitude===0&&c.longitude===0||t===0&&n===0;if(!m&&!h){if(c.latitude===null||c.latitude===void 0||c.longitude===null||c.longitude===void 0||t===null||n===null)return await St(r,c.id),{session:null,user:a,newRefreshToken:null,reason:"geolocation_missing"};let S=Ss(c.latitude,c.longitude,t,n),x=Number(r.SESSION_GEO_DISTANCE_KM)||50;if(S>x)return await St(r,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-p>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(r.OPTIONAL_SESSION_EXPIRATION_DAYS)||7)*24*60*60:(Number(r.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,_=An(c.id,E);return{session:c,user:a,newRefreshToken:_}}async function St(r,e){await new ae(r.DB).deleteSession(e)}var Dn,pi=Ze(()=>{"use strict";He();Se();$e();ai();Dn=80});async function ks(r,e){let t=j(Dn),n=Number(r.PREAUTH_TTL_SECONDS)||300,s=Math.floor(Date.now()/1e3)+n;return await new ae(r.DB).createPendingTotpSession(t,e,s),t}async function Ls(r,e){let t=new ae(r.DB),n=await t.getPendingTotpSession(e);return n?Math.floor(Date.now()/1e3)>=n.expires_at?(await t.deletePendingTotpSession(e),null):n.user_id:null}async function vn(r,e){await new ae(r.DB).deletePendingTotpSession(e)}async function tt(r,e,t){let n=`preauth_state:${e}`,s=await v.get(r,n);if(!s)return 0;let o=(s.failedAttempts||0)+1;if(o>=3)return await new ae(t.DB).deletePendingTotpSession(e),await v.delete(r,n),0;let i=Number(t.PREAUTH_TTL_SECONDS)||300;return await v.set(r,n,{...s,failedAttempts:o},i),3-o}var La=Ze(()=>{"use strict";He();Se();pi();ge()});var Pn={};Fo(Pn,{MIN_JWT_SECRET_LENGTH:()=>li,PREAUTH_COOKIE_NAME:()=>Tn,REFRESH_TOKEN_COOKIE_NAME:()=>Sn,SESSION_ID_LENGTH:()=>Dn,ZBASE32_ALPHABET:()=>ci,calculateDistanceInKm:()=>Ss,clearPreauthCookie:()=>Ds,createBlankRefreshTokenCookie:()=>et,createCsrfCookie:()=>lt,createPreauthCookie:()=>As,createPreauthSession:()=>ks,createRefreshTokenCookie:()=>Et,createRefreshTokenString:()=>An,createSession:()=>Pr,extractSaltHex:()=>Rs,generateId:()=>j,generateSessionHash:()=>ee,generateZBase32Token:()=>Wt,getJwtSecretStatus:()=>Ar,getOrCreateJwtSecret:()=>Ke,getRequestCoordinates:()=>Tr,hmacSha256:()=>xs,invalidatePreauthSession:()=>vn,invalidateSession:()=>St,isMissingJwtSecret:()=>ui,isPresetJwtSecret:()=>di,isStrongJwtSecret:()=>_t,isUsableJwtSecret:()=>Ne,parseRefreshTokenString:()=>ve,readCsrfCookie:()=>xr,readPreauthCookie:()=>vs,readRefreshTokenCookie:()=>Oe,recordFailedPreauthAttempt:()=>tt,rotateSession:()=>Cs,validatePreauthSession:()=>Ls});async function Ke(r){let e=Ar(r.JWT_SECRET);if(e==="missing")throw new Error("jwt_secret_missing");if(e==="preset")throw new Error("jwt_secret_preset");return r.JWT_SECRET}var pe=Ze(()=>{"use strict";ai();Se();Ca();pi();La();$e()});var gl={};Fo(gl,{applySecurityHeaders:()=>ea,getCurrentUser:()=>ta,invalidateAuthUserCache:()=>Xr,validateCsrf:()=>ra});function ea(r,e){let t=new Headers(r.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(r.body,{status:r.status,statusText:r.statusText,headers:t})}function Xr(r){cr.delete(r),Nt.delete(r)}async function ta(r,e,t){let n=r.headers.get("Authorization")||"",s="";if(n.startsWith("Bearer "))s=n.slice(7);else if(r.headers.get("Upgrade")?.toLowerCase().includes("websocket")||new URL(r.url).pathname.endsWith("/ws")){let o=new URL(r.url);s=o.searchParams.get("token")||o.searchParams.get("access_token")||""}if(!s)return null;try{let o=await Ke(e),i=await Ie(o),c=await vr(s,i);if(c){let a=cr.get(c.sessionId);if(a&&a.expiresAt>Date.now()){let _=Nt.get(c.sessionId);return _&&(_.lastObserved=Math.floor(Date.now()/1e3)),a.user}let l=new ae(e.DB),u=await l.getSessionWithUser(c.sessionId);if(!u)return cr.delete(c.sessionId),Nt.delete(c.sessionId),null;let d=u.id||u.session_id||c.sessionId,p=Math.floor(Date.now()/1e3),f=u.last_active_at||u.created_at,m=Nt.get(c.sessionId),h=Math.max(f,m?.lastObserved??0);if(u.pin_hash&&!u.is_paused){let _=(u.session_lock_timeout||15)*60;if(p-h>_){try{await l.pauseSession(d)}catch(S){console.error("[Auth] Failed to update pauseSession in D1:",S)}u.is_paused=1}}if(u.is_paused)return{id:c.userId,username:u.username||"",role:u.role||c.role,isPaused:!0,sessionId:c.sessionId};let g=m?.lastWriteAttempt??f,w=parseInt(String(e.SESSION_LAST_ACTIVE_UPDATE_INTERVAL||"60"),10)||60,b=g;if(p-g>w){b=p;let _=l.updateLastActive(d,p).catch(S=>console.error("[Auth] session last-active write failed:",S));t&&typeof t.waitUntil=="function"&&t.waitUntil(_)}if(Nt.size>1e3){let _=Nt.keys().next().value;_&&Nt.delete(_)}Nt.set(c.sessionId,{lastObserved:p,lastWriteAttempt:b});let y={id:c.userId,username:u.username||"",role:u.role||c.role,sessionId:c.sessionId},E=parseInt(String(e.AUTH_CACHE_TTL_SEC||"30"),10)||30;if(cr.size>100){let _=cr.keys().next().value;_&&cr.delete(_)}return cr.set(c.sessionId,{user:y,expiresAt:Date.now()+E*1e3}),y}}catch{}return null}function ra(r){let e=r.headers.get("Cookie")||"",t=xr(e),n=r.headers.get("X-CSRF-Token");return!!t&&!!n&&t===n}var cr,Nt,Zn=Ze(()=>{"use strict";pe();$e();He();cr=new Map,Nt=new Map});import Jp from"node:path";var os=class{store=new Map;maxEntries;constructor(e=5e3){this.maxEntries=e}async match(e){let t=typeof e=="string"?e:e.url,n=this.store.get(t);if(n){if(Date.now()>n.expires){this.store.delete(t);return}return this.store.delete(t),this.store.set(t,n),new Response(n.body,{status:n.status,statusText:n.statusText,headers:new Headers(n.headers)})}}async put(e,t){let n=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(),a=Date.now();if(!this.store.has(n)&&this.store.size>=this.maxEntries){for(let[l,u]of this.store)a>u.expires&&this.store.delete(l);for(;this.store.size>=this.maxEntries;){let l=this.store.keys().next().value;if(l===void 0)break;this.store.delete(l)}}this.store.delete(n),this.store.set(n,{body:new Uint8Array(c),headers:new Headers(t.headers),status:t.status,statusText:t.statusText,expires:a+i*1e3})}async delete(e){let t=typeof e=="string"?e:e.url;return this.store.delete(t)}};function da(){if(typeof globalThis.caches>"u"){let r=new os;globalThis.caches={default:r,open:async()=>new os}}typeof globalThis.HTMLRewriter>"u"&&(globalThis.HTMLRewriter=class{handlers=[];on(r,e){return e.element&&this.handlers.push({selector:r,fn:e.element}),this}transform(r){let e=this.handlers,t=r.text(),n=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(r.headers);return s.delete("content-length"),new Response(n,{status:r.status,statusText:r.statusText,headers:s})}})}import _a from"node:fs";var is=[{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"}],as=[{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"}],on="www.okx.com",De="https://freedns.controld.com/no-ads-malware-typo";import{Buffer as Ho}from"node:buffer";function $o(r){return r==null?{type:"null"}:typeof r=="boolean"?{type:"integer",value:r?"1":"0"}:typeof r=="number"?Number.isInteger(r)?{type:"integer",value:String(r)}:{type:"float",value:r}:typeof r=="bigint"?{type:"integer",value:r.toString()}:typeof r=="string"?{type:"text",value:r}:r instanceof ArrayBuffer?{type:"blob",base64:Ho.from(r).toString("base64")}:ArrayBuffer.isView(r)?{type:"blob",base64:Ho.from(r.buffer,r.byteOffset,r.byteLength).toString("base64")}:{type:"text",value:String(r)}}function cs(r){if(!r||r.type==="null")return null;if(r.type==="integer"){let e=Number(r.value);return Number.isSafeInteger(e)?e:BigInt(r.value)}if(r.type==="float")return Number(r.value);if(r.type==="text")return r.value;if(r.type==="blob"){let e=r.base64||r.value||"",t=Ho.from(e,"base64"),n=new ArrayBuffer(t.length);return new Uint8Array(n).set(t),n}return r.value??r}function Ko(r){let e=r.trim();return e.startsWith("libsql://")?e="https://"+e.slice(9):!e.startsWith("http://")&&!e.startsWith("https://")&&(e="https://"+e),e.replace(/\/+$/,"")}function an(r){try{let e=Ko(r),t=new URL(e);return`${t.protocol}//${t.host}`}catch{return r.slice(0,16)+"..."}}function mr(r){if(!r)return!1;let e=(r.TURSO_DATABASE_URL||r.TURSO_URL)?.trim(),t=r.TURSO_AUTH_TOKEN?.trim();return!!(e&&t)}function cn(r,e=!1){let t=(r?.DATABASE_SERVICE||r?.DB_SERVICE)?.trim().toLowerCase();return t==="turso"?"Turso":t==="d1"?"D1":t==="file"?"File":mr(r)?"Turso":e?"File":"D1"}function pa(r){let e=[],t="",n=!1,s=!1,o=!1;for(let c=0;c<r.length;c++){let a=r[c],l=r[c+1];if(s){a===`
|
|
14
|
+
`&&(s=!1);continue}if(o){a==="*"&&l==="/"&&(o=!1,c++);continue}if(n){t+=a,a===n&&(l===n?(t+=l,c++):n=!1);continue}if(a==="-"&&l==="-"){s=!0,c++;continue}if(a==="/"&&l==="*"){o=!0,c++;continue}if(a==="'"||a==='"'){n=a,t+=a;continue}if(a===";"){let u=t.trim();u&&e.push(u),t="";continue}t+=a}let i=t.trim();return i&&e.push(i),e}var Wo=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}getParams(){return this.params}async first(e){try{let t=await this.all();if(!t.results||t.results.length===0)return null;let n=t.results[0];return e?n[e]??null:n}catch(t){throw console.warn(`[Turso D1] Query error in first(): ${t.message}
|
|
15
15
|
SQL: ${this.sql}`),t}}async all(){let e=Date.now();try{let t=await this.db.executeStatement(this.sql,this.params),n=t.rows.map(s=>{let o={};for(let i=0;i<t.cols.length;i++)o[t.cols[i].name]=cs(s[i]);return o});return{results:n,success:!0,meta:{duration:Date.now()-e,size_after:0,rows_read:n.length,rows_written:t.affected_row_count||0,last_row_id:t.last_insert_rowid?Number(t.last_insert_rowid):0,changed_db:(t.affected_row_count||0)>0,changes:t.affected_row_count||0}}}catch(t){throw console.warn(`[Turso D1] Query error in all(): ${t.message}
|
|
16
16
|
SQL: ${this.sql}`),t}}async run(){let e=Date.now();try{let t=await this.db.executeStatement(this.sql,this.params),n=t.affected_row_count||0,s=t.last_insert_rowid?Number(t.last_insert_rowid):0;return{results:[],success:!0,meta:{duration:Date.now()-e,size_after:0,rows_read:0,rows_written:n,last_row_id:s,changed_db:n>0,changes:n}}}catch(t){throw console.warn(`[Turso D1] Query error in run(): ${t.message}
|
|
17
17
|
SQL: ${this.sql}`),t}}async raw(e){try{let t=await this.db.executeStatement(this.sql,this.params),n=t.rows.map(s=>s.map(cs));return e?.columnNames&&t.cols.length>0?[t.cols.map(s=>s.name),...n]:n}catch(t){throw console.warn(`[Turso D1] Query error in raw(): ${t.message}
|
|
18
|
-
SQL: ${this.sql}`),t}}},
|
|
19
|
-
SQL: ${e}`)}let a=c.response?.result??{cols:[],rows:[],affected_row_count:0,last_insert_rowid:null};if(n){if(this.selectCache.size>=this.maxSelectCacheEntries){let l=this.selectCache.keys().next().value;l!==void 0&&this.selectCache.delete(l)}this.selectCache.set(s,{result:a,expiresAt:Date.now()+3e4})}return a}async batch(e){if(this.clearSelectCache(),e.length===0)return[];let t=Date.now(),n=[{type:"execute",stmt:{sql:"BEGIN IMMEDIATE"}}];for(let i of e){let c=i;n.push({type:"execute",stmt:{sql:c.sql,args:c.getParams().map(
|
|
18
|
+
SQL: ${this.sql}`),t}}},jo=class{constructor(e,t){this.url=e;this.authToken=t;this.endpoint=`${Ko(e)}/v2/pipeline`}url;authToken;endpoint;selectCache=new Map;maxSelectCacheEntries=300;isReadOnlyQuery(e){let t=e.trim().toUpperCase();return t.startsWith("SELECT")||t.startsWith("PRAGMA")}clearSelectCache(){this.selectCache.clear()}prepare(e){return new Wo(this,e)}async executePipeline(e){let t=await fetch(this.endpoint,{method:"POST",headers:{Authorization:`Bearer ${this.authToken}`,"Content-Type":"application/json"},body:JSON.stringify({requests:e})});if(!t.ok){let s=await t.text().catch(()=>"");throw new Error(`[Turso D1] HTTP ${t.status} ${t.statusText}: ${s}`)}return(await t.json()).results||[]}async executeStatement(e,t){let n=this.isReadOnlyQuery(e),s=n?`${e}::${JSON.stringify(t)}`:"";if(n){let l=this.selectCache.get(s);if(l&&l.expiresAt>Date.now())return l.result}else this.clearSelectCache();let o=t.map($o),c=(await this.executePipeline([{type:"execute",stmt:{sql:e,args:o}},{type:"close"}]))[0];if(!c)throw new Error(`[Turso D1] Empty response from pipeline for SQL: ${e}`);if(c.type==="error"||c.error){let l=c.error?.message||"Unknown database error";throw new Error(`[Turso D1] Query error: ${l}
|
|
19
|
+
SQL: ${e}`)}let a=c.response?.result??{cols:[],rows:[],affected_row_count:0,last_insert_rowid:null};if(n){if(this.selectCache.size>=this.maxSelectCacheEntries){let l=this.selectCache.keys().next().value;l!==void 0&&this.selectCache.delete(l)}this.selectCache.set(s,{result:a,expiresAt:Date.now()+3e4})}return a}async batch(e){if(this.clearSelectCache(),e.length===0)return[];let t=Date.now(),n=[{type:"execute",stmt:{sql:"BEGIN IMMEDIATE"}}];for(let i of e){let c=i;n.push({type:"execute",stmt:{sql:c.sql,args:c.getParams().map($o)}})}n.push({type:"execute",stmt:{sql:"COMMIT"}},{type:"close"});let s=await this.executePipeline(n);for(let i=0;i<s.length;i++){let c=s[i];if(c.type==="error"||c.error){try{await this.executePipeline([{type:"execute",stmt:{sql:"ROLLBACK"}},{type:"close"}])}catch{}let a=i-1,l=a>=0&&a<e.length?e[a].sql:"TRANSACTION";throw new Error(`[Turso D1] Batch statement ${i} failed: ${c.error?.message||"Error"}
|
|
20
20
|
SQL: ${l}`)}}let o=[];for(let i=0;i<e.length;i++){let a=s[i+1].response?.result??{cols:[],rows:[],affected_row_count:0,last_insert_rowid:null},l=a.rows.map(u=>{let d={};for(let p=0;p<a.cols.length;p++)d[a.cols[p].name]=cs(u[p]);return d});o.push({results:l,success:!0,meta:{duration:Date.now()-t,size_after:0,rows_read:l.length,rows_written:a.affected_row_count||0,last_row_id:a.last_insert_rowid?Number(a.last_insert_rowid):0,changed_db:(a.affected_row_count||0)>0,changes:a.affected_row_count||0}})}return o}async exec(e){this.clearSelectCache();let t=Date.now(),n=pa(e);if(n.length===0)return{count:0,duration:0};let s=n.map(i=>({type:"execute",stmt:{sql:i}}));s.push({type:"close"});let o=await this.executePipeline(s);for(let i=0;i<n.length;i++){let c=o[i];if(c.type==="error"||c.error)throw new Error(`[Turso D1] Exec error on statement ${i+1}: ${c.error?.message||"Error"}
|
|
21
|
-
SQL: ${n[i]}`)}return{count:n.length,duration:Date.now()-t}}async dump(){throw new Error("dump() is not supported in TursoD1Database")}withSession(e){return Object.assign(this,{getBookmark:()=>null})}};function ln(r,e){return new
|
|
21
|
+
SQL: ${n[i]}`)}return{count:n.length,duration:Date.now()-t}}async dump(){throw new Error("dump() is not supported in TursoD1Database")}withSession(e){return Object.assign(this,{getBookmark:()=>null})}};function ln(r,e){return new jo(r,e)}var ls=null,fa=null,ma=null;function Vo(r){let e=(r.TURSO_DATABASE_URL||r.TURSO_URL||"").trim(),t=(r.TURSO_AUTH_TOKEN||"").trim();if(!e||!t)throw new Error("[Turso] Missing TURSO_DATABASE_URL or TURSO_AUTH_TOKEN in environment.");return ls&&fa===e&&ma===t||(ls=ln(e,t),fa=e,ma=t),ls}import Jo from"node:fs";import _u from"node:path";async function ha(r){await r.exec(`
|
|
22
22
|
CREATE TABLE IF NOT EXISTS _cf_d1_migrations (
|
|
23
23
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
24
24
|
name TEXT UNIQUE NOT NULL,
|
|
25
25
|
applied_at INTEGER NOT NULL
|
|
26
26
|
);
|
|
27
|
-
`)}async function ga(r){try{await ha(r);let e=await r.prepare("SELECT count(*) as count, max(name) as lastApplied FROM _cf_d1_migrations").first();return{count:e?.count||0,lastApplied:e?.lastApplied||null}}catch{return{count:0,lastApplied:null}}}async function ya(r,e){if(await ha(r),!
|
|
27
|
+
`)}async function ga(r){try{await ha(r);let e=await r.prepare("SELECT count(*) as count, max(name) as lastApplied FROM _cf_d1_migrations").first();return{count:e?.count||0,lastApplied:e?.lastApplied||null}}catch{return{count:0,lastApplied:null}}}async function ya(r,e){if(await ha(r),!Jo.existsSync(e))return console.warn(`[Turso Migrations] Directory not found: ${e}`),0;let t=Jo.readdirSync(e).filter(i=>i.endsWith(".sql")).sort(),n=await r.prepare("SELECT name FROM _cf_d1_migrations").all(),s=new Set((n.results||[]).map(i=>i.name)),o=0;for(let i of t){if(s.has(i))continue;let c=_u.join(e,i),a=Jo.readFileSync(c,"utf-8");console.log(`[Turso Migrations] Applying ${i}...`);try{await r.exec(a),await r.prepare("INSERT INTO _cf_d1_migrations (name, applied_at) VALUES (?, ?)").bind(i,Math.floor(Date.now()/1e3)).run(),o++}catch(l){throw console.error(`[Turso Migrations] Failed to apply ${i}:`,l.message||l),l}}return o>0?console.log(`[Turso Migrations] Successfully applied ${o} migration(s).`):console.log("[Turso Migrations] Database schema is up-to-date."),o}import he from"node:fs";import re from"node:path";import{fileURLToPath as Ru}from"node:url";import{execSync as wa}from"node:child_process";import us from"node:fs";import Su from"node:path";import{execFileSync as Tu}from"node:child_process";var Go=`# ==============================================================================
|
|
28
28
|
# DNS Worker - Serverfull Mode Environment Configuration (.env.serverfull)
|
|
29
29
|
# ==============================================================================
|
|
30
30
|
# You can edit this file directly, or copy it to .env:
|
|
@@ -228,20 +228,20 @@ PRESET_EXTERNAL_FILTERS='[{"label":"filtering.presetOisdBig","url":"https://big.
|
|
|
228
228
|
|
|
229
229
|
# Preset ECH Fronting (outer SNI) domains (JSON string) / \u9884\u8BBE ECH \u524D\u7F6E\u5916\u5C42 SNI \u57DF\u540D (JSON \u5B57\u7B26\u4E32)
|
|
230
230
|
PRESET_ECH_FRONTING_DOMAINS='["cloudflare-ech.com","crypto.cloudflare.com","one.one.one.one","www.cloudflare.com","encryptedsni.com","cdnjs.com"]'
|
|
231
|
-
`;function
|
|
232
|
-
`);for(let n of t){let s=n.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 ${r}:`,e)}return!1}function fs(r=process.cwd()){
|
|
231
|
+
`;function Be(r,e=!1){let t=Su.dirname(r);if(us.existsSync(t)||us.mkdirSync(t,{recursive:!0,mode:493}),us.existsSync(r)&&!e)return{created:!1,path:r};if(us.writeFileSync(r,Go,{encoding:"utf-8",mode:420}),process.platform==="linux"&&process.env.SUDO_USER&&process.env.SUDO_USER!=="root"){let n=process.env.SUDO_USER.trim();if(/^[a-zA-Z0-9._-]+$/.test(n))try{Tu("chown",[n,r])}catch{}}return{created:!0,path:r}}function ot(){try{let r=re.dirname(Ru(import.meta.url));if(he.existsSync(re.join(r,"migrations"))&&he.existsSync(re.join(r,"static")))return r;let e=re.resolve(r,"..");if(he.existsSync(re.join(e,"migrations"))&&he.existsSync(re.join(e,"static")))return e;let t=re.resolve(r,"../..");if(he.existsSync(re.join(t,"migrations"))&&he.existsSync(re.join(t,"static")))return t}catch{}return process.cwd()}function un(){try{let r=re.join(ot(),"package.json");if(he.existsSync(r)){let e=JSON.parse(he.readFileSync(r,"utf-8"));if(e.version)return e.version}}catch{}return"1.0.0"}function qe(){if(process.platform==="win32"){let r=process.env.ProgramData||re.join(process.env.SystemDrive||"C:","ProgramData");return re.join(r,"DNS-Worker")}if(process.platform==="linux"){let r="/var/lib/dns-worker";if(typeof process.getuid=="function"&&process.getuid()===0)return r;if(he.existsSync(r))try{return he.accessSync(r,he.constants.W_OK),r}catch{}let e=process.env.HOME||"/tmp",t=process.env.XDG_DATA_HOME||re.join(e,".local","share");return re.join(t,"dns-worker")}if(process.platform==="darwin"){let r=process.env.HOME||"/tmp";return re.join(r,"Library","Application Support","DNS-Worker")}return re.join(process.cwd(),"data")}function Ft(){return re.join(qe(),"dns_worker.sqlite")}function hr(){if(process.platform==="win32"){let r=process.env.ProgramData||re.join(process.env.SystemDrive||"C:","ProgramData");return re.join(r,"DNS-Worker")}if(process.platform==="linux"){let r="/etc/dns-worker";if(typeof process.getuid=="function"&&process.getuid()===0)return r;if(he.existsSync(r))try{return he.accessSync(r,he.constants.W_OK),r}catch{}let e=process.env.HOME||"/tmp",t=process.env.XDG_CONFIG_HOME||re.join(e,".config");return re.join(t,"dns-worker")}if(process.platform==="darwin"){let r=process.env.HOME||"/tmp";return re.join(r,"Library","Application Support","DNS-Worker")}return re.join(process.cwd(),"config")}function Fe(){return re.join(hr(),".env")}function gr(r=!0){let e=qe(),t=hr(),n=Fe();try{he.existsSync(e)||he.mkdirSync(e,{recursive:!0,mode:493})}catch{}try{he.existsSync(t)||he.mkdirSync(t,{recursive:!0,mode:493})}catch{}if(r)try{Be(n,!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{wa(`chown -R ${s} "${e}"`)}catch{}try{wa(`chown -R ${s} "${t}"`)}catch{}}}return{dataDir:e,configDir:t,configFile:n}}import ba from"node:fs";import dn from"node:path";var ds=[];function ps(){return ds}function xu(r){try{if(ba.existsSync(r)){let t=ba.readFileSync(r,"utf-8").split(`
|
|
232
|
+
`);for(let n of t){let s=n.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 ${r}:`,e)}return!1}function fs(r=process.cwd()){gr(!0),ds.length=0;let e=[dn.join(r,".dev.vars"),dn.join(r,".env"),dn.join(r,".env.serverfull"),Fe(),process.platform==="linux"?"/etc/dns-worker/.env":null,process.platform==="linux"?"/etc/default/dns-worker":null,process.platform==="linux"?dn.join(qe(),".env"):null,dn.join(ot(),".env.serverfull")].filter(n=>!!n),t=Array.from(new Set(e));for(let n of t)xu(n)&&ds.push(n);return ds}import pn from"node:fs";import Au from"node:path";import Du from"node:crypto";function Ea(r=qe()){if(process.env.JWT_SECRET&&process.env.JWT_SECRET.trim().length>0)return process.env.JWT_SECRET.trim();let e=Au.join(r,".jwt_secret");try{if(pn.existsSync(e)){let n=pn.readFileSync(e,"utf-8").trim();if(n.length>=16)return n}}catch{}let t=Buffer.from(Du.randomBytes(32)).toString("hex");try{pn.existsSync(r)||pn.mkdirSync(r,{recursive:!0}),pn.writeFileSync(e,t,{encoding:"utf-8",mode:384})}catch{}return t}function fn(r){gr(),fs();let e=ot(),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(),n=(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=t,o=n;if(!s&&!o){let k=[{cert:"/etc/ssl/dns-worker/fullchain.pem",key:"/etc/ssl/dns-worker/privkey.pem"},{cert:"/etc/ssl/dns-worker/cert.pem",key:"/etc/ssl/dns-worker/key.pem"},{cert:"/etc/dns-worker/certs/fullchain.pem",key:"/etc/dns-worker/certs/privkey.pem"},{cert:"/etc/dns-worker/certs/cert.pem",key:"/etc/dns-worker/certs/key.pem"}];for(let N of k)try{if(_a.existsSync(N.cert)&&_a.existsSync(N.key)){o=N.cert,s=N.key;break}}catch{}}let i=parseInt(r?.["dns-port"]||process.env.SERVERFULL_UDP_PORT||process.env.DNS_PORT||"53",10),c=parseInt(r?.["dot-port"]||process.env.SERVERFULL_DOT_PORT||process.env.DOT_PORT||"853",10),a=(r?.["dot-domain"]||process.env.SERVERFULL_DOT_DOMAIN||process.env.DOT_DOMAIN||"").trim(),l=parseInt(r?.["http-port"]||r?.port||process.env.SERVERFULL_HTTP_PORT||process.env.HTTP_PORT||process.env.PORT||"10080",10),u=parseInt(r?.["https-port"]||process.env.SERVERFULL_HTTPS_PORT||process.env.HTTPS_PORT||"10443",10),d=r?.host||process.env.SERVERFULL_HOST||process.env.SERVERFULL_BIND_ADDRESS||"0.0.0.0",p=Ft(),f=r?.db||process.env.SERVERFULL_DB_PATH||process.env.DB_PATH||p,m=r?.["default-profile"]||process.env.SERVERFULL_DEFAULT_PROFILE_KEY||process.env.DEFAULT_PROFILE_KEY||"",h=!!(r?.["disable-udp"]||process.env.SERVERFULL_DISABLE_UDP==="true"),g=!!(r?.["disable-dot"]||process.env.SERVERFULL_DISABLE_DOT==="true"),w=!!(r?.["disable-https"]||process.env.SERVERFULL_DISABLE_HTTPS==="true"),b=r?.["ech-enabled"]!==void 0?!!r["ech-enabled"]:process.env.SERVERFULL_ECH_ENABLED===void 0||process.env.SERVERFULL_ECH_ENABLED==="true"||process.env.SERVERFULL_ECH_ENABLED==="1",y=(r?.["ech-config"]||process.env.SERVERFULL_ECH_CONFIG||"").trim(),E=(r?.["ech-fronting-domain"]||process.env.SERVERFULL_ECH_FRONTING_DOMAIN||"cloudflare-ech.com").trim(),_=(r?.["turso-url"]||process.env.TURSO_DATABASE_URL||process.env.TURSO_URL||"").trim(),S=(r?.["turso-token"]||process.env.TURSO_AUTH_TOKEN||"").trim(),x=r?.["database-service"]||r?.["db-service"]||process.env.DATABASE_SERVICE||process.env.DB_SERVICE,R=cn({DATABASE_SERVICE:x,TURSO_DATABASE_URL:_,TURSO_AUTH_TOKEN:S},!0),D={tlsKeyPath:s,tlsCertPath:o,udpPort:i,dotPort:c,dotDomain:a,httpPort:l,httpsPort:u,host:d,dbPath:f,databaseService:R,tursoDatabaseUrl:_,tursoAuthToken:S,defaultProfileKey:m,disableUdp:h,disableDot:g,disableHttps:w,echEnabled:b,echConfig:y,echFrontingDomain:E,packageRoot:e},P={DB:null,DATABASE_SERVICE:R,TURSO_DATABASE_URL:_,TURSO_AUTH_TOKEN:S,ASSETS:null,JWT_SECRET:Ea(),FAIL_OPEN_UPSTREAM:process.env.FAIL_OPEN_UPSTREAM||De,SUBSTITUTE_DOMAIN:process.env.SUBSTITUTE_DOMAIN||on,PRESET_UPSTREAMS:process.env.PRESET_UPSTREAMS||JSON.stringify(is),PRESET_EXTERNAL_FILTERS:process.env.PRESET_EXTERNAL_FILTERS||JSON.stringify(as),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,CONFIG_MEM_TTL:process.env.CONFIG_MEM_TTL||3e5,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:m,SERVERFULL_DB_PATH:f,SERVERFULL_DOT_DOMAIN:a,DOT_DOMAIN:a,SERVERFULL_HTTPS_PORT:u,SERVERFULL_DOT_PORT:c,SERVERFULL_HTTP_PORT:l,SERVERFULL_ECH_ENABLED:b?"true":"false",SERVERFULL_ECH_CONFIG:y,SERVERFULL_ECH_FRONTING_DOMAIN:E,...process.env};return{config:D,env:P}}import wt from"node:fs";import yr from"node:path";import{DatabaseSync as vu}from"node:sqlite";var Yo=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 n=this.db.prepare(this.sql).get(...this.params);return n?e?n[e]??null:n:null}catch(t){throw console.warn(`[SQLite D1] Query error in first(): ${t.message}
|
|
233
233
|
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}
|
|
234
234
|
SQL: ${this.sql}`),e}}async run(){try{let t=this.db.prepare(this.sql).run(...this.params),n=Number(t.changes),s=Number(t.lastInsertRowid);return{results:[],success:!0,meta:{duration:0,size_after:0,rows_read:0,rows_written:n,last_row_id:s,changed_db:n>0,changes:n}}}catch(e){throw console.warn(`[SQLite D1] Query error in run(): ${e.message}
|
|
235
235
|
SQL: ${this.sql}`),e}}async raw(e){try{let n=this.db.prepare(this.sql).all(...this.params),s=n.map(o=>Object.values(o));return e?.columnNames&&n.length>0?[Object.keys(n[0]),...s]:s}catch(t){throw console.warn(`[SQLite D1] Query error in raw(): ${t.message}
|
|
236
|
-
SQL: ${this.sql}`),t}}},
|
|
236
|
+
SQL: ${this.sql}`),t}}},Xo=class{constructor(e,t){this.rawDb=e;this.dbPath=t}rawDb;dbPath;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 Yo(this.rawDb,e)}async batch(e){this.rawDb.exec("BEGIN IMMEDIATE");try{let t=[];for(let n of e){let s=await n.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 Pu(r,e){if(r.exec(`
|
|
237
237
|
CREATE TABLE IF NOT EXISTS _cf_d1_migrations (
|
|
238
238
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
239
239
|
name TEXT UNIQUE NOT NULL,
|
|
240
240
|
applied_at INTEGER NOT NULL
|
|
241
241
|
);
|
|
242
|
-
`),!yt.existsSync(e)){console.warn(`[Migrations] Directory not found: ${e}`);return}let t=yt.readdirSync(e).filter(i=>i.endsWith(".sql")).sort(),n=r.prepare("SELECT name FROM _cf_d1_migrations WHERE name = ?"),s=r.prepare("INSERT INTO _cf_d1_migrations (name, applied_at) VALUES (?, ?)"),o=0;for(let i of t){if(n.get(i))continue;let a=wr.join(e,i),l=yt.readFileSync(a,"utf-8");console.log(`[Migrations] Applying ${i}...`),r.exec("BEGIN IMMEDIATE");try{r.exec(l),s.run(i,Math.floor(Date.now()/1e3)),r.exec("COMMIT"),o++}catch(u){throw r.exec("ROLLBACK"),console.error(`[Migrations] Failed to apply ${i}:`,u.message||u),u}}o>0?console.log(`[Migrations] Successfully applied ${o} migration(s).`):console.log("[Migrations] Database schema is up-to-date.")}function ms(r,e=st()){let t=wr.dirname(r);if(yt.existsSync(t)||yt.mkdirSync(t,{recursive:!0}),!yt.existsSync(r)){let o=wr.join(process.cwd(),"data","dns_worker.sqlite");if(yt.existsSync(o)&&wr.resolve(o)!==wr.resolve(r))try{yt.copyFileSync(o,r),console.log(`[SQLite D1] Seamlessly migrated existing database from ${o} to ${r}`)}catch{}}console.log(`[SQLite D1] Connecting to database at: ${r}`);let n=new Pu(r);n.exec("PRAGMA journal_mode = WAL;"),n.exec("PRAGMA synchronous = NORMAL;"),n.exec("PRAGMA busy_timeout = 5000;"),n.exec("PRAGMA foreign_keys = ON;"),n.exec("PRAGMA temp_store = MEMORY;"),n.exec("PRAGMA cache_size = -64000;"),n.exec("PRAGMA mmap_size = 268435456;");let s=wr.join(e,"migrations");return Cu(n,s),new zo(n,r)}import hp from"node:dgram";var hs={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"},mn=Object.fromEntries(Object.entries(hs).map(([r,e])=>[e,Number(r)]));function ot(r,e){let t="",n=e,s=!1,o=0,i=0,c=!1;for(;i<128&&!(n>=r.length);){let a=r[n];if(a===0){s||o++,c=!0;break}if((a&192)===192){if(n+1>=r.length)break;let l=(a&63)<<8|r[n+1];s||(o+=2,s=!0),n=l,i++;continue}if((a&192)!==0||(t.length>0&&(t+="."),n+1+a>r.length))break;for(let l=0;l<a;l++)t+=String.fromCharCode(r[n+1+l]);s||(o+=a+1),n+=a+1,i++}return c?{name:t,read:o}:{name:"",read:0}}function Qo(r){return hs[r]||`TYPE${r}`}function br(r){try{if(r.length<16)return null;let{name:e,read:t}=ot(r,12);if(t===0)return null;let n=12+t;if(n+4>r.length)return null;let s=r[n]<<8|r[n+1];return{name:e,type:Qo(s),raw:r}}catch(e){return console.error("DNS Parse Error:",e),null}}async function Zo(r){try{let e;if(r.method==="GET"){let n=new URL(r.url).searchParams.get("dns");if(!n)return null;let s=n.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(r.method==="POST"){let t=await r.arrayBuffer();e=new Uint8Array(t)}else return null;return br(e)}catch(e){return console.error("DNS Parse Error:",e),null}}function ke(r){if(r.length<12)return[];let e=r[6]<<8|r[7];if(e===0)return[];let t=[],n=12,s=r[4]<<8|r[5];for(let o=0;o<s;o++){if(n>=r.length)return[];let{read:i}=ot(r,n);if(i===0)return[];if(n+=i+4,n>r.length)return[]}for(let o=0;o<e&&!(n>=r.length);o++){let{name:i,read:c}=ot(r,n);if(c===0||(n+=c,n+10>r.length))break;let a=r[n]<<8|r[n+1],l=r[n+4]<<24|r[n+5]<<16|r[n+6]<<8|r[n+7],u=r[n+8]<<8|r[n+9];if(n+=10,n+u>r.length)break;let d=Qo(a),p="";if(d==="A"&&u===4)p=`${r[n]}.${r[n+1]}.${r[n+2]}.${r[n+3]}`;else if(d==="AAAA"&&u===16){let f=[];for(let w=0;w<16;w+=2)f.push((r[n+w]<<8|r[n+w+1]).toString(16));let m=-1,h=0,g=-1,b=0;for(let w=0;w<f.length;w++)f[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===f.length?":":"";f.splice(m,h,w)}p=f.join(":").replace(":::","::")}else if(d==="CNAME"||d==="NS"||d==="PTR")p=ot(r,n).name;else if(d==="TXT"){let f=n,m=[],h=n+u;for(;f<h;){let g=r[f];if(f+1+g>h)break;m.push(String.fromCharCode(...r.slice(f+1,f+1+g))),f+=g+1}p=m.join("")}else if(d==="HTTPS"||d==="SVCB")if(u>=2){let f=r[n]<<8|r[n+1],{name:m,read:h}=ot(r,n+2),g=n+2+h,b=n+u,w=[];for(;g+4<=b;){let y=r[g]<<8|r[g+1],E=r[g+2]<<8|r[g+3];if(g+=4,g+E>b)break;if(y===1){let _=g,S=g+E,x=[];for(;_<S;){let R=r[_];if(_+1+R>S)break;let D="";for(let P=0;P<R;P++)D+=String.fromCharCode(r[_+1+P]);x.push(D),_+=R+1}w.push(`alpn=${x.join(",")}`)}else if(y===4){let _=[];for(let S=0;S+4<=E;S+=4)_.push(`${r[g+S]}.${r[g+S+1]}.${r[g+S+2]}.${r[g+S+3]}`);w.push(`ipv4hint=${_.join(",")}`)}else if(y===5){let _="";for(let S=0;S<E;S++)_+=String.fromCharCode(r[g+S]);w.push(`ech=${btoa(_)}`)}else if(y===6){let _=[];for(let S=0;S+16<=E;S+=16){let x=[];for(let R=0;R<16;R+=2)x.push((r[g+S+R]<<8|r[g+S+R+1]).toString(16));_.push(x.join(":"))}w.push(`ipv6hint=${_.join(",")}`)}else w.push(`key${y}=[${E}B]`);g+=E}p=`${f} ${m||"."}${w.length>0?" "+w.join(" "):""}`.trim()}else p=`[Raw: ${u} bytes]`;else p=`[Raw: ${u} bytes]`;t.push({name:i,type:d,data:p,ttl:l}),n+=u}return t}var ku=["cloudflare-ech.com","crypto.cloudflare.com","one.one.one.one","www.cloudflare.com","encryptedsni.com","cdnjs.com"];var Ht="cloudflare-ech.com",Sa="AEX+DQBBawAgACAUjjcEHSf2wlThCqPLx//d+m3qlWUe3nwuQaUVaVwQBgAEAAEAAQASY2xvdWRmbGFyZS1lY2guY29tAAA=";function Ta(r){if(r?.PRESET_ECH_FRONTING_DOMAINS)try{let e=JSON.parse(r.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[...ku]}function Lu(r,e=Ht){try{let t=atob(r),n=new Uint8Array(t.length);for(let R=0;R<t.length;R++)n[R]=t.charCodeAt(R);if(n.length<16||(n[2]<<8|n[3])!==65037)return r;let o=n[6],i=n[7]<<8|n[8],c=n[9]<<8|n[10],a=11,l=a+c;if(l+4>n.length)return r;let u=n.slice(a,l),d=l,p=n[d]<<8|n[d+1];if(d+=2,d+p+2>n.length)return r;let f=n.slice(d,d+p);d+=p;let m=n[d++],h=n[d++];if(d+h+2>n.length)return r;d+=h;let g=n[d]<<8|n[d+1];if(d+=2,d+g>n.length)return r;let b=n.slice(d,d+g),w=(e||Ht).trim().toLowerCase(),y=new Uint8Array(w.length);for(let R=0;R<w.length;R++)y[R]=w.charCodeAt(R);let E=[o,i>>8&255,i&255,c>>8&255,c&255,...Array.from(u),p>>8&255,p&255,...Array.from(f),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 R=0;R<S.length;R++)x+=String.fromCharCode(S[R]);return btoa(x)}catch(t){return console.error("Failed to rebuild ECH with fronting domain:",t),r}}function hn(r=Ht,e){return Lu(e||Sa,r)}function Ou(r){let e=new Uint8Array(16);if(r.includes("::")){let[t,n]=r.split("::"),s=t?t.split(":").filter(Boolean):[],o=n?n.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=r.split(":"),n=0;for(let s of t){let o=parseInt(s,16);e[n++]=o>>8&255,e[n++]=o&255}}return Array.from(e)}function Nu(r){let{priority:e=1,target:t=".",alpn:n=["h3","h2"],ipv4hints:s=[],ipv6hints:o=[],echBase64:i=null}=r,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 u=0;u<l.length;u++)c.push(l.charCodeAt(u))}c.push(0)}if(n&&n.length>0){let a=[];for(let l of n){a.push(l.length);for(let u=0;u<l.length;u++)a.push(l.charCodeAt(u))}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 u=l.split(".").map(Number);u.length===4&&u.every(d=>!isNaN(d)&&d>=0&&d<=255)&&a.push(...u)}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 u=0;u<a.length;u++)l.push(a.charCodeAt(u));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 u=Ou(l);u&&u.length===16&&a.push(...u)}a.length>0&&(c.push(0,6),c.push(a.length>>8&255,a.length&255),c.push(...a))}return c}function Ra(r){let e=r.trim().split(/\s+/),t=parseInt(e[0],10)||1,n=e[1]||".",s,o,i,c;for(let a=2;a<e.length;a++){let l=e[a],u=l.indexOf("=");if(u===-1)continue;let d=l.substring(0,u),p=l.substring(u+1);d==="alpn"?s=p.split(","):d==="ipv4hint"?o=p.split(","):d==="ech"?i=p:d==="ipv6hint"&&(c=p.split(","))}return Nu({priority:t,target:n,alpn:s,ipv4hints:o,ipv6hints:c,echBase64:i})}function gs(r){let e=r.split(".");if(e.length!==4)return null;let t=!1,n=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:n}function gn(r){let e=r.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 n=e.split("::");if(n.length>2)return null;let s=e;if(n.length===2){let c=n[0]?n[0].split(":"):[],a=n[1]?n[1].split(":"):[];if(c.includes("")||a.includes(""))return null;let l=8-(c.length+a.length);if(l<0)return null;let u=new Array(l).fill("0").join(":");s=[...c,u,...a].filter(Boolean).join(":")}let o=s.split(":");if(o.length!==8)return null;if(t){let c=gs(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 it(r){return gs(r)!==null}function $t(r){return gn(r)!==null}function qo(r){if(!r||typeof r!="string")return null;let e=r.lastIndexOf("/");if(e===-1)return null;let t=r.slice(0,e).trim(),n=r.slice(e+1).trim(),s=parseInt(n,10);if(isNaN(s)||s<0)return null;if(t.includes(":")){if(s>128)return null;let o=gn(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=gs(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 ys(r){let e=[],t=[];for(let n of r){let s=qo(n);s&&(s.version===4?e.push(s):t.push(s))}return n=>{if(!n)return!1;if(n.includes(":")){let s=gn(n);return s===null?!1:t.some(o=>(s&o.mask)===o.net)}else{let s=gs(n);return s===null?!1:e.some(o=>(s&o.mask)>>>0===o.net)}}}var ei=[],ti=null;function ri(r){r&&r.length>0&&(ei=r,ti=ys(ei))}function ws(){return ei}function bs(r){return ti?ti(r):!1}var wt=new Map,yn=300*1e3,de=class{constructor(e){this.db=e}db;static clearMemoryCache(e){e?wt.delete(e):wt.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={},n=Date.now()+yn;for(let s of e)t[s.key]=s.value,wt.set(s.key,{value:s.value,expiresAt:n});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=wt.get(e);if(t&&t.expiresAt>Date.now())return t.value;try{let n=await this.db.prepare("SELECT value FROM system_settings WHERE key = ?").bind(e).first(),s=n?n.value:null;return wt.set(e,{value:s,expiresAt:Date.now()+yn}),s}catch(n){if((n instanceof Error?n.message:String(n)).includes("no such table"))return await this.ensureTable(),null;throw n}}async set(e,t){let n=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,n).run();return s.success&&wt.set(e,{value:t,expiresAt:Date.now()+yn}),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,n).run();return i.success&&wt.set(e,{value:t,expiresAt:Date.now()+yn}),i.success}throw s}}async setMany(e){let t=Math.floor(Date.now()/1e3),n=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{n.length>0&&await this.db.batch(n)}catch(o){if((o instanceof Error?o.message:String(o)).includes("no such table"))await this.ensureTable(),n.length>0&&await this.db.batch(n);else throw o}let s=Date.now()+yn;for(let[o,i]of Object.entries(e))wt.set(o,{value:String(i),expiresAt:s});return!0}};var xa=null,wn=null;async function Aa(r){ws().length>0||(!wn&&r&&(wn=(async()=>{try{let t=new de(r),[n,s]=await Promise.all([t.get("cf_proxy_cidrs"),t.get("cf_active_ech_config")]);if(s&&(xa=s),n){let o=JSON.parse(n);if(Array.isArray(o)&&o.length>0){ri(o);return}}await ni(r,!0)}catch(t){console.warn("[ECH] Could not load Cloudflare IP ranges from DB:",t)}finally{wn=null}})()),wn&&await wn)}async function ni(r,e=!1){let t=new de(r),n=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)&&n-o<86400)return{success:!0,updated:!1,count:ws().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(),u=[...c.split(`
|
|
242
|
+
`),!wt.existsSync(e)){console.warn(`[Migrations] Directory not found: ${e}`);return}let t=wt.readdirSync(e).filter(i=>i.endsWith(".sql")).sort(),n=r.prepare("SELECT name FROM _cf_d1_migrations WHERE name = ?"),s=r.prepare("INSERT INTO _cf_d1_migrations (name, applied_at) VALUES (?, ?)"),o=0;for(let i of t){if(n.get(i))continue;let a=yr.join(e,i),l=wt.readFileSync(a,"utf-8");console.log(`[Migrations] Applying ${i}...`),r.exec("BEGIN IMMEDIATE");try{r.exec(l),s.run(i,Math.floor(Date.now()/1e3)),r.exec("COMMIT"),o++}catch(u){throw r.exec("ROLLBACK"),console.error(`[Migrations] Failed to apply ${i}:`,u.message||u),u}}o>0?console.log(`[Migrations] Successfully applied ${o} migration(s).`):console.log("[Migrations] Database schema is up-to-date.")}function ms(r,e=ot()){let t=yr.dirname(r);if(wt.existsSync(t)||wt.mkdirSync(t,{recursive:!0}),!wt.existsSync(r)){let o=yr.join(process.cwd(),"data","dns_worker.sqlite");if(wt.existsSync(o)&&yr.resolve(o)!==yr.resolve(r))try{wt.copyFileSync(o,r),console.log(`[SQLite D1] Seamlessly migrated existing database from ${o} to ${r}`)}catch{}}console.log(`[SQLite D1] Connecting to database at: ${r}`);let n=new vu(r);n.exec("PRAGMA journal_mode = WAL;"),n.exec("PRAGMA synchronous = NORMAL;"),n.exec("PRAGMA busy_timeout = 5000;"),n.exec("PRAGMA foreign_keys = ON;"),n.exec("PRAGMA temp_store = MEMORY;"),n.exec("PRAGMA cache_size = -64000;"),n.exec("PRAGMA mmap_size = 268435456;");let s=yr.join(e,"migrations");return Pu(n,s),new Xo(n,r)}import mp from"node:dgram";var hs={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"},mn=Object.fromEntries(Object.entries(hs).map(([r,e])=>[e,Number(r)]));function it(r,e){let t="",n=e,s=!1,o=0,i=0,c=!1;for(;i<128&&!(n>=r.length);){let a=r[n];if(a===0){s||o++,c=!0;break}if((a&192)===192){if(n+1>=r.length)break;let l=(a&63)<<8|r[n+1];s||(o+=2,s=!0),n=l,i++;continue}if((a&192)!==0||(t.length>0&&(t+="."),n+1+a>r.length))break;for(let l=0;l<a;l++)t+=String.fromCharCode(r[n+1+l]);s||(o+=a+1),n+=a+1,i++}return c?{name:t,read:o}:{name:"",read:0}}function zo(r){return hs[r]||`TYPE${r}`}function wr(r){try{if(r.length<16)return null;let{name:e,read:t}=it(r,12);if(t===0)return null;let n=12+t;if(n+4>r.length)return null;let s=r[n]<<8|r[n+1];return{name:e,type:zo(s),raw:r}}catch(e){return console.error("DNS Parse Error:",e),null}}async function Qo(r){try{let e;if(r.method==="GET"){let n=new URL(r.url).searchParams.get("dns");if(!n)return null;let s=n.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(r.method==="POST"){let t=await r.arrayBuffer();e=new Uint8Array(t)}else return null;return wr(e)}catch(e){return console.error("DNS Parse Error:",e),null}}function Le(r){if(r.length<12)return[];let e=r[6]<<8|r[7];if(e===0)return[];let t=[],n=12,s=r[4]<<8|r[5];for(let o=0;o<s;o++){if(n>=r.length)return[];let{read:i}=it(r,n);if(i===0)return[];if(n+=i+4,n>r.length)return[]}for(let o=0;o<e&&!(n>=r.length);o++){let{name:i,read:c}=it(r,n);if(c===0||(n+=c,n+10>r.length))break;let a=r[n]<<8|r[n+1],l=r[n+4]<<24|r[n+5]<<16|r[n+6]<<8|r[n+7],u=r[n+8]<<8|r[n+9];if(n+=10,n+u>r.length)break;let d=zo(a),p="";if(d==="A"&&u===4)p=`${r[n]}.${r[n+1]}.${r[n+2]}.${r[n+3]}`;else if(d==="AAAA"&&u===16){let f=[];for(let b=0;b<16;b+=2)f.push((r[n+b]<<8|r[n+b+1]).toString(16));let m=-1,h=0,g=-1,w=0;for(let b=0;b<f.length;b++)f[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===f.length?":":"";f.splice(m,h,b)}p=f.join(":").replace(":::","::")}else if(d==="CNAME"||d==="NS"||d==="PTR")p=it(r,n).name;else if(d==="TXT"){let f=n,m=[],h=n+u;for(;f<h;){let g=r[f];if(f+1+g>h)break;m.push(String.fromCharCode(...r.slice(f+1,f+1+g))),f+=g+1}p=m.join("")}else if(d==="HTTPS"||d==="SVCB")if(u>=2){let f=r[n]<<8|r[n+1],{name:m,read:h}=it(r,n+2),g=n+2+h,w=n+u,b=[];for(;g+4<=w;){let y=r[g]<<8|r[g+1],E=r[g+2]<<8|r[g+3];if(g+=4,g+E>w)break;if(y===1){let _=g,S=g+E,x=[];for(;_<S;){let R=r[_];if(_+1+R>S)break;let D="";for(let P=0;P<R;P++)D+=String.fromCharCode(r[_+1+P]);x.push(D),_+=R+1}b.push(`alpn=${x.join(",")}`)}else if(y===4){let _=[];for(let S=0;S+4<=E;S+=4)_.push(`${r[g+S]}.${r[g+S+1]}.${r[g+S+2]}.${r[g+S+3]}`);b.push(`ipv4hint=${_.join(",")}`)}else if(y===5){let _="";for(let S=0;S<E;S++)_+=String.fromCharCode(r[g+S]);b.push(`ech=${btoa(_)}`)}else if(y===6){let _=[];for(let S=0;S+16<=E;S+=16){let x=[];for(let R=0;R<16;R+=2)x.push((r[g+S+R]<<8|r[g+S+R+1]).toString(16));_.push(x.join(":"))}b.push(`ipv6hint=${_.join(",")}`)}else b.push(`key${y}=[${E}B]`);g+=E}p=`${f} ${m||"."}${b.length>0?" "+b.join(" "):""}`.trim()}else p=`[Raw: ${u} bytes]`;else p=`[Raw: ${u} bytes]`;t.push({name:i,type:d,data:p,ttl:l}),n+=u}return t}var Cu=["cloudflare-ech.com","crypto.cloudflare.com","one.one.one.one","www.cloudflare.com","encryptedsni.com","cdnjs.com"];var Ht="cloudflare-ech.com",Sa="AEX+DQBBawAgACAUjjcEHSf2wlThCqPLx//d+m3qlWUe3nwuQaUVaVwQBgAEAAEAAQASY2xvdWRmbGFyZS1lY2guY29tAAA=";function Ta(r){if(r?.PRESET_ECH_FRONTING_DOMAINS)try{let e=JSON.parse(r.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[...Cu]}function ku(r,e=Ht){try{let t=atob(r),n=new Uint8Array(t.length);for(let R=0;R<t.length;R++)n[R]=t.charCodeAt(R);if(n.length<16||(n[2]<<8|n[3])!==65037)return r;let o=n[6],i=n[7]<<8|n[8],c=n[9]<<8|n[10],a=11,l=a+c;if(l+4>n.length)return r;let u=n.slice(a,l),d=l,p=n[d]<<8|n[d+1];if(d+=2,d+p+2>n.length)return r;let f=n.slice(d,d+p);d+=p;let m=n[d++],h=n[d++];if(d+h+2>n.length)return r;d+=h;let g=n[d]<<8|n[d+1];if(d+=2,d+g>n.length)return r;let w=n.slice(d,d+g),b=(e||Ht).trim().toLowerCase(),y=new Uint8Array(b.length);for(let R=0;R<b.length;R++)y[R]=b.charCodeAt(R);let E=[o,i>>8&255,i&255,c>>8&255,c&255,...Array.from(u),p>>8&255,p&255,...Array.from(f),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 R=0;R<S.length;R++)x+=String.fromCharCode(S[R]);return btoa(x)}catch(t){return console.error("Failed to rebuild ECH with fronting domain:",t),r}}function hn(r=Ht,e){return ku(e||Sa,r)}function Lu(r){let e=new Uint8Array(16);if(r.includes("::")){let[t,n]=r.split("::"),s=t?t.split(":").filter(Boolean):[],o=n?n.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=r.split(":"),n=0;for(let s of t){let o=parseInt(s,16);e[n++]=o>>8&255,e[n++]=o&255}}return Array.from(e)}function Ou(r){let{priority:e=1,target:t=".",alpn:n=["h3","h2"],ipv4hints:s=[],ipv6hints:o=[],echBase64:i=null}=r,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 u=0;u<l.length;u++)c.push(l.charCodeAt(u))}c.push(0)}if(n&&n.length>0){let a=[];for(let l of n){a.push(l.length);for(let u=0;u<l.length;u++)a.push(l.charCodeAt(u))}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 u=l.split(".").map(Number);u.length===4&&u.every(d=>!isNaN(d)&&d>=0&&d<=255)&&a.push(...u)}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 u=0;u<a.length;u++)l.push(a.charCodeAt(u));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 u=Lu(l);u&&u.length===16&&a.push(...u)}a.length>0&&(c.push(0,6),c.push(a.length>>8&255,a.length&255),c.push(...a))}return c}function Ra(r){let e=r.trim().split(/\s+/),t=parseInt(e[0],10)||1,n=e[1]||".",s,o,i,c;for(let a=2;a<e.length;a++){let l=e[a],u=l.indexOf("=");if(u===-1)continue;let d=l.substring(0,u),p=l.substring(u+1);d==="alpn"?s=p.split(","):d==="ipv4hint"?o=p.split(","):d==="ech"?i=p:d==="ipv6hint"&&(c=p.split(","))}return Ou({priority:t,target:n,alpn:s,ipv4hints:o,ipv6hints:c,echBase64:i})}function gs(r){let e=r.split(".");if(e.length!==4)return null;let t=!1,n=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:n}function gn(r){let e=r.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 n=e.split("::");if(n.length>2)return null;let s=e;if(n.length===2){let c=n[0]?n[0].split(":"):[],a=n[1]?n[1].split(":"):[];if(c.includes("")||a.includes(""))return null;let l=8-(c.length+a.length);if(l<0)return null;let u=new Array(l).fill("0").join(":");s=[...c,u,...a].filter(Boolean).join(":")}let o=s.split(":");if(o.length!==8)return null;if(t){let c=gs(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 at(r){return gs(r)!==null}function $t(r){return gn(r)!==null}function Zo(r){if(!r||typeof r!="string")return null;let e=r.lastIndexOf("/");if(e===-1)return null;let t=r.slice(0,e).trim(),n=r.slice(e+1).trim(),s=parseInt(n,10);if(isNaN(s)||s<0)return null;if(t.includes(":")){if(s>128)return null;let o=gn(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=gs(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 ys(r){let e=[],t=[];for(let n of r){let s=Zo(n);s&&(s.version===4?e.push(s):t.push(s))}return n=>{if(!n)return!1;if(n.includes(":")){let s=gn(n);return s===null?!1:t.some(o=>(s&o.mask)===o.net)}else{let s=gs(n);return s===null?!1:e.some(o=>(s&o.mask)>>>0===o.net)}}}var qo=[],ei=null;function ti(r){r&&r.length>0&&(qo=r,ei=ys(qo))}function ws(){return qo}function bs(r){return ei?ei(r):!1}var bt=new Map,yn=300*1e3,de=class{constructor(e){this.db=e}db;static clearMemoryCache(e){e?bt.delete(e):bt.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={},n=Date.now()+yn;for(let s of e)t[s.key]=s.value,bt.set(s.key,{value:s.value,expiresAt:n});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=bt.get(e);if(t&&t.expiresAt>Date.now())return t.value;try{let n=await this.db.prepare("SELECT value FROM system_settings WHERE key = ?").bind(e).first(),s=n?n.value:null;return bt.set(e,{value:s,expiresAt:Date.now()+yn}),s}catch(n){if((n instanceof Error?n.message:String(n)).includes("no such table"))return await this.ensureTable(),null;throw n}}async set(e,t){let n=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,n).run();return s.success&&bt.set(e,{value:t,expiresAt:Date.now()+yn}),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,n).run();return i.success&&bt.set(e,{value:t,expiresAt:Date.now()+yn}),i.success}throw s}}async setMany(e){let t=Math.floor(Date.now()/1e3),n=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{n.length>0&&await this.db.batch(n)}catch(o){if((o instanceof Error?o.message:String(o)).includes("no such table"))await this.ensureTable(),n.length>0&&await this.db.batch(n);else throw o}let s=Date.now()+yn;for(let[o,i]of Object.entries(e))bt.set(o,{value:String(i),expiresAt:s});return!0}};var xa=null,wn=null;async function Aa(r){ws().length>0||(!wn&&r&&(wn=(async()=>{try{let t=new de(r),[n,s]=await Promise.all([t.get("cf_proxy_cidrs"),t.get("cf_active_ech_config")]);if(s&&(xa=s),n){let o=JSON.parse(n);if(Array.isArray(o)&&o.length>0){ti(o);return}}await ri(r,!0)}catch(t){console.warn("[ECH] Could not load Cloudflare IP ranges from DB:",t)}finally{wn=null}})()),wn&&await wn)}async function ri(r,e=!1){let t=new de(r),n=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)&&n-o<86400)return{success:!0,updated:!1,count:ws().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(),u=[...c.split(`
|
|
243
243
|
`),...a.split(`
|
|
244
|
-
`)].map(p=>p.trim()).filter(p=>p.length>0&&!p.startsWith("#")).filter(p=>
|
|
244
|
+
`)].map(p=>p.trim()).filter(p=>p.length>0&&!p.startsWith("#")).filter(p=>Zo(p)!==null),d=null;if(i&&i.ok)try{let p=await i.json();if(p.Answer)for(let f of p.Answer){let m=String(f.data).match(/ech=([A-Za-z0-9+/=]+)/);if(m){d=m[1];break}}}catch(p){console.warn("[ECH] Failed to parse live Cloudflare ECH config:",p)}if(u.length>=10){let p={cf_proxy_cidrs:JSON.stringify(u),cf_proxy_cidrs_updated_at:String(n)};return d&&(p.cf_active_ech_config=d,xa=d),await t.setMany(p),ti(u),console.log(`[ECH] Synced ${u.length} Cloudflare IP ranges and active ECH config.`),{success:!0,updated:!0,count:u.length}}else throw new Error(`Received insufficient valid CIDRs: ${u.length}`)}catch(s){return console.warn("[ECH] Cloudflare IP/ECH sync failed:",s.message||s),{success:!1,updated:!1,count:ws().length}}}function Es(r,e){let t=[];if(r==="A")t=e.split(".").map(n=>parseInt(n)||0);else if(r==="AAAA"){let n=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 u=parseInt(l,16);n[a++]=u>>8&255,n[a++]=u&255}a=16-c.length*2;for(let l of c){let u=parseInt(l,16);n[a++]=u>>8&255,n[a++]=u&255}}else{let s=e.split(":"),o=0;for(let i of s){let c=parseInt(i,16);n[o++]=c>>8&255,n[o++]=c&255}}t=Array.from(n)}else if(r==="CNAME"){let n=e.split(".");for(let s of n){t.push(s.length);for(let o=0;o<s.length;o++)t.push(s.charCodeAt(o))}t.push(0)}else if(r==="TXT")for(let n=0;n<e.length;n+=255){let s=e.substring(n,n+255);t.push(s.length);for(let o=0;o<s.length;o++)t.push(s.charCodeAt(o))}else(r==="HTTPS"||r==="SVCB")&&(t=Ra(e));return t}function Kt(r,e){let t=new Uint8Array(12),n=crypto.getRandomValues(new Uint16Array(1))[0];t[0]=n>>8,t[1]=n&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=r.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=mn[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 br(r){let e=new Uint8Array(12);return r&&r.length>=12&&e.set(r.slice(0,12)),e[2]=e[2]&1|128,e[3]=e[3]&240|2,e}function ni(r,e,t=0){try{if(!r||r.length<12)return br(r);let n=new Uint8Array(12);n.set(r.slice(0,12)),n[2]=n[2]&1|132,n[3]=128|t&15;let s=12,o=r[4]<<8|r[5];for(let d=0;d<o;d++){let{read:p}=it(r,s);if(p===0||(s+=p+4,s>r.length))return br(r)}let i=r.slice(12,s);if(n[4]=o>>8&255,n[5]=o&255,n[6]=e.length>>8&255,n[7]=e.length&255,n[8]=0,n[9]=0,n[10]=0,n[11]=0,e.length===0){let d=new Uint8Array(12+i.length);return d.set(n),d.set(i,12),d}let c=[],a=12+i.length;for(let d of e){let{name:p,type:f,value:m,ttl:h=60}=d,g=[];if(!p)g=[192,12];else{let S=p.split(".");for(let x of S){g.push(x.length);for(let R=0;R<x.length;R++)g.push(x.charCodeAt(R))}g.push(0)}let w=Es(f,m),b=w.length,y=new Uint8Array(g.length+10+b);y.set(g,0);let E=g.length,_=mn[f]||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(n,0),l.set(i,12);let u=12+i.length;for(let d of c)l.set(d,u),u+=d.length;return l}catch(n){console.error("Critical error in buildResponseMulti:",n);let s=new Uint8Array(12);return s.set(r.slice(0,12)),s[2]|=128,s[3]=s[3]&240|2,s}}function _e(r,e,t,n=60,s=0){try{if(!r||r.length<12)return br(r);let o=new Uint8Array(12);o.set(r.slice(0,12)),o[2]=o[2]&1|132,o[3]=128|s&15;let i=12,c=r[4]<<8|r[5];for(let m=0;m<c;m++){let{read:h}=it(r,i);if(h===0||(i+=h+4,i>r.length))return br(r)}let a=r.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=Es(e,t),u=l.length,d=new Uint8Array(12+u);d[0]=192,d[1]=12;let p=mn[e]||1;d[2]=p>>8,d[3]=p&255,d[4]=0,d[5]=1,d[6]=n>>24&255,d[7]=n>>16&255,d[8]=n>>8&255,d[9]=n&255,d[10]=u>>8&255,d[11]=u&255,d.set(l,12);let f=new Uint8Array(12+a.length+d.length);return f.set(o),f.set(a,12),f.set(d,12+a.length),f}catch(o){console.error("Critical error in buildResponse:",o);let i=new Uint8Array(12);return i.set(r.slice(0,12)),i[2]|=128,i[3]=i[3]&240|2,i}}function Nu(r){let e=r.lastIndexOf("/");if(e===-1)return null;let t=r.slice(0,e),n=parseInt(r.slice(e+1),10);if(isNaN(n))return null;if(t.includes(":")){let s=Iu(t);if(!s||n<0||n>128)return null;let o=Da(s,n);return{family:2,prefixLen:n,addrBytes:o}}else{let s=t.split(".").map(Number);if(s.length!==4||s.some(c=>isNaN(c)||c<0||c>255)||n<0||n>32)return null;let o=new Uint8Array(s),i=Da(o,n);return{family:1,prefixLen:n,addrBytes:i}}}function Da(r,e){let t=Math.ceil(e/8),n=new Uint8Array(t);for(let o=0;o<t;o++)n[o]=r[o]??0;let s=e%8;return s!==0&&t>0&&(n[t-1]&=255<<8-s&255),n}function Iu(r){try{let e=r.split("::");if(e.length>2)return null;let t=e[0]?e[0].split(":"):[],n=e[1]?e[1].split(":"):[],s=8-t.length-n.length,o=[...t,...Array(s).fill("0"),...n];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 Uu(r){let e=Nu(r);if(!e)return null;let{family:t,prefixLen:n,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++]=n,i[c++]=0,i.set(s,c);let a=i.length,l=new Uint8Array(11+a),u=0;return l[u++]=0,l[u++]=0,l[u++]=41,l[u++]=16,l[u++]=0,l[u++]=0,l[u++]=0,l[u++]=0,l[u++]=0,l[u++]=a>>8&255,l[u++]=a&255,l.set(i,u),l}function oi(r,e){let t=Uu(e);if(!t)return console.warn(`[ECS] Invalid CIDR "${e}", skipping injection.`),r;if(r.length<12)return r;let n=r[10]<<8|r[11],s=12,o=r[4]<<8|r[5];for(let p=0;p<o&&s<r.length;p++){for(;s<r.length;){let f=r[s];if(f===0){s++;break}if((f&192)===192){s+=2;break}s+=1+f}s+=4}let i=(r[6]<<8|r[7])+(r[8]<<8|r[9]);for(let p=0;p<i&&s<r.length;p++)s=si(r,s);let c=s,a=-1,l=-1,u=c;for(let p=0;p<n&&u<r.length;p++){let f=u;if(u<r.length&&r[u]===0&&(u+1<r.length?r[u+1]<<8|r[u+2]:-1)===41){a=f,u=si(r,u),l=u;break}u=si(r,u)}let d;if(a!==-1){let p=r.slice(0,a),f=r.slice(l);d=new Uint8Array(p.length+t.length+f.length),d.set(p,0),d.set(t,p.length),d.set(f,p.length+t.length)}else{d=new Uint8Array(r.length+t.length),d.set(r,0),d.set(t,r.length);let p=n+1;d[10]=p>>8&255,d[11]=p&255}return d}function si(r,e){if(e>=r.length)return e;for(;e<r.length;){let n=r[e];if(n===0){e++;break}if((n&192)===192){e+=2;break}e+=1+n}if(e+10>r.length)return r.length;let t=r[e+8]<<8|r[e+9];return e+=10+t,Math.min(e,r.length)}ge();var Er=class extends Map{constructor(t){super();this.maxEntries=t}maxEntries;set(t,n){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,n),this}},bn=new Er(3),En=new Er(200),_r=new Er(500),_n=new Er(500),Sr=null;function ii(r){Sr=r}async function Mu(r,e){try{let t=await fetch(`https://api.cloudflare.com/client/v4/zones/${r.CF_ZONE_ID}/purge_cache`,{method:"POST",headers:{Authorization:`Bearer ${r.CF_PURGE_TOKEN}`,"Content-Type":"application/json"},body:JSON.stringify({tags:e})});if(!t.ok){let n=await t.text();console.error(`[Cache] Global cache purge failed (HTTP ${t.status}):`,n)}}catch(t){console.error("[Cache] Global cache purge error:",t?.message||t)}}var _s={async clear(r,e=!0,t){let n=!0,s;typeof e=="boolean"?(n=e,t&&typeof t=="object"&&(s=t)):e&&typeof e=="object"&&(s=e,typeof t=="boolean"&&(n=t)),En.delete(r),n&&bn.delete(r),_n.clear(),Sr=null;for(let o of _r.keys())o.startsWith(`${r}:`)&&_r.delete(o);try{if(typeof caches<"u"&&caches&&caches.default){let o=caches.default,i=[v.delete(o,`profile_v6:${r}`)];n&&i.push(o.delete(`https://obex.local/bloom-bin/${r}`)),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-${r}`];n&&o.push(`bloom-${r}`),await Mu(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{return await this.db.prepare(`
|
|
245
245
|
SELECT * FROM (
|
|
246
246
|
SELECT p.*, ap.id as access_point_id, ap.name as access_point_name, 1 as priority
|
|
247
247
|
FROM access_points ap
|
|
@@ -254,7 +254,7 @@ SQL: ${this.sql}`),t}}},zo=class{constructor(e,t){this.rawDb=e;this.dbPath=t}raw
|
|
|
254
254
|
)
|
|
255
255
|
ORDER BY priority ASC
|
|
256
256
|
LIMIT 1
|
|
257
|
-
`).bind(e,e,e).first()||null}catch(t){return console.warn("[ProfileModel] findByKey query failed:",t.message||t),null}}async list(e,t){let{results:n}=await this.db.prepare(`SELECT * FROM profiles ${e}`).bind(...t).all();return n}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),n=j(12),s=5;for(let o=0;o<s;o++){let i=Wt(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(n,e.id,"Device-1",i,t,t)];try{return(await this.db.batch(a)).every(u=>u.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(n=>n.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(n=>n.success)}async updateName(e,t){let n=Math.floor(Date.now()/1e3);return(await this.db.prepare("UPDATE profiles SET name = ?, updated_at = ? WHERE id = ?").bind(t,n,e).run()).success}async updateSettings(e,t){let n=Math.floor(Date.now()/1e3);return(await this.db.prepare("UPDATE profiles SET settings = ?, updated_at = ? WHERE id = ?").bind(JSON.stringify(t),n,e).run()).success}async rotateKey(e,t){let n=Math.floor(Date.now()/1e3);return(await this.db.prepare("UPDATE profiles SET profile_key = ?, updated_at = ? WHERE id = ?").bind(t,n,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:n}=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 n}async updateListUpdatedAt(e,t){return(await this.db.prepare("UPDATE profiles SET list_updated_at = ? WHERE id = ?").bind(t,e).run()).success}};var Cr=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 n=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,n,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 n=Math.floor(Date.now()/1e3),s=t.map(i=>{let c=i.pattern?i.pattern.trim().toLowerCase():"",a=i.created_at??n;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,n){let s=n.pattern?n.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(n.type,s,n.v_a||null,n.v_aaaa||null,n.v_txt||null,n.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,n){return await this.db.prepare("SELECT * FROM rules WHERE profile_id = ? AND LOWER(pattern) = ? AND id != ?").bind(e,t.trim().toLowerCase(),n).first()}async deleteRule(e,t){return(await this.db.prepare("DELETE FROM rules WHERE id = ? AND profile_id = ?").bind(e,t).run()).success}};var Te=class r{size;hashes;bitArray;static FNV_PRIME=16777619;static FNV_SEED_0=2166136261;static encoder=new TextEncoder;constructor(e,t,n){this.size=e>>>0,this.hashes=t>>>0;let s=this.size+31>>>5;this.bitArray=n||new Uint32Array(s)}static create(e,t=1e-4){let n=Math.max(e,100),o=Math.ceil(-(n*Math.log(t))/Math.log(2)**2),i=Math.round(o/n*Math.log(2));return new r(o,i)}add(e){let t=r.FNV_SEED_0,n=e.length;for(let a=0;a<n;a++)t^=e.charCodeAt(a)&255,t=Math.imul(t,r.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=r.FNV_SEED_0,n=e.length;for(let a=0;a<n;a++)t^=e.charCodeAt(a)&255,t=Math.imul(t,r.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),n=t.getUint32(0,!0),s=t.getUint32(4,!0);if(n===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=n+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 u=new Uint8Array(c<<2);u.set(e.subarray(8,8+(c<<2))),l=new Uint32Array(u.buffer,0,c)}return new r(n,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,n=e.bitArray,s=t.length;for(let o=0;o<s;o++)t[o]|=n[o]}fnv1a(e,t){let n=t>>>0;for(let s=0;s<e.length;s++)n^=e[s],n=Math.imul(n,r.FNV_PRIME);return n>>>0}fnv1aString(e,t){let n=t>>>0,s=e.length;for(let o=0;o<s;o++)n^=e.charCodeAt(o)&255,n=Math.imul(n,r.FNV_PRIME);return n>>>0}dump(){let e=new Uint8Array(this.bitArray.buffer,this.bitArray.byteOffset,this.bitArray.byteLength),t="",n=e.byteLength,s=32768;for(let o=0;o<n;o+=s)t+=String.fromCharCode.apply(null,e.subarray(o,Math.min(o+s,n)));return{size:this.size,hashes:this.hashes,data:btoa(t)}}static load(e){let t=atob(e.data),n=new Uint8Array(t.length);for(let i=0;i<t.length;i++)n[i]=t.charCodeAt(i);let s=n.length+3>>2,o=new Uint32Array(s);return new Uint8Array(o.buffer).set(n),new r(e.size,e.hashes,o)}};var Tt=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,n){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,n)),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 n=t.reduce((i,c)=>{let a=c.bloom_filter_chunk.byteLength??c.bloom_filter_chunk.length;return i+a},0),s=new Uint8Array(n),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,n,s){let i=Te.create(t,n).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,n){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,n)),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 n=t.reduce((i,c)=>{let a=c.bloom_filter_chunk.byteLength??c.bloom_filter_chunk.length;return i+a},0),s=new Uint8Array(n),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:n}=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(!n||n.length===0)return await this.clearProfileBlooms(e),!0;let s=[this.db.prepare("DELETE FROM profile_blooms WHERE profile_id = ?").bind(e),...n.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 Oa={async load(r,e){let{profileId:t,env:n,ctx:s}=r;if(t==="default")return{settings:{upstream:[n.FAIL_OPEN_UPSTREAM||De],default_policy:"ALLOW",log_retention_days:0,ecs:{enabled:!0,use_client_ip:!0}},rules:[],bloom:void 0};let o=bn.get(t),i=En.get(t),c=Number(n.BLOOM_MEM_TTL)||6e5,a=Number(n.CONFIG_MEM_TTL)||3e5,l=Number.isFinite(a)&&a>0?a:3e5;if(i&&Date.now()-(i.timestamp||0)<l){e("load_config_l1_mem");let h=o&&Date.now()-o.ts<c?o.bloom:void 0;return{...i,bloom:h}}let u=caches.default,d=`profile_v6:${t}`,p=v.generateCacheUrl(`bloom-bin:${t}`),f=await v.get(u,d),m;if(f){if(e("load_config_l2_cache"),o&&Date.now()-o.ts<c)m=o.bloom;else try{let h=await u.match(p);if(h){e("load_bloom_l2_cache");let g=await h.arrayBuffer();m=Te.fromUint8Array(new Uint8Array(g)),bn.set(t,{bloom:m,ts:Date.now()})}}catch{}return En.set(t,{...f,timestamp:Date.now()}),{...f,bloom:m}}try{let h=new q(n.DB),g=new Cr(n.DB),b=new Tt(n.DB),[w,y,E]=await Promise.all([h.getById(t),g.getRules(t),b.getProfileBloom(t).catch(x=>(console.error("[Config] D1 Bloom loading failed:",x),null))]);if(!w)return i?(console.warn(`[Config] Profile ${t} not in D1, using stale memory config.`),{...i,bloom:o?.bloom}):null;let _=JSON.parse(w.settings);if(E){e("load_bloom_l3_d1");let x=new Uint8Array(E);m=Te.fromUint8Array(x),s.waitUntil(u.put(p,new Response(x,{headers:{"Content-Type":"application/octet-stream","Cache-Control":"public, max-age=604800","Cache-Tag":`bloom-${t}`}})))}let S={settings:_,rules:y};return m&&bn.set(t,{bloom:m,ts:Date.now()}),En.set(t,{...S,timestamp:Date.now()}),s.waitUntil(v.set(u,d,S,86400,[`profile-${t}`])),e("load_config_full_sync"),{...S,bloom:m}}catch(h){return console.warn(`[Config] D1 profile fetch failed for ${t}:`,h?.message||h),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:[n.FAIL_OPEN_UPSTREAM||De],default_policy:"ALLOW",log_retention_days:0,ecs:{enabled:!0,use_client_ip:!0}},rules:[],bloom:void 0})}}};function Cn(r){let e=r.trim();if(!e.startsWith("sdns://"))throw new Error("Invalid DNS Stamp: must start with sdns://");let t=e.slice(7),n=t.length;for(;n>0&&t.charCodeAt(n-1)===61;)n--;let s=t.slice(0,n),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 u=()=>{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)},d=()=>{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},p="unknown",f,m,h,g,b,w="";switch(a){case 0:{p="dns",f=u(),f&&(w=f.includes(":")&&!f.startsWith("[")?`tcp://${f}`:`tcp://${f}:53`);break}case 1:{p="dnscrypt",f=u(),c+=32,b=u(),w=`dnscrypt://${b||f}`;break}case 2:{p="doh",f=u(),g=d(),m=u(),h=u()||"/dns-query";let y=m||f;h.startsWith("/")||(h=`/${h}`),w=`https://${y}${h}`;break}case 3:{p="dot",f=u(),g=d(),m=u();let y=m||f,E=f&&f.includes(":")?f.split(":").pop():"853";w=y?.includes(":")?`tls://${y}`:`tls://${y}:${E}`;break}case 4:{p="doq",f=u(),g=d(),m=u(),w=`quic://${m||f}:853`;break}case 5:{p="odoh",f=u(),g=d(),m=u(),h=u()||"/dns-query",w=`https://${m||f}${h}`;break}default:w=e;break}return{protocol:p,protocolId:a,props:l,serverAddress:f||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 Rt=/^[a-zA-Z\d~`!@#$%^&*()_\-+={[}\]|\\:;"'<,>.?\/]{12,100}$/,xt=/^[a-z_][a-z0-9_-]{4,31}$/,hi=/^[a-zA-Z0-9_-]{1,30}$/,gi=/^[a-zA-Z0-9_-]{1,30}$/;var yi=/^[\p{L}\p{N}_ ()-]{1,30}$/u,Vt=/^[a-zA-Z0-9]{5,12}$/,Ia=/^\d{6}$/,Na=["localhost","metadata.google.internal","metadata.goog","169.254.169.254","instance-data","localtest.me"],Ku=[".localhost",".local",".internal",".lan",".home.arpa",".corp",".home",".localtest.me"];function Wu(r){let e=r.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=r.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 ju=["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"],mi=ys(ju);function tt(r){if(!r||typeof r!="string")return!1;let e=r.trim();if(e.startsWith("[")&&e.endsWith("]")&&(e=e.slice(1,-1)),e.includes(":")&&e.includes(".")){let n=e.lastIndexOf(":"),s=e.substring(n+1);return it(s)?!mi(s):!1}if(!it(e)&&!$t(e))return!1;let t=gn(e);if(t!==null&&t>>32n===0xffffn){let n=Number(t&0xffffffffn),s=`${n>>>24&255}.${n>>>16&255}.${n>>>8&255}.${n&255}`;return!mi(s)}return!mi(e)}function lt(r){try{if(r.startsWith("sdns://")){let o=Cn(r);return lt(o.resolvedUrl)}let e;r.startsWith("tcp://")||r.startsWith("udp://")?e=r.replace(/^(tcp|udp):\/\//,"http://"):r.startsWith("tls://")||r.startsWith("dot://")?e=r.replace(/^(tls|dot):\/\//,"http://"):r.startsWith("http://")||r.startsWith("https://")?e=r:e=`http://${r}`;let t=new URL(e),n=t.hostname.replace(/^\[|\]$/g,"").toLowerCase();if(Na.includes(n)||Na.includes(t.hostname.toLowerCase()))return!1;for(let o of Ku)if(n.endsWith(o)||n===o.slice(1))return!1;if(n.includes("metadata.google"))return!1;let s=Wu(n);return!(s&&!tt(s)||(it(n)||$t(n))&&!tt(n)||t.hostname.includes("@")||t.username||t.password)}catch{return!1}}async function Ua(r){if(!lt(r))return!1;if(typeof process<"u"&&process.versions?.node)try{let e=r;r.startsWith("sdns://")&&(e=Cn(r).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(it(s)||$t(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(!tt(c.address))return!1}catch{return!1}return!0}async function wi(r){if(!(typeof navigator<"u"&&navigator.userAgent==="Cloudflare-Workers"||typeof WebSocketPair<"u")&&typeof process<"u"&&!!process.versions?.node){if(r.secureTransport==="on"){let s=await import("node:tls"),o=await import("node:net");return new Promise((i,c)=>{let a=s.connect({host:r.hostname,port:r.port,servername:o.isIP(r.hostname)?void 0:r.hostname},()=>{let l=!1,u=new ReadableStream({start(p){a.on("data",f=>{p.enqueue(new Uint8Array(f.buffer,f.byteOffset,f.byteLength))}),a.on("end",()=>{try{p.close()}catch{}}),a.on("error",f=>{try{p.error(f)}catch{}})},cancel(){l||(l=!0,a.destroy())}}),d=new WritableStream({write(p){return new Promise((f,m)=>{a.write(p,h=>h?m(h):f())})},close(){return new Promise(p=>{a.end(()=>p())})},abort(p){a.destroy(p)}});i({readable:u,writable:d,close:async()=>{l||(l=!0,a.destroy())}})});a.on("error",c)})}let n=await import("node:net");return new Promise((s,o)=>{let i=n.createConnection({host:r.hostname,port:r.port},()=>{let c=!1,a=new ReadableStream({start(u){i.on("data",d=>{u.enqueue(new Uint8Array(d.buffer,d.byteOffset,d.byteLength))}),i.on("end",()=>{try{u.close()}catch{}}),i.on("error",d=>{try{u.error(d)}catch{}})},cancel(){c||(c=!0,i.destroy())}}),l=new WritableStream({write(u){return new Promise((d,p)=>{i.write(u,f=>f?p(f):d())})},close(){return new Promise(u=>{i.end(()=>u())})},abort(u){i.destroy(u)}});s({readable:a,writable:l,close:async()=>{c||(c=!0,i.destroy())}})});i.on("error",o)})}try{return(await import("cloudflare:sockets")).connect({hostname:r.hostname,port:r.port},{secureTransport:r.secureTransport||"off",allowHalfOpen:!1})}catch(n){throw new Error(`Socket connection failed in current environment: ${n}`)}}var kr=class extends Error{constructor(t,n,s,o){super(`Upstream HTTP ${t}${n?` ${n}`:""}`);this.status=t;this.statusText=n;this.responseBodySnippet=s;this.cfRay=o;this.name="UpstreamHttpError"}status;statusText;responseBodySnippet;cfRay};async function Ma(r,e=5e3){let t=[],n=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([r.read(),i]);if(a||!c)throw new Error("Socket closed before complete DNS response received");if(t.push(c),n+=c.length,n>65537)throw new Error("DNS upstream message exceeded maximum RFC frame length (65535 bytes)");if(s===null&&n>=2){let l=t[0][0],u=t[0].length>1?t[0][1]:t[1][0];s=l<<8|u}if(s!==null&&n>=2+s){let l=new Uint8Array(n),u=0;for(let d of t)l.set(d,u),u+=d.length;return l.slice(2,2+s)}}}finally{o!==void 0&&clearTimeout(o)}}function kn(r,e){let t=r,n=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(":")&&(n=parseInt(i.slice(1),10)||e)}}else if(t.includes(":")){let s=t.split(":");t=s[0],n=parseInt(s[1],10)||e}return{host:t,port:n}}function At(r){let e=r;if(r.startsWith("sdns://")){let t=Cn(r);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:n,port:s}=kn(t,853);return{effectiveUrl:`tls://${n}:${s}`,diagMethod:"DoQ",diagTarget:`quic://${n}:${s}`}}if(e.startsWith("tls://")){let t=e.replace(/^tls:\/\//,""),{host:n,port:s}=kn(t,853);return{effectiveUrl:e,diagMethod:"DoT",diagTarget:`tls://${n}:${s}`}}if(!e.startsWith("http://")&&!e.startsWith("https://")){let t=e.replace(/^(tcp|udp):\/\//,""),{host:n,port:s}=kn(t,53);return{effectiveUrl:e,diagMethod:"TCP",diagTarget:`tcp://${n}:${s}`}}return{effectiveUrl:e,diagMethod:"POST",diagTarget:e}}async function Dt(r,e){let{effectiveUrl:t,diagMethod:n,diagTarget:s}=r,o=Date.now(),i;if(t.startsWith("tls://")||t.startsWith("dot://")){let a=t.replace(/^(tls|dot):\/\//,""),{host:l,port:u}=kn(a,853),d=await wi({hostname:l,port:u,secureTransport:"on"});try{let p=d.writable.getWriter(),f=d.readable.getReader(),m=new Uint8Array(e.length+2);m[0]=e.length>>8&255,m[1]=e.length&255,m.set(e,2),await p.write(m),p.releaseLock(),i=await Ma(f,5e3)}finally{await d.close().catch(()=>{})}}else if(!t.startsWith("http://")&&!t.startsWith("https://")){let a=t.replace(/^(tcp|udp):\/\//,""),{host:l,port:u}=kn(a,53),d=await wi({hostname:l,port:u,secureTransport:"off"});try{let p=d.writable.getWriter(),f=d.readable.getReader(),m=new Uint8Array(e.length+2);m[0]=e.length>>8&255,m[1]=e.length&255,m.set(e,2),await p.write(m),p.releaseLock(),i=await Ma(f,5e3)}finally{await d.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 u="";try{u=(await a.text()).replace(/<[^>]*>?/gm," ").replace(/\s+/g," ").trim().slice(0,300)}catch{}let d=a.headers.get("cf-ray")||void 0;throw new kr(a.status,a.statusText,u,d)}let l=await a.arrayBuffer();i=new Uint8Array(l)}let c=Date.now()-o;return{answer:i,latency:c,diagMethod:n,diagTarget:s}}function Ba(r,e,t){let n,s=e.raw;if(t.ecs?.enabled){let o=r.headers.get("CF-Connecting-IP")||"127.0.0.1";n=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,n&&(s=ii(e.raw,n))}return{queryRaw:s,ecs:n}}async function Fa(r,e,t,n,s,o,i,c){let a=r.type==="HTTPS"||r.type==="SVCB"||r.type==="TYPE65"||r.type==="TYPE64",l=typeof s.best_effort_ech=="boolean"?s.best_effort_ech:!!s.best_effort_ech?.enabled,u=t,d=e,p=c;if(a){let f=(n.env.SERVERFULL_DOT_DOMAIN||n.env.DOT_DOMAIN||"").toLowerCase().trim(),m=r.name.toLowerCase().trim(),h=m.startsWith("_dns.")||!!(f&&(m===`_dns.${f}`||m.endsWith(`._dns.${f}`))),g=!!(f&&(m===f||m.endsWith(`.${f}`)));if(h||g){let b=n.env.SERVERFULL_ECH_FRONTING_DOMAIN||typeof s.best_effort_ech=="object"&&s.best_effort_ech?.fronting_domain||Ht,w=n.env.SERVERFULL_ECH_CONFIG||hn(b),y=n.env.SERVERFULL_HTTPS_PORT||n.env.HTTPS_PORT||10443,E=n.env.SERVERFULL_DOT_PORT||n.env.DOT_PORT||853;if(h){let _=r.type==="HTTPS"||r.type==="TYPE65"?"HTTPS":"SVCB",S=`1 . alpn=doq,dot port=${E} ech=${w}`;return u=_e(r.raw,_,S,300,0),d=ke(u),p="DDR SVCB (DoQ/DoT/H3/ECH)",{answer:u,parsedAnswers:d,effectiveReason:p}}if(g){let _=r.type==="SVCB"||r.type==="TYPE64"?"SVCB":"HTTPS",S=`1 . alpn=h3,h2 port=${y} ech=${w}`;return u=_e(r.raw,_,S,300,0),d=ke(u),p="Server HTTPS (H3/ECH)",{answer:u,parsedAnswers:d,effectiveReason:p}}}if(l){await Aa(n.env.DB);let b=[],w=[],y;for(let _ of d){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 R=_.data.match(/ech=([A-Za-z0-9+/=]+)/);R&&(y=R[1])}let E=b.some(bs)||w.some(bs);if(!E)try{let _=Kt(r.name,"A"),S=await i(o,{name:r.name,type:"A",raw:_},n,s,"PASS");if(S.answer&&S.answer.length>0){let x=ke(S.answer);for(let R of x)R.type==="A"&&(b.push(R.data),bs(R.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:Ht,S=hn(_,y),x=r.type==="SVCB"||r.type==="TYPE64"?"SVCB":"HTTPS",R=["alpn=h3,h2"];b.length>0&&R.push(`ipv4hint=${Array.from(new Set(b)).join(",")}`),R.push(`ech=${S}`),w.length>0&&R.push(`ipv6hint=${Array.from(new Set(w)).join(",")}`);let D=`1 . ${R.join(" ")}`;u=_e(r.raw,x,D,300,0),d=ke(u),p="ECH Rewritten"}}}return{answer:u,parsedAnswers:d,effectiveReason:p}}ge();var Jt=new Map,Ha=336*60*60*1e3;async function Ln(r){if(!tt(r))return null;let e=`geoip:${r}`,t=Date.now(),n=Jt.get(e);if(n){if(t<n.expiresAt)return n.data;Jt.delete(e)}let s=null;if(typeof caches<"u"&&caches.default&&(s=caches.default),s)try{let i=await v.get(s,e);if(i)return Jt.set(e,{data:i,expiresAt:t+Ha}),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+Ha}),s)try{await v.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/${r}?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/${r}`);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 Gt(r,e){let t=r.cf?.country||r.headers.get("CF-IPCountry");if(t&&t!=="UN"&&t!=="UNKNOWN"&&t!=="XX")return t.toUpperCase();if(!tt(e))return"LAN";try{let n=await Ln(e);if(n?.country_code)return n.country_code.toUpperCase()}catch{}return"UNKNOWN"}var Vu=0;function On(){let r=Vu++%1e3;return Date.now()*1e3+r}var Os=class{constructor(e){this.db=e}db;createInsertStatement(e){let t=e.id??On();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 n="";t.export?n=`
|
|
257
|
+
`).bind(e,e,e).first()||null}catch(t){return console.warn("[ProfileModel] findByKey query failed:",t.message||t),null}}async list(e,t){let{results:n}=await this.db.prepare(`SELECT * FROM profiles ${e}`).bind(...t).all();return n}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),n=j(12),s=5;for(let o=0;o<s;o++){let i=Wt(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(n,e.id,"Device-1",i,t,t)];try{return(await this.db.batch(a)).every(u=>u.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(n=>n.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(n=>n.success)}async updateName(e,t){let n=Math.floor(Date.now()/1e3);return(await this.db.prepare("UPDATE profiles SET name = ?, updated_at = ? WHERE id = ?").bind(t,n,e).run()).success}async updateSettings(e,t){let n=Math.floor(Date.now()/1e3);return(await this.db.prepare("UPDATE profiles SET settings = ?, updated_at = ? WHERE id = ?").bind(JSON.stringify(t),n,e).run()).success}async rotateKey(e,t){let n=Math.floor(Date.now()/1e3);return(await this.db.prepare("UPDATE profiles SET profile_key = ?, updated_at = ? WHERE id = ?").bind(t,n,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:n}=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 n}async updateListUpdatedAt(e,t){return(await this.db.prepare("UPDATE profiles SET list_updated_at = ? WHERE id = ?").bind(t,e).run()).success}};var Cr=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 n=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,n,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 n=Math.floor(Date.now()/1e3),s=t.map(i=>{let c=i.pattern?i.pattern.trim().toLowerCase():"",a=i.created_at??n;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,n){let s=n.pattern?n.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(n.type,s,n.v_a||null,n.v_aaaa||null,n.v_txt||null,n.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,n){return await this.db.prepare("SELECT * FROM rules WHERE profile_id = ? AND LOWER(pattern) = ? AND id != ?").bind(e,t.trim().toLowerCase(),n).first()}async deleteRule(e,t){return(await this.db.prepare("DELETE FROM rules WHERE id = ? AND profile_id = ?").bind(e,t).run()).success}};var Te=class r{size;hashes;bitArray;static FNV_PRIME=16777619;static FNV_SEED_0=2166136261;static encoder=new TextEncoder;constructor(e,t,n){this.size=e>>>0,this.hashes=t>>>0;let s=this.size+31>>>5;this.bitArray=n||new Uint32Array(s)}static create(e,t=1e-4){let n=Math.max(e,100),o=Math.ceil(-(n*Math.log(t))/Math.log(2)**2),i=Math.round(o/n*Math.log(2));return new r(o,i)}add(e){let t=r.FNV_SEED_0,n=e.length;for(let a=0;a<n;a++)t^=e.charCodeAt(a)&255,t=Math.imul(t,r.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=r.FNV_SEED_0,n=e.length;for(let a=0;a<n;a++)t^=e.charCodeAt(a)&255,t=Math.imul(t,r.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),n=t.getUint32(0,!0),s=t.getUint32(4,!0);if(n===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=n+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 u=new Uint8Array(c<<2);u.set(e.subarray(8,8+(c<<2))),l=new Uint32Array(u.buffer,0,c)}return new r(n,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,n=e.bitArray,s=t.length;for(let o=0;o<s;o++)t[o]|=n[o]}fnv1a(e,t){let n=t>>>0;for(let s=0;s<e.length;s++)n^=e[s],n=Math.imul(n,r.FNV_PRIME);return n>>>0}fnv1aString(e,t){let n=t>>>0,s=e.length;for(let o=0;o<s;o++)n^=e.charCodeAt(o)&255,n=Math.imul(n,r.FNV_PRIME);return n>>>0}dump(){let e=new Uint8Array(this.bitArray.buffer,this.bitArray.byteOffset,this.bitArray.byteLength),t="",n=e.byteLength,s=32768;for(let o=0;o<n;o+=s)t+=String.fromCharCode.apply(null,e.subarray(o,Math.min(o+s,n)));return{size:this.size,hashes:this.hashes,data:btoa(t)}}static load(e){let t=atob(e.data),n=new Uint8Array(t.length);for(let i=0;i<t.length;i++)n[i]=t.charCodeAt(i);let s=n.length+3>>2,o=new Uint32Array(s);return new Uint8Array(o.buffer).set(n),new r(e.size,e.hashes,o)}};var Tt=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,n){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,n)),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 n=t.reduce((i,c)=>{let a=c.bloom_filter_chunk.byteLength??c.bloom_filter_chunk.length;return i+a},0),s=new Uint8Array(n),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,n,s){let i=Te.create(t,n).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,n){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,n)),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 n=t.reduce((i,c)=>{let a=c.bloom_filter_chunk.byteLength??c.bloom_filter_chunk.length;return i+a},0),s=new Uint8Array(n),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:n}=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(!n||n.length===0)return await this.clearProfileBlooms(e),!0;let s=[this.db.prepare("DELETE FROM profile_blooms WHERE profile_id = ?").bind(e),...n.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 Oa={async load(r,e){let{profileId:t,env:n,ctx:s}=r;if(t==="default")return{settings:{upstream:[n.FAIL_OPEN_UPSTREAM||De],default_policy:"ALLOW",log_retention_days:0,ecs:{enabled:!0,use_client_ip:!0}},rules:[],bloom:void 0};let o=bn.get(t),i=En.get(t),c=Number(n.BLOOM_MEM_TTL)||6e5,a=Number(n.CONFIG_MEM_TTL)||3e5,l=Number.isFinite(a)&&a>0?a:3e5;if(i&&Date.now()-(i.timestamp||0)<l){e("load_config_l1_mem");let h=o&&Date.now()-o.ts<c?o.bloom:void 0;return{...i,bloom:h}}let u=caches.default,d=`profile_v6:${t}`,p=v.generateCacheUrl(`bloom-bin:${t}`),f=await v.get(u,d),m;if(f){if(e("load_config_l2_cache"),o&&Date.now()-o.ts<c)m=o.bloom;else try{let h=await u.match(p);if(h){e("load_bloom_l2_cache");let g=await h.arrayBuffer();m=Te.fromUint8Array(new Uint8Array(g)),bn.set(t,{bloom:m,ts:Date.now()})}}catch{}return En.set(t,{...f,timestamp:Date.now()}),{...f,bloom:m}}try{let h=new q(n.DB),g=new Cr(n.DB),w=new Tt(n.DB),[b,y,E]=await Promise.all([h.getById(t),g.getRules(t),w.getProfileBloom(t).catch(x=>(console.error("[Config] D1 Bloom loading failed:",x),null))]);if(!b)return i?(console.warn(`[Config] Profile ${t} not in D1, using stale memory config.`),{...i,bloom:o?.bloom}):null;let _=JSON.parse(b.settings);if(E){e("load_bloom_l3_d1");let x=new Uint8Array(E);m=Te.fromUint8Array(x),s.waitUntil(u.put(p,new Response(x,{headers:{"Content-Type":"application/octet-stream","Cache-Control":"public, max-age=604800","Cache-Tag":`bloom-${t}`}})))}let S={settings:_,rules:y};return m&&bn.set(t,{bloom:m,ts:Date.now()}),En.set(t,{...S,timestamp:Date.now()}),s.waitUntil(v.set(u,d,S,86400,[`profile-${t}`])),e("load_config_full_sync"),{...S,bloom:m}}catch(h){return console.warn(`[Config] D1 profile fetch failed for ${t}:`,h?.message||h),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:[n.FAIL_OPEN_UPSTREAM||De],default_policy:"ALLOW",log_retention_days:0,ecs:{enabled:!0,use_client_ip:!0}},rules:[],bloom:void 0})}}};function Cn(r){let e=r.trim();if(!e.startsWith("sdns://"))throw new Error("Invalid DNS Stamp: must start with sdns://");let t=e.slice(7),n=t.length;for(;n>0&&t.charCodeAt(n-1)===61;)n--;let s=t.slice(0,n),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 u=()=>{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)},d=()=>{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},p="unknown",f,m,h,g,w,b="";switch(a){case 0:{p="dns",f=u(),f&&(b=f.includes(":")&&!f.startsWith("[")?`tcp://${f}`:`tcp://${f}:53`);break}case 1:{p="dnscrypt",f=u(),c+=32,w=u(),b=`dnscrypt://${w||f}`;break}case 2:{p="doh",f=u(),g=d(),m=u(),h=u()||"/dns-query";let y=m||f;h.startsWith("/")||(h=`/${h}`),b=`https://${y}${h}`;break}case 3:{p="dot",f=u(),g=d(),m=u();let y=m||f,E=f&&f.includes(":")?f.split(":").pop():"853";b=y?.includes(":")?`tls://${y}`:`tls://${y}:${E}`;break}case 4:{p="doq",f=u(),g=d(),m=u(),b=`quic://${m||f}:853`;break}case 5:{p="odoh",f=u(),g=d(),m=u(),h=u()||"/dns-query",b=`https://${m||f}${h}`;break}default:b=e;break}return{protocol:p,protocolId:a,props:l,serverAddress:f||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 Rt=/^[a-zA-Z\d~`!@#$%^&*()_\-+={[}\]|\\:;"'<,>.?\/]{12,100}$/,xt=/^[a-z_][a-z0-9_-]{4,31}$/,mi=/^[a-zA-Z0-9_-]{1,30}$/,hi=/^[a-zA-Z0-9_-]{1,30}$/;var gi=/^[\p{L}\p{N}_ ()-]{1,30}$/u,Vt=/^[a-zA-Z0-9]{5,12}$/,Ia=/^\d{6}$/,Na=["localhost","metadata.google.internal","metadata.goog","169.254.169.254","instance-data","localtest.me"],$u=[".localhost",".local",".internal",".lan",".home.arpa",".corp",".home",".localtest.me"];function Ku(r){let e=r.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=r.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 Wu=["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"],fi=ys(Wu);function rt(r){if(!r||typeof r!="string")return!1;let e=r.trim();if(e.startsWith("[")&&e.endsWith("]")&&(e=e.slice(1,-1)),e.includes(":")&&e.includes(".")){let n=e.lastIndexOf(":"),s=e.substring(n+1);return at(s)?!fi(s):!1}if(!at(e)&&!$t(e))return!1;let t=gn(e);if(t!==null&&t>>32n===0xffffn){let n=Number(t&0xffffffffn),s=`${n>>>24&255}.${n>>>16&255}.${n>>>8&255}.${n&255}`;return!fi(s)}return!fi(e)}function ut(r){try{if(r.startsWith("sdns://")){let o=Cn(r);return ut(o.resolvedUrl)}let e;r.startsWith("tcp://")||r.startsWith("udp://")?e=r.replace(/^(tcp|udp):\/\//,"http://"):r.startsWith("tls://")||r.startsWith("dot://")?e=r.replace(/^(tls|dot):\/\//,"http://"):r.startsWith("http://")||r.startsWith("https://")?e=r:e=`http://${r}`;let t=new URL(e),n=t.hostname.replace(/^\[|\]$/g,"").toLowerCase();if(Na.includes(n)||Na.includes(t.hostname.toLowerCase()))return!1;for(let o of $u)if(n.endsWith(o)||n===o.slice(1))return!1;if(n.includes("metadata.google"))return!1;let s=Ku(n);return!(s&&!rt(s)||(at(n)||$t(n))&&!rt(n)||t.hostname.includes("@")||t.username||t.password)}catch{return!1}}async function Ua(r){if(!ut(r))return!1;if(typeof process<"u"&&process.versions?.node)try{let e=r;r.startsWith("sdns://")&&(e=Cn(r).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(at(s)||$t(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(!rt(c.address))return!1}catch{return!1}return!0}async function yi(r){if(!(typeof navigator<"u"&&navigator.userAgent==="Cloudflare-Workers"||typeof WebSocketPair<"u")&&typeof process<"u"&&!!process.versions?.node){if(r.secureTransport==="on"){let s=await import("node:tls"),o=await import("node:net");return new Promise((i,c)=>{let a=s.connect({host:r.hostname,port:r.port,servername:o.isIP(r.hostname)?void 0:r.hostname},()=>{let l=!1,u=new ReadableStream({start(p){a.on("data",f=>{p.enqueue(new Uint8Array(f.buffer,f.byteOffset,f.byteLength))}),a.on("end",()=>{try{p.close()}catch{}}),a.on("error",f=>{try{p.error(f)}catch{}})},cancel(){l||(l=!0,a.destroy())}}),d=new WritableStream({write(p){return new Promise((f,m)=>{a.write(p,h=>h?m(h):f())})},close(){return new Promise(p=>{a.end(()=>p())})},abort(p){a.destroy(p)}});i({readable:u,writable:d,close:async()=>{l||(l=!0,a.destroy())}})});a.on("error",c)})}let n=await import("node:net");return new Promise((s,o)=>{let i=n.createConnection({host:r.hostname,port:r.port},()=>{let c=!1,a=new ReadableStream({start(u){i.on("data",d=>{u.enqueue(new Uint8Array(d.buffer,d.byteOffset,d.byteLength))}),i.on("end",()=>{try{u.close()}catch{}}),i.on("error",d=>{try{u.error(d)}catch{}})},cancel(){c||(c=!0,i.destroy())}}),l=new WritableStream({write(u){return new Promise((d,p)=>{i.write(u,f=>f?p(f):d())})},close(){return new Promise(u=>{i.end(()=>u())})},abort(u){i.destroy(u)}});s({readable:a,writable:l,close:async()=>{c||(c=!0,i.destroy())}})});i.on("error",o)})}try{return(await import("cloudflare:sockets")).connect({hostname:r.hostname,port:r.port},{secureTransport:r.secureTransport||"off",allowHalfOpen:!1})}catch(n){throw new Error(`Socket connection failed in current environment: ${n}`)}}var kr=class extends Error{constructor(t,n,s,o){super(`Upstream HTTP ${t}${n?` ${n}`:""}`);this.status=t;this.statusText=n;this.responseBodySnippet=s;this.cfRay=o;this.name="UpstreamHttpError"}status;statusText;responseBodySnippet;cfRay};async function Ma(r,e=5e3){let t=[],n=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([r.read(),i]);if(a||!c)throw new Error("Socket closed before complete DNS response received");if(t.push(c),n+=c.length,n>65537)throw new Error("DNS upstream message exceeded maximum RFC frame length (65535 bytes)");if(s===null&&n>=2){let l=t[0][0],u=t[0].length>1?t[0][1]:t[1][0];s=l<<8|u}if(s!==null&&n>=2+s){let l=new Uint8Array(n),u=0;for(let d of t)l.set(d,u),u+=d.length;return l.slice(2,2+s)}}}finally{o!==void 0&&clearTimeout(o)}}function kn(r,e){let t=r,n=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(":")&&(n=parseInt(i.slice(1),10)||e)}}else if(t.includes(":")){let s=t.split(":");t=s[0],n=parseInt(s[1],10)||e}return{host:t,port:n}}function At(r){let e=r;if(r.startsWith("sdns://")){let t=Cn(r);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:n,port:s}=kn(t,853);return{effectiveUrl:`tls://${n}:${s}`,diagMethod:"DoQ",diagTarget:`quic://${n}:${s}`}}if(e.startsWith("tls://")){let t=e.replace(/^tls:\/\//,""),{host:n,port:s}=kn(t,853);return{effectiveUrl:e,diagMethod:"DoT",diagTarget:`tls://${n}:${s}`}}if(!e.startsWith("http://")&&!e.startsWith("https://")){let t=e.replace(/^(tcp|udp):\/\//,""),{host:n,port:s}=kn(t,53);return{effectiveUrl:e,diagMethod:"TCP",diagTarget:`tcp://${n}:${s}`}}return{effectiveUrl:e,diagMethod:"POST",diagTarget:e}}async function Dt(r,e){let{effectiveUrl:t,diagMethod:n,diagTarget:s}=r,o=Date.now(),i;if(t.startsWith("tls://")||t.startsWith("dot://")){let a=t.replace(/^(tls|dot):\/\//,""),{host:l,port:u}=kn(a,853),d=await yi({hostname:l,port:u,secureTransport:"on"});try{let p=d.writable.getWriter(),f=d.readable.getReader(),m=new Uint8Array(e.length+2);m[0]=e.length>>8&255,m[1]=e.length&255,m.set(e,2),await p.write(m),p.releaseLock(),i=await Ma(f,5e3)}finally{await d.close().catch(()=>{})}}else if(!t.startsWith("http://")&&!t.startsWith("https://")){let a=t.replace(/^(tcp|udp):\/\//,""),{host:l,port:u}=kn(a,53),d=await yi({hostname:l,port:u,secureTransport:"off"});try{let p=d.writable.getWriter(),f=d.readable.getReader(),m=new Uint8Array(e.length+2);m[0]=e.length>>8&255,m[1]=e.length&255,m.set(e,2),await p.write(m),p.releaseLock(),i=await Ma(f,5e3)}finally{await d.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 u="";try{u=(await a.text()).replace(/<[^>]*>?/gm," ").replace(/\s+/g," ").trim().slice(0,300)}catch{}let d=a.headers.get("cf-ray")||void 0;throw new kr(a.status,a.statusText,u,d)}let l=await a.arrayBuffer();i=new Uint8Array(l)}let c=Date.now()-o;return{answer:i,latency:c,diagMethod:n,diagTarget:s}}function Ba(r,e,t){let n,s=e.raw;if(t.ecs?.enabled){let o=r.headers.get("CF-Connecting-IP")||"127.0.0.1";n=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,n&&(s=oi(e.raw,n))}return{queryRaw:s,ecs:n}}async function Fa(r,e,t,n,s,o,i,c){let a=r.type==="HTTPS"||r.type==="SVCB"||r.type==="TYPE65"||r.type==="TYPE64",l=typeof s.best_effort_ech=="boolean"?s.best_effort_ech:!!s.best_effort_ech?.enabled,u=t,d=e,p=c;if(a){let f=(n.env.SERVERFULL_DOT_DOMAIN||n.env.DOT_DOMAIN||"").toLowerCase().trim(),m=r.name.toLowerCase().trim(),h=m.startsWith("_dns.")||!!(f&&(m===`_dns.${f}`||m.endsWith(`._dns.${f}`))),g=!!(f&&(m===f||m.endsWith(`.${f}`)));if(h||g){let w=n.env.SERVERFULL_ECH_FRONTING_DOMAIN||typeof s.best_effort_ech=="object"&&s.best_effort_ech?.fronting_domain||Ht,b=n.env.SERVERFULL_ECH_CONFIG||hn(w),y=n.env.SERVERFULL_HTTPS_PORT||n.env.HTTPS_PORT||10443,E=n.env.SERVERFULL_DOT_PORT||n.env.DOT_PORT||853;if(h){let _=r.type==="HTTPS"||r.type==="TYPE65"?"HTTPS":"SVCB",S=`1 . alpn=doq,dot port=${E} ech=${b}`;return u=_e(r.raw,_,S,300,0),d=Le(u),p="DDR SVCB (DoQ/DoT/H3/ECH)",{answer:u,parsedAnswers:d,effectiveReason:p}}if(g){let _=r.type==="SVCB"||r.type==="TYPE64"?"SVCB":"HTTPS",S=`1 . alpn=h3,h2 port=${y} ech=${b}`;return u=_e(r.raw,_,S,300,0),d=Le(u),p="Server HTTPS (H3/ECH)",{answer:u,parsedAnswers:d,effectiveReason:p}}}if(l){await Aa(n.env.DB);let w=[],b=[],y;for(let _ of d){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 R=_.data.match(/ech=([A-Za-z0-9+/=]+)/);R&&(y=R[1])}let E=w.some(bs)||b.some(bs);if(!E)try{let _=Kt(r.name,"A"),S=await i(o,{name:r.name,type:"A",raw:_},n,s,"PASS");if(S.answer&&S.answer.length>0){let x=Le(S.answer);for(let R of x)R.type==="A"&&(w.push(R.data),bs(R.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:Ht,S=hn(_,y),x=r.type==="SVCB"||r.type==="TYPE64"?"SVCB":"HTTPS",R=["alpn=h3,h2"];w.length>0&&R.push(`ipv4hint=${Array.from(new Set(w)).join(",")}`),R.push(`ech=${S}`),b.length>0&&R.push(`ipv6hint=${Array.from(new Set(b)).join(",")}`);let D=`1 . ${R.join(" ")}`;u=_e(r.raw,x,D,300,0),d=Le(u),p="ECH Rewritten"}}}return{answer:u,parsedAnswers:d,effectiveReason:p}}ge();var Jt=new Map,Ha=336*60*60*1e3;async function Ln(r){if(!rt(r))return null;let e=`geoip:${r}`,t=Date.now(),n=Jt.get(e);if(n){if(t<n.expiresAt)return n.data;Jt.delete(e)}let s=null;if(typeof caches<"u"&&caches.default&&(s=caches.default),s)try{let i=await v.get(s,e);if(i)return Jt.set(e,{data:i,expiresAt:t+Ha}),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+Ha}),s)try{await v.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/${r}?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/${r}`);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 Gt(r,e){let t=r.cf?.country||r.headers.get("CF-IPCountry");if(t&&t!=="UN"&&t!=="UNKNOWN"&&t!=="XX")return t.toUpperCase();if(!rt(e))return"LAN";try{let n=await Ln(e);if(n?.country_code)return n.country_code.toUpperCase()}catch{}return"UNKNOWN"}var ju=0;function On(){let r=ju++%1e3;return Date.now()*1e3+r}var Os=class{constructor(e){this.db=e}db;createInsertStatement(e){let t=e.id??On();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 n="";t.export?n=`
|
|
258
258
|
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
|
|
259
259
|
FROM logs l
|
|
260
260
|
LEFT JOIN kem_keys k ON l.kem_key_id = k.id
|
|
@@ -299,11 +299,11 @@ SQL: ${this.sql}`),t}}},zo=class{constructor(e,t){this.rawDb=e;this.dbPath=t}raw
|
|
|
299
299
|
AND NOT EXISTS (
|
|
300
300
|
SELECT 1 FROM logs l WHERE l.kem_key_id = kem_keys.id AND l.kem_key_id IS NOT NULL
|
|
301
301
|
)
|
|
302
|
-
`).bind(e,n).run();return o.meta?.changes??o.meta?.rows_written??0}catch(s){return console.error(`[KemKeyModel] Failed to cleanup profile orphan kem_keys for ${e}:`,s),0}}};var Is=class{constructor(e,t){this.db=e;this.settingsModel=t??new de(e)}db;settingsModel;async cleanupGlobal(e=30,t=1e3,n=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(n>0)try{let h=await this.settingsModel.get("log_cleanup_daily_date"),g=await this.settingsModel.get("log_cleanup_daily_count");h===o&&g&&(i=parseInt(g,10)||0)}catch(h){console.warn("[LogRetentionModel] Failed to read daily cleanup settings:",h)}let c=n>0?Math.max(0,n-i):t,a=n<=0||c>0;n>0&&c<=0&&console.log(`[LogRetentionModel] cleanupGlobal: daily budget reached (${i}/${n}), skipping raw log deletion for today (${o})`);let l=n>0?Math.min(t,c):t,u=Math.max(1,Math.floor(l/s.length)),d=[];for(let h of s){let g=30;try{let y=JSON.parse(h.settings);y?.log_retention_days!=null&&(g=Number(y.log_retention_days))}catch{}let
|
|
302
|
+
`).bind(e,n).run();return o.meta?.changes??o.meta?.rows_written??0}catch(s){return console.error(`[KemKeyModel] Failed to cleanup profile orphan kem_keys for ${e}:`,s),0}}};var Is=class{constructor(e,t){this.db=e;this.settingsModel=t??new de(e)}db;settingsModel;async cleanupGlobal(e=30,t=1e3,n=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(n>0)try{let h=await this.settingsModel.get("log_cleanup_daily_date"),g=await this.settingsModel.get("log_cleanup_daily_count");h===o&&g&&(i=parseInt(g,10)||0)}catch(h){console.warn("[LogRetentionModel] Failed to read daily cleanup settings:",h)}let c=n>0?Math.max(0,n-i):t,a=n<=0||c>0;n>0&&c<=0&&console.log(`[LogRetentionModel] cleanupGlobal: daily budget reached (${i}/${n}), skipping raw log deletion for today (${o})`);let l=n>0?Math.min(t,c):t,u=Math.max(1,Math.floor(l/s.length)),d=[];for(let h of s){let g=30;try{let y=JSON.parse(h.settings);y?.log_retention_days!=null&&(g=Number(y.log_retention_days))}catch{}let w=Math.min(g,e),b=Math.floor(Date.now()/1e3-w*24*3600);a&&l>0&&d.push(this.db.prepare(`
|
|
303
303
|
DELETE FROM logs WHERE (profile_id, timestamp, id) IN (
|
|
304
304
|
SELECT profile_id, timestamp, id FROM logs WHERE profile_id = ? AND timestamp < ? LIMIT ?
|
|
305
305
|
)
|
|
306
|
-
`).bind(h.id,
|
|
306
|
+
`).bind(h.id,b,u))}let p=50,f=0;if(d.length>0){for(let h=0;h<d.length;h+=p){let g=d.slice(h,h+p),w=await this.db.batch(g);if(Array.isArray(w))for(let b of w)b?.meta?.changes!==void 0?f+=b.meta.changes:b?.meta?.rows_written!==void 0&&(f+=b.meta.rows_written)}if(n>0){let h=i+f;try{await this.settingsModel.setMany({log_cleanup_daily_date:o,log_cleanup_daily_count:String(h)})}catch(g){console.warn("[LogRetentionModel] Failed to persist daily cleanup count:",g)}}}let m=!1;try{await this.settingsModel.get("kem_orphan_cleanup_date")!==o&&(m=!0)}catch{}if(f>0||m)try{let g=await new Lr(this.db).cleanupOrphans(86400,100);m&&await this.settingsModel.set("kem_orphan_cleanup_date",o).catch(()=>{}),g>0&&console.log(`[LogRetentionModel] Cleaned up ${g} orphaned kem_keys with zero referencing logs.`)}catch(h){console.warn("[LogRetentionModel] Failed to cleanup orphaned kem_keys:",h)}console.log(`[LogRetentionModel] cleanupGlobal: processed ${s.length} profile(s), maxRetentionDays=${e}d, batchLimit=${t} (effective=${l}, perProfile=${u}), dailyBudget=${n} (today: ${i+f}/${n})`)}catch(s){console.error("[LogRetentionModel] cleanupGlobal failed:",s.message||s)}}};var Us=class{constructor(e){this.db=e}db;async getSummary(e,t,n,s,o){let i="SELECT action, COUNT(*) as count FROM logs WHERE profile_id = ? AND timestamp >= ? AND timestamp <= ?",c=[e,t,n];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,n,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,n];o&&(a+=" AND access_point_id = ?",l.push(o)),a+=` GROUP BY ${c}, action ORDER BY timestamp ASC`;let{results:u}=await this.db.prepare(a).bind(...l).all();return u}};var Ms=class{constructor(e){this.db=e}db;async getTopAllowed(e,t,n,s){let o="SELECT domain, COUNT(*) as count FROM logs WHERE profile_id = ? AND timestamp >= ? AND timestamp <= ? AND action = 'PASS'",i=[e,t,n];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,n,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,n];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 Bs=class{constructor(e){this.db=e}db;async getClients(e,t,n,s){let o="SELECT client_ip, geo_country, COUNT(*) as count FROM logs WHERE profile_id = ? AND timestamp >= ? AND timestamp <= ?",i=[e,t,n];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 Fs=class{constructor(e){this.db=e}db;async getDestinations(e,t,n,s,o=250){let i=`
|
|
307
307
|
SELECT
|
|
308
308
|
COALESCE(dest_country_code, json_extract(dest_geoip, '$.country_code')) as country_code,
|
|
309
309
|
COALESCE(dest_country, json_extract(dest_geoip, '$.country')) as country,
|
|
@@ -321,7 +321,7 @@ SQL: ${this.sql}`),t}}},zo=class{constructor(e,t){this.rawDb=e;this.dbPath=t}raw
|
|
|
321
321
|
AND (dest_country_code IS NOT NULL OR dest_geoip IS NOT NULL)
|
|
322
322
|
AND COALESCE(dest_isp, json_extract(dest_geoip, '$.isp')) IS NOT NULL
|
|
323
323
|
AND COALESCE(dest_isp, json_extract(dest_geoip, '$.isp')) != ''
|
|
324
|
-
`,a=[e,n,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(u=>({name:u.name||"Unknown",count:u.count}))}};var Hs=class{constructor(e,t){this.db=e;this.traffic=new Us(e),this.domains=new Ms(e),this.clients=new Bs(e),this.destinations=new Fs(e)}db;traffic;domains;clients;destinations;async getSummary(e,t,n,s,o){return this.traffic.getSummary(e,t,n,s,o)}async getTrend(e,t,n,s,o){return this.traffic.getTrend(e,t,n,s,o)}async getTopAllowed(e,t,n,s){return this.domains.getTopAllowed(e,t,n,s)}async getTopBlocked(e,t,n,s){return this.domains.getTopBlocked(e,t,n,s)}async getClients(e,t,n,s){return this.clients.getClients(e,t,n,s)}async getDestinations(e,t,n,s,o=250){return this.destinations.getDestinations(e,t,n,s,o)}async getISPByCountry(e,t,n,s,o,i=250){return this.destinations.getISPByCountry(e,t,n,s,o,i)}async getAnalytics(e,t,n,s,o){let[i,c,a,l,u,d]=await Promise.all([this.getSummary(e,t,n,void 0,o),this.getTrend(e,t,n,s,o),this.getTopAllowed(e,t,n,o),this.getTopBlocked(e,t,n,o),this.getClients(e,t,n,o),this.getDestinations(e,t,n,o)]);return{summary:i,trend:c,top_allowed:a,top_blocked:l,clients:u,destinations:d}}};var Ie=class{constructor(e){this.db=e;this.core=new Os(e),this.aggregation=new Ns(e),this.retention=new Is(e),this.analytics=new Hs(e,this.aggregation),this.kemKeys=new Lr(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,n){return this.core.getLog(e,t,n)}async deleteByOwner(e){return this.core.deleteByOwner(e)}async cleanup(e,t,n=1e3){return this.core.cleanup(e,t,n)}async cleanupGlobal(e=30,t=1e3,n=2e4){return this.retention.cleanupGlobal(e,t,n)}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,n=2){return this.aggregation.aggregateHourlyRollups(e,t,n)}async getSummary(e,t,n,s,o){return this.analytics.getSummary(e,t,n,s,o)}async getTrend(e,t,n,s,o){return this.analytics.getTrend(e,t,n,s,o)}async getTopAllowed(e,t,n,s){return this.analytics.getTopAllowed(e,t,n,s)}async getTopBlocked(e,t,n,s){return this.analytics.getTopBlocked(e,t,n,s)}async getClients(e,t,n,s){return this.analytics.getClients(e,t,n,s)}async getDestinations(e,t,n,s,o=250){return this.analytics.getDestinations(e,t,n,s,o)}async getISPByCountry(e,t,n,s,o,i=250){return this.analytics.getISPByCountry(e,t,n,s,o,i)}async getAnalytics(e,t,n,s,o){return this.analytics.getAnalytics(e,t,n,s,o)}};ge();function Yt(r){let e=r instanceof Uint8Array?r:new Uint8Array(r);if(typeof Buffer<"u")return Buffer.from(e).toString("base64");let t="";for(let n=0;n<e.length;n++)t+=String.fromCharCode(e[n]);return btoa(t)}function $s(r){if(typeof Buffer<"u")return new Uint8Array(Buffer.from(r,"base64"));let e=atob(r),t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n);return t}async function Ka(r,e){let t=crypto.subtle,n=await t.generateKey({name:"ECDH",namedCurve:"P-256"},!0,["deriveKey"]),s=await t.importKey("jwk",r,{name:"ECDH",namedCurve:"P-256"},!1,[]),o=await t.deriveKey({name:"ECDH",public:s,$public:s},n.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),u={ephem_pk:await t.exportKey("jwk",n.publicKey),iv:Yt(i),ciphertext:Yt(a)};return JSON.stringify(u)}function Xt(r){return r instanceof Uint8Array||ArrayBuffer.isView(r)&&r.constructor.name==="Uint8Array"&&"BYTES_PER_ELEMENT"in r&&r.BYTES_PER_ELEMENT===1}var Ks=r=>r?`"${r}" `:"";function le(r,e=""){if(typeof r!="number")throw new TypeError(Ks(e)+"expected number, got "+typeof r);if(!Number.isSafeInteger(r)||r<0)throw new RangeError(Ks(e)+"expected integer >= 0, got "+r);return r}function Va(r,e=""){if(typeof r!="boolean")throw new TypeError(Ks(e)+"expected boolean, got type="+typeof r);return r}function Y(r,e,t=""){if(Xt(r)&&(e===void 0||r.length===e))return r;e!==void 0&&le(e,"length");let n=Xt(r),s=e!==void 0?` of length ${e}`:"",o=n?`length=${r.length}`:`type=${typeof r}`,i=Ks(t)+"expected Uint8Array"+s+", got "+o;throw n?new RangeError(i):new TypeError(i)}function Or(r){if(typeof r!="function"||typeof r.create!="function")throw new TypeError("expected hash wrapped by utils.createHasher");if(le(r.outputLen),le(r.blockLen),r.outputLen<1||r.blockLen<1)throw new Error("hash blockLen / outputLen must be >= 1")}var Gu=(r,e)=>{if(r===null||typeof r!="object"||Array.isArray(r))throw new TypeError((e==="object"?"":`"${e}" `)+"expected object, got type="+typeof r)},Wa=(r,e)=>{Gu(r,e);let t=Object.getPrototypeOf(r);if(t!==Object.prototype&&t!==null)throw new TypeError(`"${e}" expected plain object`);if(Object.hasOwn(r,"__proto__"))throw new TypeError(`"${e}.__proto__" is not allowed`)};function ut(r,e=!0){if(r.destroyed)throw new Error("hash was destroyed");if(e&&r.finished)throw new Error("digest() was already called")}function Nr(r,e){Y(r,void 0,"output");let t=e.outputLen;if(!(r.length>=t))throw new RangeError('"output" expected length >= '+t)}function In(r){return new Uint32Array(r.buffer,r.byteOffset,Math.floor(r.byteLength/4))}function vt(...r){for(let e=0;e<r.length;e++)r[e].fill(0)}function Ws(r){return new DataView(r.buffer,r.byteOffset,r.byteLength)}function Ke(r,e){return r<<32-e|r>>>e}var Ja=new Uint8Array(new Uint32Array([287454020]).buffer)[0]===68;function Yu(r){return r<<24&4278190080|r<<8&16711680|r>>>8&65280|r>>>24&255}function Xu(r){for(let e=0;e<r.length;e++)r[e]=Yu(r[e]);return r}var Ir=Ja?r=>r:Xu,Ga=typeof Uint8Array.from([]).toHex=="function"&&typeof Uint8Array.fromHex=="function",zu=Array.from({length:256},(r,e)=>e.toString(16).padStart(2,"0"));function Un(r){if(Y(r),Ga)return r.toHex();let e="";for(let t=0;t<r.length;t++)e+=zu[r[t]];return e}function ja(r){return r>=48&&r<=57?r-48:r>=65&&r<=70?r-55:r>=97&&r<=102?r-87:void 0}function bi(r){if(typeof r!="string")throw new TypeError("hex string expected, got "+typeof r);if(Ga)try{return Uint8Array.fromHex(r)}catch(s){throw s instanceof SyntaxError?new RangeError(s.message):s}let e=r.length,t=e/2;if(e%2)throw new RangeError("hex string expected, got unpadded hex of length "+e);let n=new Uint8Array(t);for(let s=0,o=0;s<t;s++,o+=2){let i=ja(r.charCodeAt(o)),c=ja(r.charCodeAt(o+1));if(i===void 0||c===void 0){let a=r[o]+r[o+1];throw new RangeError('hex string expected, got non-hex character "'+a+'" at index '+o)}n[s]=i*16+c}return n}function Ei(...r){let e=0;for(let n=0;n<r.length;n++){let s=r[n];Y(s),e+=s.length}let t=new Uint8Array(e);for(let n=0,s=0;n<r.length;n++){let o=r[n];t.set(o,s),s+=o.length}return t}function _i(r,e,t="opts"){return Wa(r,"defaults"),e!==void 0&&Wa(e,t),Object.assign(Object.create(null),r,e)}function Mn(r,e={}){if(typeof r!="function")throw new TypeError('"hashCons" expected function, got type='+typeof r);e=_i({},e,"info");let t=(s,o)=>r(o).update(s).digest(),n=r(void 0);return t.outputLen=n.outputLen,t.blockLen=n.blockLen,t.canXOF=n.canXOF,t.create=s=>r(s),Object.assign(t,e),Object.freeze(t)}function js(r=32){le(r,"bytesLength");let e=typeof globalThis=="object"?globalThis.crypto:null;if(typeof e?.getRandomValues!="function")throw new Error("crypto.getRandomValues must be defined");if(r>65536)throw new RangeError(`"bytesLength" expected <= 65536, got ${r}`);return e.getRandomValues(new Uint8Array(r))}var zt=r=>({oid:Uint8Array.from([6,9,96,134,72,1,101,3,4,2,r])});function Bn(r,e,t=()=>{}){if(!Array.isArray(r))throw new TypeError(`"${e}" expected array, got type=${typeof r}`);for(let n=0;n<r.length;n++)t(r[n],`${e}[${n}]`);return r}var fe=(r,e,t)=>Y(r,e,t),Si=le;function Xa(r,e=""){if(typeof r!="string"){let t=e&&`"${e}" `;throw new TypeError(t+"expected string, got type="+typeof r)}return r}function Pt(r,e="object"){if(r===null||typeof r!="object"||Array.isArray(r))throw new TypeError(e==="object"?"expected valid options object":`"${e}" expected object, got type=${typeof r}`);return r}function Ue(r,e){if(typeof r!="function")throw new TypeError(`"${e}" is invalid: expected function, got ${typeof r}`);return r}var Ti=Un,We=(...r)=>Ei(...r),Js=r=>bi(r),Ur=Xt,Gs=r=>js(r),Vs=BigInt(0),Ya=BigInt(1),Qu=r=>r?`"${r}" `:"";function je(r,e=""){if(typeof r!="boolean")throw new TypeError(Qu(e)+"expected boolean, got type="+typeof r);return r}function Ys(r){if(typeof r=="bigint"){if(!Ct(r))throw new RangeError("positive bigint expected, got "+r)}else Si(r);return r}function Qt(r,e=""){if(typeof r!="number"){let t=e&&`"${e}" `;throw new TypeError(t+"expected number, got type="+typeof r)}if(!Number.isSafeInteger(r)){let t=e&&`"${e}" `;throw new RangeError(t+"expected safe integer, got "+r)}}function Fn(r){let e=Ys(r).toString(16);return e.length&1?"0"+e:e}function za(r){if(typeof r!="string")throw new TypeError("hex string expected, got "+typeof r);return r===""?Vs:BigInt("0x"+r)}function Ve(r){return za(Un(r))}function Xs(r){return za(Un(Zu(Y(r)).reverse()))}function Hn(r,e){if(le(e),e===0)throw new Error("zero output length is invalid");r=Ys(r);let t=e*2,n=r.toString(16);if(n.length>t)throw new RangeError("number is too large");return bi(n.padStart(t,"0"))}function Ri(r,e){return Hn(r,e).reverse()}function Zu(r){return Uint8Array.from(fe(r))}function Qa(r){if(typeof r!="string")throw new TypeError("ascii string expected, got "+typeof r);return Uint8Array.from(r,(e,t)=>{let n=e.charCodeAt(0);if(e.length!==1||n>127)throw new RangeError(`string contains non-ASCII character "${r[t]}" with code ${n} at position ${t}`);return n})}function Ct(r){return typeof r=="bigint"&&Vs<=r}function xi(r,e,t){return Ct(r)&&Ct(e)&&Ct(t)&&e<=r&&r<t}function Ai(r,e,t,n){if(!xi(e,t,n))throw new RangeError("expected valid "+r+": "+t+" <= n < "+n+", got "+e)}function Mr(r){if(r<Vs)throw new Error("expected non-negative bigint, got "+r);return r===Vs?0:r.toString(2).length}var $n=r=>(Qt(r,"n"),(Ya<<BigInt(r))-Ya);function Za(r,e,t){if(le(r,"hashLen"),le(e,"qByteLen"),typeof t!="function")throw new TypeError("hmacFn must be a function");let n=g=>new Uint8Array(g),s=Uint8Array.of(),o=Uint8Array.of(0),i=Uint8Array.of(1),c=1e3,a=n(r),l=n(r),u=0,d=()=>{a.fill(1),l.fill(0),u=0},p=(...g)=>t(l,We(a,...g)),f=(g=s)=>{l=p(o,g),a=p(),g.length!==0&&(l=p(i,g),a=p())},m=()=>{if(u++>=c)throw new Error("drbg: tried max amount of iterations");let g=0,b=[];for(;g<e;){a=p();let w=a.slice();b.push(w),g+=a.length}return We(...b)};return(g,b)=>{d(),f(g);let w;for(;(w=b(m()))===void 0;)f();return d(),w}}function rt(r,e={},t={},n="object"){Pt(r,n),Pt(e,"fields"),Pt(t,"optFields");function s(i,c,a){let l=n==="object"?`param "${String(i)}"`:`"${n}.${String(i)}"`,u=r[i];if(!Object.hasOwn(r,i)&&(a?u!==void 0:c!=="function"))throw new TypeError(`${l} is invalid: expected own property`);if(a&&u===void 0)return;let d=typeof u;if(d!==c||u===null)throw new TypeError(`${l} is invalid: expected ${c}, got ${d}`)}let o=(i,c)=>Object.entries(i).forEach(([a,l])=>s(a,l,c));o(e,!1),o(t,!0)}var ye=BigInt(0),Q=BigInt(1),kt=BigInt(2),rc=BigInt(3),Di=BigInt(4),nc=BigInt(5),qu=BigInt(7),sc=BigInt(8),ed=BigInt(9),td=BigInt(15),oc=BigInt(16),rd=BigInt("0x10000000000000000");function Pe(r,e){if(e<=ye)throw new Error("mod: expected positive modulus, got "+e);let t=r%e;return t>=ye?t:e+t}function ic(r,e,t){if(t<=Q)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 Q;if(e===Q)return r;let n=r%t;if(n<ye&&(n+=t),e<rd){let c=Q;for(;e>ye;)e&Q&&(c=c*n%t),n=n*n%t,e>>=Q;return c}let s=[];for(;e>ye;)s.push(Number(e&td)),e>>=Di;let o=new Array(16);o[0]=Q,o[1]=n;for(let c=2;c<16;c++)o[c]=o[c-1]*n%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 qa(r,e){if(r===ye)throw new Error("invert: expected non-zero number");if(e<=Q)throw new Error("invert: expected modulus > 1, got "+e);let t=Pe(r,e),n=e,s=ye,o=Q;for(;t!==ye;){let c=n/t,a=n-t*c,l=s-o*c;n=t,t=a,s=o,o=l}if(n!==Q)throw new Error("invert: does not exist");return Pe(s,e)}function ac(r,e){if(e<=Q)throw new Error("invertCt: expected prime modulus > 1, got "+e);let t=Pe(r,e);if(t===ye)throw new Error("invertCt: expected non-zero number");let n=ic(t,e-kt,e);if(Pe(t*n,e)!==Q)throw new Error("invertCt: does not exist");return n}function vi(r,e,t){let n=r;if(!n.eql(n.sqr(e),t))throw new Error("Cannot find square root")}function Pi(r,e){if((r&Q)===ye)throw new Error(e+": expected odd modulus, got "+r)}function cc(r,e){let t=r,n=(t.ORDER+Q)/Di,s=t.pow(e,n);return vi(t,s,e),s}function nd(r,e){let t=r,n=(t.ORDER-nc)/sc,s=t.mul(e,kt),o=t.pow(s,n),i=t.mul(e,o),c=t.mul(t.mul(i,kt),o),a=t.mul(i,t.sub(c,t.ONE));return vi(t,a,e),a}function sd(r){let e=Qs(r),t=lc(r),n=t(e,e.neg(e.ONE)),s=t(e,n),o=t(e,e.neg(n)),i=(r+qu)/oc;return((c,a)=>{let l=c,u=l.pow(a,i),d=l.mul(u,n),p=l.mul(u,s),f=l.mul(u,o),m=l.eql(l.sqr(d),a),h=l.eql(l.sqr(p),a);u=l.cmov(u,d,m),d=l.cmov(f,p,h);let g=l.eql(l.sqr(d),a),b=l.cmov(u,d,g);return vi(l,b,a),b})}function lc(r){if(r<rc)throw new Error("sqrt is not defined for small field");Pi(r,"tonelliShanks");let e=r-Q,t=0;for(;e%kt===ye;)e/=kt,t++;let n=kt,s=Qs(r);for(;ec(s,n)===1;)if(n++>1e3)throw new Error("Cannot find square root: probably non-prime P");if(t===1)return cc;let o=s.pow(n,e),i=(e+Q)/kt;return function(a,l){let u=a;if(u.is0(l))return l;if(ec(u,l)!==1)throw new Error("Cannot find square root");let d=t,p=u.mul(u.ONE,o),f=u.pow(l,e),m=u.pow(l,i);for(;!u.eql(f,u.ONE);){if(u.is0(f))throw new Error("Cannot find square root: probably non-prime P");let h=1,g=u.sqr(f);for(;!u.eql(g,u.ONE);)if(h++,g=u.sqr(g),h===d)throw new Error("Cannot find square root");let b=Q<<BigInt(d-h-1),w=u.pow(p,b);d=h,p=u.sqr(w),f=u.mul(f,p),m=u.mul(m,w)}return m}}function od(r){return Pi(r,"Fp.sqrt"),r%Di===rc?cc:r%sc===nc?nd:r%oc===ed?sd(r):lc(r)}var id=["create","isValid","is0","neg","inv","sqrt","sqr","eql","add","sub","mul","pow","div","addN","subN","mulN","sqrN"];function Br(r){if(Pt(r,"field"),typeof r.ORDER!="bigint")throw new TypeError('param "ORDER" is invalid: expected bigint, got '+typeof r.ORDER);Qt(r.BYTES,"BYTES"),Qt(r.BITS,"BITS");for(let e of id)Ue(r[e],"field."+e);if(r.BYTES<1||r.BITS<1)throw new Error("invalid field: expected BYTES/BITS > 0");if(r.ORDER<=Q)throw new Error("invalid field: expected ORDER > 1, got "+r.ORDER);return r}function Ci(r,e,t=!1){Br(r),Bn(e,"nums"),je(t,"passZero");let n=r,s=new Array(e.length).fill(t?n.ZERO:void 0),o=e.reduce((c,a,l)=>n.is0(a)?c:(s[l]=c,n.mul(c,a)),n.ONE),i=n.inv(o);return e.reduceRight((c,a,l)=>n.is0(a)?c:(s[l]=n.mul(c,s[l]),n.mul(c,a)),i),s}function ec(r,e){Br(r);let t=r;Pi(t.ORDER,"FpLegendre");let n=(t.ORDER-Q)/kt,s=t.pow(e,n),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 ad(r,e){if(e!==void 0&&Si(e),r<=ye)throw new Error("invalid n length: expected positive n, got "+r);if(e!==void 0&&e<1)throw new Error("invalid n length: expected positive bit length, got "+e);let t=Mr(r);if(e!==void 0&&e<t)throw new Error(`invalid n length: expected nBitLength (${e}) >= bitLen(n) (${t})`);let n=e!==void 0?e:t,s=Math.ceil(n/8);return{nBitLength:n,nByteLength:s}}var tc=new WeakMap,zs=class{ORDER;BITS;BYTES;isLE;ZERO=ye;ONE=Q;_lengths;_mod;constructor(e,t={}){if(e<=Q)throw new Error("invalid field: expected ORDER > 1, got "+e);let n;this.isLE=!1,t!=null&&typeof t=="object"&&(typeof t.BITS=="number"&&(n=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}=ad(e,n);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&Q)===Q}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 ic(e,t,this.ORDER)}div(e,t){return Pe(e*qa(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 qa(e,this.ORDER)}sqrt(e){let t=tc.get(this);return t||tc.set(this,t=od(this.ORDER)),t(this,e)}toBytes(e){return this.isLE?Ri(e,this.BYTES):Hn(e,this.BYTES)}fromBytes(e,t=!1){fe(e);let{_lengths:n,BYTES:s,isLE:o,ORDER:i,_mod:c}=this;if(n){if(e.length<1||!n.includes(e.length)||e.length>s)throw new Error("Field.fromBytes: expected "+n+" 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?Xs(e):Ve(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 Ci(this,e,!0)}cmov(e,t,n){return je(n,"condition"),n?t:e}};function Qs(r,e={}){return Object.freeze(zs.prototype),new zs(r,e)}function uc(r){if(typeof r!="bigint")throw new Error("field order must be bigint");if(r<=Q)throw new Error("field order must be greater than 1");let e=Mr(r-Q);return Math.ceil(e/8)}function Zs(r){let e=uc(r);return e+Math.ceil(e/2)}function ki(r,e,t=!1){fe(r);let n=r.length,s=uc(e),o=Math.max(Zs(e),16);if(n<o||n>1024)throw new Error("expected "+o+"-1024 bytes of input, got "+n);let i=t?Xs(r):Ve(r),c=Pe(i,e-Q)+Q;return t?Ri(c,s):Hn(c,s)}var Ni=BigInt(0),Kn=BigInt(1),cd=BigInt(4),Li=16,dc=128,ld=5,pc=2**31;function Fr(r){let e=r;if(typeof e!="function")throw new TypeError('"Point" expected constructor, got type='+typeof r);Ue(e.fromAffine,"Point.fromAffine"),Ue(e.fromBytes,"Point.fromBytes"),Ue(e.fromHex,"Point.fromHex"),Pt(e.BASE,"Point.BASE"),Pt(e.ZERO,"Point.ZERO"),Br(e.Fp),Br(e.Fn)}function mc(r,e){Fr(r),hc(e,r);let t=Ci(r.Fp,e.map(n=>n.Z));return e.map((n,s)=>r.fromAffine(n.toAffine(t[s])))}function ud(r,e,t=1){if(!Number.isSafeInteger(r)||r<t||r>e)throw new Error("invalid window size, expected ["+t+".."+e+"], got W="+r)}function dd(r,e){let t=r*(4*e+128);if(t>pc)throw new Error("invalid window size: table would need ~"+Math.ceil(t/2**20)+" MiB, max "+pc/2**20+" MiB")}function Ii(r,e){if(r!==void 0){Ue(r,"randomBytes");try{let t=r(e);if(!Ur(t)||t.length!==e)return}catch{return}return r}}function hc(r,e){Bn(r,"points"),r.forEach((t,n)=>{if(!(t instanceof e))throw new Error("invalid point at index "+n)})}function pd(r,e,t){if(!Array.isArray(r))throw new Error("array of scalars expected");r.forEach((n,s)=>{if(!(t===void 0?e.isValid(n):Ct(n)&&n<t))throw new Error("invalid scalar at index "+s)})}var gc=new WeakMap;function Oi(r){return gc.get(r)||1}function fd(r,e){let t=r.double(),n=[r];for(let s=1;s<e;s++)n.push(n[s-1].add(t));return n}function md(r,e){let t=2**e,n=t/2,s=BigInt(t-1),o=[];for(;r>Ni;){let i=0;r&Kn&&(i=Number(r&s),i>=n&&(i-=t),r-=BigInt(i)),o.push(i),r>>=Kn}return o}function hd(r,e,t){let n=2**e,s=n/2,o=BigInt(n-1),i=BigInt(e),c=[];for(let a=0;a<t;a++){let l=Number(r&o);r>>=i,l>s&&(l-=n,r+=Kn),c.push(l)}if(r!==Ni)throw new Error("invalid wnaf");return c}function gd(r,e,t){let n=0;for(let o of t)n=Math.max(n,o.length);let s=r;for(let o=n-1;o>=0;o--){o!==n-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 qs=class{Point;BASE;ZERO;randomBytes;wnafPrecomputes=new WeakMap;baseCanBeBlinded;bits;constructor(e,t){Fr(e),this.randomBytes=Ii(t,Li),this.Point=e,this.BASE=e.BASE,this.ZERO=e.ZERO,this.bits=e.Fn.BITS}buildWnafTable(e,t,n){let s=Math.ceil(n/t)+1,o=2**(t-1),i=[],c=e;for(let a=0;a<s;a++){let l=c;for(let u=0;u<o;u++)i.push(l),l=l.add(c);c=i[i.length-1].double()}return{W:t,bits:n,windows:s,comp:i}}wnafCachedCT(e,t){let{W:n,windows:s,comp:o}=e,i=2**(n-1),c=hd(t,n,s),a=this.ZERO,l=this.BASE;for(let u=0;u<s;u++){let d=c[u],p=u*i,f=Math.abs(d)-1,m=o[p];for(let g=1;g<i;g++)m=g===f?o[p+g]:m;let h=m.negate();d===0?l=l.add(o[p]):a=a.add(d<0?h:m)}return{p:a,f:l}}getWnafPrecomputes(e,t,n,s){let o=this.wnafPrecomputes.get(t),i=o?.find(c=>c.W===e&&c.bits===n);return i||(i=this.buildWnafTable(t,e,n),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),!xi(t,Kn,this.Point.Fn.ORDER))throw new Error("invalid scalar")}runCT(e,t,n,s){let o=Oi(e);return o===1?this.fixedWindowCT(e,t,n):this.wnafCachedCT(this.getWnafPrecomputes(o,e,n,s),t)}mulCT(e,t,n){return this.validateMulInput(e,t),this.runCT(e,t,this.bits,n)}mulCTBlinded(e,t,n){if(this.validateMulInput(e,t),this.randomBytes===void 0)throw new Error("randomBytes is required for scalar blinding");let s=this.Point.Fn.BITS+dc,o=this.randomBytes(Li);if(!Ur(o)||o.length!==Li)throw new Error("randomBytes returned invalid byte array");o[0]=o[0]&63|128;let i=t+Ve(o)*this.Point.Fn.ORDER;return this.runCT(e,i,s,n)}fixedWindowCT(e,t,n){let s=ld,o=1<<s,i=$n(s),c=new Array(o);c[0]=this.ZERO;for(let u=1;u<o;u++)c[u]=c[u-1].add(e);let a=Math.ceil(n/s),l=this.ZERO;for(let u=a-1;u>=0;u--){if(u!==a-1)for(let f=0;f<s;f++)l=l.double();let d=Number(t>>BigInt(u*s)&i),p=c[0];for(let f=1;f<o;f++)p=f===d?c[f]:p;l=l.add(p)}return{p:l,f:l}}shouldBlind(e,t){return this.randomBytes===void 0?!1:t===Kn?!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,n,s){return this.shouldBlind(e,n)?this.mulCTBlinded(e,t,s):this.mulCT(e,t,s)}mulUnsafe(e,t,n){if(this.assertPoint(e),!Ct(t))throw new Error("invalid scalar");let s=Oi(e);if(s===1||t>=this.Point.Fn.ORDER)return eo(this.Point,[e],[t],!0);let o=this.getWnafPrecomputes(s,e,this.bits,n);return this.wnafCachedCT(o,t).p}setWindowSize(e,t){this.assertPoint(e),ud(t,this.bits);let n=Math.ceil((this.bits+dc)/t)+1;dd(n*2**(t-1),this.Point.Fp.BYTES),gc.set(e,t),this.wnafPrecomputes.delete(e)}hasWindowSize(e){return Oi(e)!==1}};function eo(r,e,t,n=!1){if(Fr(r),hc(e,r),je(n,"allowOversized"),pd(t,r.Fn,n?r.Fn.ORDER**cd:void 0),e.length!==t.length)throw new Error("arrays of points and scalars must have equal length");let s=e.map(i=>fd(i,4)),o=t.map(i=>md(i,4));return gd(r.ZERO,s,o)}function fc(r,e,t){if(e){if(e.ORDER!==r)throw new Error("Field.ORDER must match order: Fp == p, Fn == n");return Br(e),e}else return Qs(r,{isLE:t})}function yc(r,e,t={},n){if(r!=="weierstrass"&&r!=="edwards")throw new Error('expected curve type "weierstrass" or "edwards"');if(n===void 0&&(n=r==="edwards"),!e||typeof e!="object")throw new Error(`expected valid ${r} CURVE object`);rt(t);for(let a of["p","n","h"]){let l=e[a];if(!(Ct(l)&&l!==Ni))throw new Error(`CURVE.${a} must be positive bigint`)}let s=fc(e.p,t.Fp,n),o=fc(e.n,t.Fn,n),c=["Gx","Gy","a",r==="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 wc(r,e){return function(n){let s=r(n);return{secretKey:s,publicKey:e(s)}}}var to=class{oHash;iHash;blockLen;outputLen;canXOF=!1;finished=!1;destroyed=!1;constructor(e,t){if(Or(e),Y(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 n=this.blockLen,s=new Uint8Array(n);s.set(t.length>n?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),vt(s)}update(e){return ut(this),this.iHash.update(e),this}digestInto(e){ut(this),Nr(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:n,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=n._cloneInto(e.iHash),e}clone(){return this._cloneInto()}destroy(){this.destroyed=!0,this.oHash.destroy(),this.iHash.destroy()}},bc=(()=>{let r=((e,t,n)=>new to(e,t).update(n).digest());return r.create=(e,t)=>new to(e,t),r})();var yd=BigInt(0),Ui=class extends Error{constructor(e=""){super(e)}},dt={Err:Ui,_tlv:{encode:(r,e)=>{let{Err:t}=dt;if(Qt(r,"tag"),r<0||r>255)throw new t("tlv.encode: wrong tag");if(Xa(e,"data"),e.length&1)throw new t("tlv.encode: unpadded data");let n=e.length/2,s=Fn(n);if(s.length/2&128)throw new t("tlv.encode: long form length too big");let o=n>127?Fn(s.length/2|128):"";return Fn(r)+o+s+e},decode(r,e){let{Err:t}=dt;e=fe(e,void 0,"DER data");let n=0;if(r<0||r>255)throw new t("tlv.decode: wrong tag");if(e.length<2||e[n++]!==r)throw new t("tlv.decode: wrong tlv");let s=e[n++],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(n,n+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 u of l)i=i<<8|u;if(n+=a,i<128)throw new t("tlv.decode(long): not minimal encoding")}let c=e.subarray(n,n+i);if(c.length!==i)throw new t("tlv.decode: wrong value length");return{v:c,l:e.subarray(n+i)}}},_int:{encode(r){let{Err:e}=dt;if(Ys(r),r<yd)throw new e("integer: negative integers are not allowed");let t=Fn(r);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(r){let{Err:e}=dt;if(r.length<1)throw new e("invalid signature integer: empty");if(r[0]&128)throw new e("invalid signature integer: negative");if(r.length>1&&r[0]===0&&!(r[1]&128))throw new e("invalid signature integer: unnecessary leading zero");return Ve(r)}},toSig(r,e){let{Err:t,_int:n,_tlv:s}=dt;if(e!==void 0&&(Qt(e,"maxScalarBytes"),e<1))throw new t("invalid signature: maxScalarBytes must be positive");let o=fe(r,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:u,l:d}=s.decode(2,l);if(d.length)throw new t("invalid signature: left bytes after parsing");if(e!==void 0&&(a.length>e||u.length>e))throw new t("invalid signature: integer too large");return{r:n.decode(a),s:n.decode(u)}},hexFromSig(r){let{_tlv:e,_int:t}=dt;rt(r,{r:"bigint",s:"bigint"},{},"sig");let n=e.encode(2,t.encode(r.r)),s=e.encode(2,t.encode(r.s)),o=n+s;return e.encode(48,o)}},ro=(Object.freeze(dt._tlv),Object.freeze(dt._int),Object.freeze(dt));var Ec=(r,e)=>(r+(r>=0?e:-e)/_c)/e;function wd(r,e,t){Ai("scalar",r,pt,t);let[[n,s],[o,i]]=e,c=Ec(i*r,t),a=Ec(-s*r,t),l=r-c*n-a*o,u=-c*s-a*i,d=l<pt,p=u<pt;d&&(l=-l),p&&(u=-u);let f=$n(Math.ceil(Mr(t)/2))+Zt;if(l<pt||l>=f||u<pt||u>=f)throw new Error("splitScalar (endomorphism): failed for k");return{k1neg:d,k1:l,k2neg:p,k2:u}}function Fi(r){if(!["compact","recovered","der"].includes(r))throw new Error('Signature format must be "compact", "recovered", or "der"');return r}function Mi(r,e){rt(r);let t={};for(let n of Object.keys(e))t[n]=r[n]===void 0?e[n]:r[n];return je(t.lowS,"lowS"),je(t.prehash,"prehash"),t.format!==void 0&&Fi(t.format),t}var pt=BigInt(0),Zt=BigInt(1),_c=BigInt(2),Bi=BigInt(3),bd=BigInt(4);function Sc(r,e={}){let t=yc("weierstrass",r,e),n=t.Fp,s=t.Fn,o=t.CURVE,{h:i,n:c}=o;rt(e,{},{allowInfinityPoint:"boolean",clearCofactor:"function",isTorsionFree:"function",fromBytes:"function",toBytes:"function",endo:"object",randomBytes:"function"});let{endo:a,allowInfinityPoint:l,clearCofactor:u,isTorsionFree:d,fromBytes:p,toBytes:f}=e,m=e.randomBytes===void 0?Gs:e.randomBytes;if(a&&(!n.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(L=>[...L])}:void 0,g=Rc(n,s);function b(){if(!n.isOdd)throw new Error("compression is not supported: Field does not have .isOdd()")}function w(L,T,A){if(T.is0()){if(!l)throw new Error("bad point: ZERO");return Uint8Array.of(0)}let{x:C,y:I}=T.toAffine(),M=n.toBytes(C);if(je(A,"isCompressed"),A){b();let B=!n.isOdd(I);return We(Tc(B),M)}else return We(Uint8Array.of(4),M,n.toBytes(I))}function y(L){fe(L,void 0,"Point");let{publicKey:T,publicKeyUncompressed:A}=g,C=L.length,I=L[0],M=L.subarray(1);if(l&&C===1&&I===0)return{x:n.ZERO,y:n.ZERO};if(C===T&&(I===2||I===3)){let B=n.fromBytes(M);if(!n.isValid(B))throw new Error("bad point: is not on curve, wrong x");let $=R(B),F;try{F=n.sqrt($)}catch(W){let J=W instanceof Error?": "+W.message:"";throw new Error("bad point: is not on curve, sqrt error"+J)}b();let H=n.isOdd(F);return(I&1)===1!==H&&(F=n.neg(F)),{x:B,y:F}}else if(C===A&&I===4){let B=n.BYTES,$=n.fromBytes(M.subarray(0,B)),F=n.fromBytes(M.subarray(B,B*2));if(!D($,F))throw new Error("bad point: is not on curve");return{x:$,y:F}}else throw new Error(`bad point: got length ${C}, expected compressed=${T} or uncompressed=${A}`)}let E=f===void 0?w:f,_=p===void 0?y:p,S=n.mul(o.b,Bi),x=n.is0(o.a)?L=>n.ZERO:L=>n.mul(o.a,L);function R(L){let T=n.sqr(L),A=n.mul(T,L);return n.add(n.add(A,n.mul(L,o.a)),o.b)}function D(L,T){let A=n.sqr(T),C=R(L);return n.eql(A,C)}if(!D(o.Gx,o.Gy))throw new Error("bad curve params: generator point");let P=n.mul(n.pow(o.a,Bi),bd),k=n.mul(n.sqr(o.b),BigInt(27));if(n.is0(n.add(P,k)))throw new Error("bad curve params: a or b");function N(L,T,A=!1){if(!n.isValid(T)||A&&n.is0(T))throw new Error(`bad point coordinate ${L}`);return typeof T=="object"&&T!==null?n.create(T):T}function V(L){if(!(L instanceof K))throw new Error("Weierstrass Point expected")}function z(L){if(!h||!h.basises)throw new Error("no endo");return wd(L,h.basises,s.ORDER)}function ue(L,T,A,C){if(!s.isValid(C))throw new RangeError("invalid scalar: out of range");if(h){let{k1neg:I,k1:M,k2neg:B,k2:$}=z(C),F=new K(n.mul(A.X,h.beta),A.Y,A.Z);L.push(I?A.negate():A,B?F.negate():F),T.push(M,$)}else L.push(A),T.push(C)}let Ae=new WeakSet;class K{static BASE=new K(o.Gx,o.Gy,n.ONE);static ZERO=new K(n.ZERO,n.ONE,n.ZERO);static Fp=n;static Fn=s;X;Y;Z;constructor(T,A,C){this.X=N("x",T),this.Y=N("y",A,!0),this.Z=N("z",C),Object.freeze(this)}static CURVE(){return o}static fromAffine(T){let{x:A,y:C}=T||{};if(!T||!n.isValid(A)||!n.isValid(C))throw new Error("invalid affine point");if(T instanceof K)throw new Error("projective point not allowed");return n.is0(A)&&n.is0(C)?K.ZERO:new K(A,C,n.ONE)}static fromBytes(T){let A=K.fromAffine(_(fe(T,void 0,"point")));return A.assertValidity(),A}static fromHex(T){return K.fromBytes(Js(T))}get x(){return this.toAffine().x}get y(){return this.toAffine().y}precompute(T=6,A=!0){return we.setWindowSize(this,T),A||this.multiply(Bi),this}assertValidity(){let T=this;if(T.is0()){if(l&&n.is0(T.X)&&n.eql(T.Y,n.ONE)&&n.is0(T.Z))return;throw new Error("bad point: ZERO")}if(Ae.has(T))return;let{x:A,y:C}=T.toAffine();if(!n.isValid(A)||!n.isValid(C))throw new Error("bad point: x or y not field elements");if(!D(A,C))throw new Error("bad point: equation left != right");if(!T.isTorsionFree())throw new Error("bad point: not in prime-order subgroup");Ae.add(T)}hasEvenY(){let{y:T}=this.toAffine();if(!n.isOdd)throw new Error("Field doesn't support isOdd");return!n.isOdd(T)}equals(T){V(T);let{X:A,Y:C,Z:I}=this,{X:M,Y:B,Z:$}=T,F=n.eql(n.mul(A,$),n.mul(M,I)),H=n.eql(n.mul(C,$),n.mul(B,I));return F&&H}negate(){return new K(this.X,n.neg(this.Y),this.Z)}double(){let{X:T,Y:A,Z:C}=this,I=n.ZERO,M=n.ZERO,B=n.ZERO,$=n.mul(T,T),F=n.mul(A,A),H=n.mul(C,C),U=n.mul(T,A);return U=n.add(U,U),B=n.mul(T,C),B=n.add(B,B),I=x(B),M=n.mul(S,H),M=n.add(I,M),I=n.sub(F,M),M=n.add(F,M),M=n.mul(I,M),I=n.mul(U,I),B=n.mul(S,B),H=x(H),U=n.sub($,H),U=x(U),U=n.add(U,B),B=n.add($,$),$=n.add(B,$),$=n.add($,H),$=n.mul($,U),M=n.add(M,$),H=n.mul(A,C),H=n.add(H,H),$=n.mul(H,U),I=n.sub(I,$),B=n.mul(H,F),B=n.add(B,B),B=n.add(B,B),new K(I,M,B)}add(T){V(T);let{X:A,Y:C,Z:I}=this,{X:M,Y:B,Z:$}=T,F=n.ZERO,H=n.ZERO,U=n.ZERO,W=n.mul(A,M),J=n.mul(C,B),Z=n.mul(I,$),Ce=n.add(A,C),te=n.add(M,B);Ce=n.mul(Ce,te),te=n.add(W,J),Ce=n.sub(Ce,te),te=n.add(A,I);let ie=n.add(M,$);return te=n.mul(te,ie),ie=n.add(W,Z),te=n.sub(te,ie),ie=n.add(C,I),F=n.add(B,$),ie=n.mul(ie,F),F=n.add(J,Z),ie=n.sub(ie,F),U=x(te),F=n.mul(S,Z),U=n.add(F,U),F=n.sub(J,U),U=n.add(J,U),H=n.mul(F,U),J=n.add(W,W),J=n.add(J,W),Z=x(Z),te=n.mul(S,te),J=n.add(J,Z),Z=n.sub(W,Z),Z=x(Z),te=n.add(te,Z),W=n.mul(J,te),H=n.add(H,W),W=n.mul(ie,te),F=n.mul(Ce,F),F=n.sub(F,W),W=n.mul(Ce,J),U=n.mul(ie,U),U=n.add(U,W),new K(F,H,U)}subtract(T){return V(T),this.add(T.negate())}is0(){return this.equals(K.ZERO)}multiply(T){if(!s.isValidNot0(T))throw new RangeError("invalid scalar: out of range");let{p:A,f:C}=we.mulSecret(this,T,i,se);return se([A,C])[0]}multiplyUnsafe(T){let A=this,C=T;if(!s.isValid(C))throw new RangeError("invalid scalar: out of range");if(C===pt||A.is0())return K.ZERO;if(C===Zt)return A;if(we.hasWindowSize(this))return we.mulUnsafe(A,C,se);let I=[],M=[];return ue(I,M,A,C),eo(K,I,M)}mulAddUnsafe(T,A,C){V(A);let I=[],M=[];return ue(I,M,this,T),ue(I,M,A,C),eo(K,I,M)}toAffine(T){let A=this,C=T;if(C!=null&&!n.isValid(C))throw new RangeError('"invertedZ" expected valid field element');let{X:I,Y:M,Z:B}=A;if(n.eql(B,n.ONE))return{x:I,y:M};let $=A.is0();C==null&&(C=$?n.ONE:n.inv(B));let F=n.mul(I,C),H=n.mul(M,C),U=n.mul(B,C);if($)return{x:n.ZERO,y:n.ZERO};if(!n.eql(U,n.ONE))throw new Error("invZ was invalid");return{x:F,y:H}}isTorsionFree(){return i===Zt?!0:d?d(K,this):we.mulUnsafe(this,c).is0()}clearCofactor(){return i===Zt?this:u?u(K,this):this.multiplyUnsafe(i)}isSmallOrder(){return i===Zt?this.is0():this.clearCofactor().is0()}toBytes(T=!0){return je(T,"isCompressed"),this.assertValidity(),E(K,this,T)}toHex(T=!0){return Ti(this.toBytes(T))}toString(){return`<Point ${this.is0()?"ZERO":this.toHex()}>`}}let se=L=>mc(K,L),we=new qs(K,m);return we.bits>=6&&K.BASE.precompute(6),Object.freeze(K.prototype),Object.freeze(K),K}function Tc(r){return Uint8Array.of(r?2:3)}function Rc(r,e){return{secretKey:e.BYTES,publicKey:1+r.BYTES,publicKeyUncompressed:1+2*r.BYTES,publicKeyHasPrefix:!0,signature:2*e.BYTES}}function Ed(r,e={}){Fr(r);let{Fn:t}=r,n=e.randomBytes===void 0?Gs:e.randomBytes,s=Object.assign(Rc(r.Fp,t),{seed:Math.max(Zs(t.ORDER),16)});function o(f){try{let m=t.fromBytes(f);return t.isValidNot0(m)}catch{return!1}}function i(f,m){let{publicKey:h,publicKeyUncompressed:g}=s;try{let b=f.length;return m===!0&&b!==h||m===!1&&b!==g?!1:!r.fromBytes(f).is0()}catch{return!1}}function c(f){return f=f===void 0?n(s.seed):f,ki(fe(f,s.seed,"seed"),t.ORDER)}function a(f,m=!0){return r.BASE.multiply(t.fromBytes(f)).toBytes(m)}function l(f){let{secretKey:m,publicKey:h,publicKeyUncompressed:g}=s,b=t._lengths;if(!Ur(f))return;let w=fe(f,void 0,"key").length,y=w===h||w===g,E=w===m||!!b?.includes(w);if(!(y&&E))return y}function u(f,m,h=!0){if(l(f)===!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(f),b=r.fromBytes(m);if(b.is0())throw new Error("invalid public key: point at infinity");return b.multiply(g).toBytes(h)}let d={isValidSecretKey:o,isValidPublicKey:i,randomSecretKey:c},p=wc(c,a);return Object.freeze(d),Object.freeze(s),Object.freeze({getPublicKey:a,getSharedSecret:u,keygen:p,Point:r,utils:d,lengths:s})}function xc(r,e,t={}){Fr(r);let n=e;Or(n),rt(t,{},{hmac:"function",lowS:"boolean",randomBytes:"function",bits2int:"function",bits2int_modN:"function"});let s=Object.assign({},t),o=s.randomBytes===void 0?Gs:s.randomBytes,i=s.hmac===void 0?(L,T)=>bc(n,L,T):s.hmac,{Fp:c,Fn:a}=r,{ORDER:l,BITS:u}=a,d=Zs(l),p=Ii(o,d),{keygen:f,getPublicKey:m,getSharedSecret:h,utils:g,lengths:b}=Ed(r,s),w={prehash:!0,lowS:typeof s.lowS=="boolean"?s.lowS:!0,format:"compact",extraEntropy:!1},y=l*_c+Zt<c.ORDER;function E(L){let T=l>>Zt;return L>T}function _(L,T){if(!a.isValidNot0(T))throw new Error(`invalid signature ${L}: out of range 1..Point.Fn.ORDER`);return T}function S(){if(!c.isOdd)throw new Error("Field doesn't support isOdd")}function x(L,T,A){return S(),(L===A?0:2)|Number(c.isOdd(T))}function R(){if(y)throw new Error('"recovered" sig type is not supported for cofactor >2 curves')}function D(L,T){Fi(T);let A=b.signature,C=T==="compact"?A:T==="recovered"?A+1:void 0;return fe(L,C)}class P{r;s;recovery;constructor(T,A,C){if(this.r=_("r",T),this.s=_("s",A),C!=null){if(R(),![0,1,2,3].includes(C))throw new Error("invalid recovery id");this.recovery=C}Object.freeze(this)}static fromBytes(T,A=w.format){D(T,A);let C;if(A==="der"){if(T.length>2*a.BYTES+16)throw new ro.Err("invalid signature: DER signature too long");let{r:$,s:F}=ro.toSig(fe(T),a.BYTES+1);return new P($,F)}A==="recovered"&&(C=T[0],A="compact",T=T.subarray(1));let I=b.signature/2,M=T.subarray(0,I),B=T.subarray(I,I*2);return new P(a.fromBytes(M),a.fromBytes(B),C)}static fromHex(T,A){return this.fromBytes(Js(T),A)}assertRecovery(){let{recovery:T}=this;if(T==null)throw new Error("invalid recovery id: must be present");return T}addRecoveryBit(T){return new P(this.r,this.s,T)}recoverPublicKey(T){let{r:A,s:C}=this,I=this.assertRecovery(),M=I===2||I===3?A+l:A;if(!c.isValid(M))throw new Error("invalid recovery id: sig.r+curve.n != R.x");let B=c.toBytes(M),$=r.fromBytes(We(Tc((I&1)===0),B)),F=a.inv(M),H=N(fe(T,void 0,"msgHash")),U=a.create(-H*F),W=a.create(C*F),J=r.BASE.mulAddUnsafe(U,$,W);if(J.is0())throw new Error("invalid recovery: point at infinify");return J.assertValidity(),J}hasHighS(){return E(this.s)}toBytes(T=w.format){if(Fi(T),T==="der")return Js(ro.hexFromSig(this));let{r:A,s:C}=this,I=a.toBytes(A),M=a.toBytes(C);return T==="recovered"?(R(),We(Uint8Array.of(this.assertRecovery()),I,M)):We(I,M)}toHex(T){return Ti(this.toBytes(T))}}Object.freeze(P.prototype),Object.freeze(P);let k=s.bits2int===void 0?function(T){if(T.length>8192)throw new Error("input is too large");let A=Ve(T),C=T.length*8-u;return C>0?A>>BigInt(C):A}:s.bits2int,N=s.bits2int_modN===void 0?function(T){return a.create(k(T))}:s.bits2int_modN,V=$n(u);function z(L){return Ai("num < 2^"+u,L,pt,V),a.toBytes(L)}function ue(L,T){return fe(L,void 0,"message"),T?fe(n(L),void 0,"prehashed message"):L}function Ae(L,T,A){let{lowS:C,prehash:I,extraEntropy:M}=Mi(A,w);L=ue(L,I);let B=N(L),$=a.fromBytes(T);if(!a.isValidNot0($))throw new Error("invalid private key");let F=[z($),z(B)];if(M!=null&&M!==!1){let J=M===!0?o(b.secretKey):M;F.push(fe(J,void 0,"extraEntropy"))}let H=We(...F),U=B;function W(J){let Z=k(J);if(!a.isValidNot0(Z))return;let Ce=r.BASE.multiply(Z).toAffine(),te=a.create(Ce.x);if(te===pt)return;let ie;if(p!==void 0){let sn=Ve(ki(p(d),l)),wu=a.inv(a.mul(sn,Z)),bu=a.mul(sn,U),Eu=a.mul(sn,$);ie=a.create(wu*a.create(bu+Eu*te))}else{let sn=ac(Z,l);ie=a.create(sn*a.create(U+te*$))}if(ie===pt)return;let Fo=x(Ce.x,Ce.y,te),ua=ie;return C&&E(ie)&&(ua=a.neg(ie),Fo^=1),new P(te,ua,y?void 0:Fo)}return{seed:H,k2sig:W}}function K(L,T,A={}){let{seed:C,k2sig:I}=Ae(L,T,A);return Za(n.outputLen,a.BYTES,i)(C,I).toBytes(A.format)}function se(L,T,A,C={}){let{lowS:I,prehash:M,format:B}=Mi(C,w);if(A=fe(A,void 0,"publicKey"),T=ue(T,M),!Ur(L)){let $=L instanceof P?", use sig.toBytes()":"";throw new Error("verify expects Uint8Array signature"+$)}D(L,B);try{let $=P.fromBytes(L,B),F=r.fromBytes(A);if(F.is0()||I&&$.hasHighS())return!1;let{r:H,s:U}=$,W=N(T),J=a.inv(U),Z=a.create(W*J),Ce=a.create(H*J),te=r.BASE.mulAddUnsafe(Z,F,Ce);if(te.is0())return!1;let ie=te.toAffine();return!(a.create(ie.x)!==H||B==="recovered"&&$.recovery!==x(ie.x,ie.y,H))}catch{return!1}}function we(L,T,A={}){let{prehash:C}=Mi(A,w);return T=ue(T,C),P.fromBytes(L,"recovered").recoverPublicKey(T).toBytes()}return Object.freeze({keygen:f,getPublicKey:m,getSharedSecret:h,utils:g,lengths:b,Point:r,sign:K,verify:se,recoverPublicKey:we,Signature:P,hash:n})}var no=BigInt(4294967295),Ac=BigInt(32);function _d(r,e=!1){return e?{h:Number(r&no),l:Number(r>>Ac&no)}:{h:Number(r>>Ac&no)|0,l:Number(r&no)|0}}function Dc(r,e=!1){let t=r.length,n=new Uint32Array(t),s=new Uint32Array(t);for(let o=0;o<t;o++){let{h:i,l:c}=_d(r[o],e);[n[o],s[o]]=[i,c]}return[n,s]}var Sd=r=>r/2**32|0,Td=r=>r>>>0;function vc(r,e,t,n){let s=Sd(t),o=Td(t);r.setUint32(e,n?o:s,n),r.setUint32(e+4,n?s:o,n)}function Pc(r,e,t){return r&e^~r&t}function Cc(r,e,t){return r&e^r&t^e&t}var so=class{blockLen;outputLen;canXOF=!1;padOffset;isLE;buffer;view;finished=!1;length=0;pos=0;destroyed=!1;constructor(e,t,n,s){this.blockLen=e,this.outputLen=t,this.padOffset=n,this.isLE=s,this.buffer=new Uint8Array(e),this.view=Ws(this.buffer)}update(e){ut(this),Y(e);let{view:t,buffer:n,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=Ws(e);for(;s<=o-c;c+=s)this.process(l,c);i=!0;continue}n.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){ut(this),Nr(e,this),this.finished=!0;let{buffer:t,view:n,blockLen:s,isLE:o}=this,{pos:i}=this;t[i++]=128,t.fill(0,i),this.padOffset>s-i&&(this.process(n,0),t.fill(0)),vc(n,s-8,this.length*8,o),this.process(n,0),this.roundClean();let c=e===t?n:Ws(e),a=this.outputLen,l=a/4,u=this.get();if(a%4||l>u.length)throw new Error("invalid outputLen");for(let d=0;d<l;d++)c.setUint32(4*d,u[d],o)}digest(){let{buffer:e,outputLen:t}=this;this.digestInto(e);let n=e.slice(0,t);return this.destroy(),n}_cloneIntoMeta(e){let{buffer:t,length:n,finished:s,destroyed:o,pos:i}=this;return e.destroyed=o,e.finished=s,e.length=n,e.pos=i,i&&e.buffer.set(t),e}clone(){return this._cloneInto()}},kc=Uint32Array.from([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]);var Rd=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]),Lt=new Uint32Array(64),Hi=class extends so{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:n,D:s,E:o,F:i,G:c,H:a}=this;return[e,t,n,s,o,i,c,a]}set(e,t,n,s,o,i,c,a){this.A=e|0,this.B=t|0,this.C=n|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 d=0;d<16;d++,t+=4)Lt[d]=e.getUint32(t,!1);for(let d=16;d<64;d++){let p=Lt[d-15],f=Lt[d-2],m=Ke(p,7)^Ke(p,18)^p>>>3,h=Ke(f,17)^Ke(f,19)^f>>>10;Lt[d]=h+Lt[d-7]+m+Lt[d-16]|0}let{A:n,B:s,C:o,D:i,E:c,F:a,G:l,H:u}=this;for(let d=0;d<64;d++){let p=Ke(c,6)^Ke(c,11)^Ke(c,25),f=u+p+Pc(c,a,l)+Rd[d]+Lt[d]|0,h=(Ke(n,2)^Ke(n,13)^Ke(n,22))+Cc(n,s,o)|0;u=l,l=a,a=c,c=i+f|0,i=o,o=s,s=n,n=f+h|0}n=n+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,u=u+this.H|0,this.set(n,s,o,i,c,a,l,u)}roundClean(){vt(Lt)}destroy(){this.destroyed=!0,this.set(0,0,0,0,0,0,0,0),vt(this.buffer)}},$i=class extends Hi{constructor(){super(32,kc)}};var Lc=Mn(()=>new $i,zt(1));function Wn(r,e="n"){if(typeof r!="number")throw new TypeError(`wrong u32 integer "${e}": expected number, got type=${typeof r}`);if(!Number.isSafeInteger(r)||r<0||r>4294967295)throw new RangeError(`wrong u32 integer "${e}": expected 0..4294967295, got ${r}`);return r}function Nc(r){return Wn(r,"x"),(r&r-1)===0&&r!==0}function Ki(r,e){if(Wn(r),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 n=0;n<e;n++,r>>>=1)t=t<<1|r&1;return t>>>0}function Ic(r){return Wn(r),31-Math.clz32(r)}function Oc(r){if(!r||typeof r!="object"||typeof r.length!="number")throw new TypeError('"values" expected array-like, got type='+typeof r);let e=r.length;if(!Nc(e))throw new Error("expected positive power-of-two length, got "+e);let t=Ic(e);for(let n=0;n<e;n++){let s=Ki(n,t);if(n<s){let o=r[n];r[n]=r[s],r[s]=o}}return r}var Wi=(r,e)=>{rt(e,{N:"number",roots:"object",dit:"boolean"},{invertButterflies:"boolean",skipStages:"number",brp:"boolean"},"coreOpts");let{N:t,roots:n,dit:s,invertButterflies:o=!1,skipStages:i=0,brp:c=!0}=e;Wn(t,"coreOpts.N");let a=Ic(t);if(!Nc(t))throw new Error("FFT: Polynomial size should be power of two");Wn(i,"coreOpts.skipStages");let l=a===0?0:a-1;if(i>l)throw new Error(`FFT: wrong skipStages: expected 0 <= skipStages <= ${l}`);if(n.length!==t)throw new Error(`FFT: wrong roots length: expected ${t}, got ${n.length}`);let u=s!==o;return d=>{if(d.length!==t)throw new Error("FFT: wrong Polynomial length");s&&c&&Oc(d);for(let p=0,f=1;p<a-i;p++){let m=s?p+1+i:a-p,h=1<<m,g=h>>1,b=t>>m;for(let w=0;w<t;w+=h)for(let y=0,E=f++;y<g;y++){let _=o?s?t-E:E:y*b,S=w+y,x=w+y+g,R=n[_],D=d[x],P=d[S];if(u){let k=r.mul(D,R);d[S]=r.add(P,k),d[x]=r.sub(P,k)}else o?(d[S]=r.add(D,P),d[x]=r.mul(r.sub(D,P),R)):(d[S]=r.add(P,D),d[x]=r.mul(r.sub(P,D),R))}}return!s&&c&&Oc(d),d}};var xd={p:BigInt("0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"),n:BigInt("0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"),h:BigInt(1),a:BigInt("0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc"),b:BigInt("0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b"),Gx:BigInt("0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"),Gy:BigInt("0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5")};var Ad=Sc(xd),Uc=xc(Ad,Lc);var Dd=BigInt(0),jn=BigInt(1),vd=BigInt(2),Pd=BigInt(7),Cd=BigInt(256),kd=BigInt(113),Fc=[],Hc=[],$c=[];for(let r=0,e=jn,t=1,n=0;r<24;r++){[t,n]=[n,(2*t+3*n)%5],Fc.push(2*(5*n+t)),Hc.push((r+1)*(r+2)/2%64);let s=Dd;for(let o=0;o<7;o++)e=(e<<jn^(e>>Pd)*kd)%Cd,e&vd&&(s^=jn<<(jn<<BigInt(o))-jn);$c.push(s)}var Kc=Dc($c,!0),Ld=Kc[0],Od=Kc[1],Nd=(r,e,t)=>r<<t|e>>>32-t,Id=(r,e,t)=>e<<t|r>>>32-t,Ud=(r,e,t)=>e<<t-32|r>>>64-t,Md=(r,e,t)=>r<<t-32|e>>>64-t,Mc=(r,e,t)=>t>32?Ud(r,e,t):Nd(r,e,t),Bc=(r,e,t)=>t>32?Md(r,e,t):Id(r,e,t),Hr=new Uint32Array(10);function Bd(r,e=24){if(!(r instanceof Uint32Array))throw new TypeError('"s" expected Uint32Array(50), got type='+typeof r);if(r.length!==50)throw new RangeError('"s" expected Uint32Array(50), got length='+r.length);if(le(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++)Hr[o]=r[o]^r[o+10]^r[o+20]^r[o+30]^r[o+40];for(let o=0;o<10;o+=2){let i=(o+8)%10,c=(o+2)%10,a=Hr[c],l=Hr[c+1],u=Mc(a,l,1)^Hr[i],d=Bc(a,l,1)^Hr[i+1];for(let p=0;p<50;p+=10)r[o+p]^=u,r[o+p+1]^=d}let n=r[2],s=r[3];for(let o=0;o<24;o++){let i=Hc[o],c=Mc(n,s,i),a=Bc(n,s,i),l=Fc[o];n=r[l],s=r[l+1],r[l]=c,r[l+1]=a}for(let o=0;o<50;o+=10){let i=r[o],c=r[o+1],a=r[o+2],l=r[o+3];r[o]^=~r[o+2]&r[o+4],r[o+1]^=~r[o+3]&r[o+5],r[o+2]^=~r[o+4]&r[o+6],r[o+3]^=~r[o+5]&r[o+7],r[o+4]^=~r[o+6]&r[o+8],r[o+5]^=~r[o+7]&r[o+9],r[o+6]^=~r[o+8]&i,r[o+7]^=~r[o+9]&c,r[o+8]^=~i&a,r[o+9]^=~c&l}r[0]^=Ld[t],r[1]^=Od[t]}vt(Hr)}var oo=class r{state;pos=0;posOut=0;finished=!1;state32;destroyed=!1;blockLen;suffix;outputLen;canXOF;enableXOF=!1;rounds;constructor(e,t,n,s=!1,o=24){if(le(e,"blockLen"),le(t,"suffix"),le(o,"rounds"),Va(s,"enableXOF"),this.blockLen=e,this.suffix=t,this.outputLen=n,this.enableXOF=s,this.canXOF=s,this.rounds=o,le(n,"outputLen"),!(0<e&&e<200))throw new Error('"blockLen" must be 1..199');this.state=new Uint8Array(200),this.state32=In(this.state)}clone(){return this._cloneInto()}keccak(){Ir(this.state32),Bd(this.state32,this.rounds),Ir(this.state32),this.posOut=0,this.pos=0}update(e){ut(this),Y(e);let{blockLen:t,state:n,state32:s}=this,o=e.length,i=t%4===0&&e.byteOffset%4===0,c=t/4,a=i&&o>=t?In(e):void 0;for(let l=0;l<o;){if(a!==void 0&&this.pos===0&&l%4===0&&o-l>=t){for(let d=0,p=l/4;d<c;d++)s[d]^=a[p+d];l+=t,this.pos=t,this.keccak();continue}let u=Math.min(t-this.pos,o-l);for(let d=0;d<u;d++)n[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:n,blockLen:s}=this;e[n]^=t,(t&128)!==0&&n===s-1&&this.keccak(),e[s-1]^=128,this.keccak()}writeInto(e){ut(this,!1),Y(e),this.finish();let t=this.state,{blockLen:n}=this;for(let s=0,o=e.length;s<o;){this.posOut>=n&&this.keccak();let i=Math.min(n-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 le(e),this.xofInto(new Uint8Array(e))}digestInto(e){if(Nr(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,vt(this.state)}_cloneInto(e){let{blockLen:t,suffix:n,outputLen:s,rounds:o,enableXOF:i}=this;return e||=new r(t,n,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=n,e.outputLen=s,e.enableXOF=i,e.canXOF=this.canXOF,e.destroyed=this.destroyed,e}},Wc=(r,e,t,n={})=>Mn(()=>new oo(e,r,t),n);var io=Wc(6,136,32,zt(8));var jc=Wc(6,72,64,zt(10));var Vc=(r,e,t,n={})=>Mn((s={})=>(s=_i({},s),new oo(e,r,s.dkLen===void 0?t:s.dkLen,!0)),n),Jc=Vc(31,168,16,zt(11)),$r=Vc(31,136,32,zt(12));var Je=Y;var ft=js;function Fd(r,e,t=()=>{}){if(!Array.isArray(r))throw new TypeError(`"${e}" expected array, got type=${typeof r}`);for(let n=0;n<r.length;n++)t(r[n],`${e}[${n}]`);return r}function ji(r,e="object"){if(r===null||typeof r!="object"||Array.isArray(r))throw new TypeError(e==="object"?"expected valid options object":`"${e}" expected object, got type=${typeof r}`);return r}function qt(r,e){if(r=Y(r),e=Y(e),r.length!==e.length)return!1;let t=0;for(let n=0;n<r.length;n++)t|=r[n]^e[n];return t===0}function mt(r){return new Uint8Array(Y(r))}function er(r,...e){let t=s=>typeof s=="number"?s:s.bytesLen,n=e.reduce((s,o)=>s+t(o),0);return{bytesLen:n,encode:s=>{let o=new Uint8Array(n);for(let i=0,c=0;i<e.length;i++){let a=e[i],l=t(a),u=typeof a=="number"?s[i]:a.encode(s[i]);Y(u,l,r),o.set(u,c),typeof a!="number"&&u.fill(0),c+=l}return o},decode:s=>{Y(s,n,r);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 ao(r,e){let t=r,n=e*t.bytesLen;return{bytesLen:n,encode:s=>{let o=Fd(s,"u");if(o.length!==e)throw new RangeError(`vecCoder.encode: wrong length=${o.length}. Expected: ${e}`);let i=new Uint8Array(n);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=>{Y(s,n);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(...r){for(let e of r)if(Array.isArray(e))for(let t of e)t.fill(0);else e.fill(0)}function co(r){if(le(r,"bits"),r>32)throw new RangeError('"bits" expected <= 32, got '+r);return r===32?4294967295:~(-1<<r)>>>0}var Gc=r=>{let{newPoly:e,N:t,Q:n,F:s,ROOT_OF_UNITY:o,brvBits:i,isKyber:c}=r,a=(y,E=n)=>{let _=y%E|0;return(_>=0?_|0:E+_|0)|0},l=(y,E=n)=>{let _=a(y,E)|0;return(_>E>>1?_-E|0:_)|0};function u(){let y=e(t);for(let E=0;E<t;E++){let _=Ki(E,i),S=BigInt(o)**BigInt(_)%BigInt(n);y[E]=Number(S)|0}return y}let d=u(),p=y=>{throw new Error("not implemented")},f=c?{add:(y,E)=>{let _=y+E|0;return _>=n?_-n|0:_},sub:(y,E)=>{let _=y-E|0;return _<0?_+n|0:_},mul:(y,E)=>a((y|0)*(E|0))|0,inv:p}:{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:p},m={N:t,roots:d,invertButterflies:!0,skipStages:c?1:0,brp:!1},h=Wi(f,{dit:!1,...m}),g=Wi(f,{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:d,NTT:{encode:y=>b.encode(y),decode:y=>b.decode(y)},bitsCoder:(y,E)=>{for(let x=0,R=0;x<t;x++)R+=y,R>32&&co(R),R%=8;let _=co(y),S=y*(t/8);return{bytesLen:S,encode:x=>{let R=x,D=new Uint8Array(S);for(let P=0,k=0,N=0,V=0;P<R.length;P++)for(k|=(E.encode(R[P])&_)<<N,N+=y;N>=8;N-=8,k>>=8)D[V++]=k&255;return D},decode:x=>{let R=e(t);for(let D=0,P=0,k=0,N=0;D<x.length;D++)for(P|=x[D]<<k,k+=8;k>=y;k-=y,P>>=y)R[N++]=E.decode(P&_);return R}}}}},Hd=r=>(e,t)=>{t||(t=r.blockLen);let n=new Uint8Array(e.length+2);n.set(e);let s=e.length,o=new Uint8Array(t),i=r.create({}),c=0,a=0;return{stats:()=>({calls:c,xofs:a}),get:(l,u)=>(n[s+0]=l,n[s+1]=u,i.destroy(),i=r.create({}).update(n),c++,()=>(a++,i.xofInto(o))),clean:()=>{i.destroy(),X(o,n)}}},Yc=Hd(Jc);var Ee=256,be=3329,$d=3303,Kd=17,Re=Gc({N:Ee,Q:be,F:$d,ROOT_OF_UNITY:Kd,newPoly:r=>new Uint16Array(r),brvBits:7,isKyber:!0}),Wd=Object.freeze({512:Object.freeze({N:Ee,Q:be,K:2,ETA1:3,ETA2:2,du:10,dv:4,RBGstrength:128}),768:Object.freeze({N:Ee,Q:be,K:3,ETA1:2,ETA2:2,du:10,dv:4,RBGstrength:192}),1024:Object.freeze({N:Ee,Q:be,K:4,ETA1:2,ETA2:2,du:11,dv:5,RBGstrength:256})}),jd=r=>{if(r>=12)return{encode:t=>t,decode:t=>t>=be?t-be:t};let e=2**(r-1);return{encode:t=>((t<<r)+be/2)/be,decode:t=>t*be+e>>>r}},Vd=r=>Re.bitsCoder(r,r===12?{encode:e=>e,decode:e=>e>=be?e-be:e}:{encode:e=>e,decode:e=>e}),Vn=r=>r===12?Vd(12):Re.bitsCoder(r,jd(r));function tr(r,e){let t=r,n=e;for(let s=0;s<Ee;s++){let o=t[s]+n[s];t[s]=o>=be?o-be:o}}function Jd(r,e){let t=r,n=e;for(let s=0;s<Ee;s++){let o=t[s]-n[s];t[s]=o<0?o+be:o}}function Gd(r,e,t,n,s){let o=Re.mod(Re.mod(e*n)*s+r*t),i=Re.mod(r*n+e*t);return{c0:o,c1:i}}function lo(r,e){let t=r,n=e;for(let s=0;s<Ee/2;s++){let o=Re.nttZetas[64+(s>>1)];s&1&&(o=-o);let{c0:i,c1:c}=Gd(t[2*s+0],t[2*s+1],n[2*s+0],n[2*s+1],o);t[2*s+0]=i,t[2*s+1]=c}return t}function Vi(r){let e=r,t=new Uint16Array(Ee);for(let n=0;n<Ee;){let s=e();if(s.length%3)throw new Error("SampleNTT: unaligned block");for(let o=0;n<Ee&&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<be&&(t[n++]=i),n<Ee&&c<be&&(t[n++]=c)}}return t}var Yd=(r,e)=>{let t=new Uint16Array(Ee),n=In(r);Ir(n);let s=0;for(let o=0,i=0,c=0,a=0;o<n.length;o++){let l=n[o];for(let u=0;u<32;u++)c+=l&1,l>>=1,s+=1,s===e?(a=c,c=0):s===2*e&&(t[i++]=Re.mod(a-c),c=0,s=0)}if(Ir(n),s)throw new Error(`sampleCBD: leftover bits: ${s}`);return t};function Jn(r,e,t,n){return Yd(r(n*Ee/4,e,t),n)}var Xd=r=>{let e=r,{K:t,PRF:n,XOF:s,HASH512:o,ETA1:i,ETA2:c,du:a,dv:l}=e,u=Vn(1),d=Vn(l),p=Vn(a),f=er("publicKey",ao(Vn(12),t),32),m=ao(Vn(12),t),h=er("ciphertext",ao(p,t),d),g=er("seed",32,32),b=(w,y,E,_)=>{let S=[];for(let k=0;k<t;k++)S.push(Re.NTT.encode(Jn(n,_,k,i)));let x=new Uint16Array(Ee),R=[];for(let k=0;k<t;k++){let N=Jn(n,_,t+k,c),V=new Uint16Array(Ee);for(let z=0;z<t;z++){let ue=y(k,z);tr(V,lo(ue,S[z]))}tr(N,Re.NTT.decode(V)),R.push(N),tr(x,lo(w[k],S[k])),X(V)}let D=Jn(n,_,2*t,c);tr(D,Re.NTT.decode(x));let P=u.decode(E);return tr(P,D),X(w,S,x,D),h.encode([R,P])};return{secretCoder:m,lengths:{secretKey:m.bytesLen,publicKey:f.bytesLen,cipherText:h.bytesLen},keygen:w=>{Je(w,32,"seed");let y=new Uint8Array(33);y.set(w),y[32]=t;let E=o(y),[_,S]=g.decode(E),x=[],R=[];for(let k=0;k<t;k++)x.push(Re.NTT.encode(Jn(n,S,k,i)));let D=s(_);for(let k=0;k<t;k++){let N=Re.NTT.encode(Jn(n,S,t+k,i));for(let V=0;V<t;V++){let z=Vi(D.get(V,k));tr(N,lo(z,x[V]))}R.push(N)}D.clean();let P={publicKey:f.encode([R,_]),secretKey:m.encode(x)};return X(_,S,x,R,y,E),P},encrypt:(w,y,E)=>{let[_,S]=f.decode(w),x=s(S),R=b(_,(D,P)=>Vi(x.get(D,P)),y,E);return x.clean(),R},prepare:w=>{let[y,E]=f.decode(w),_=s(E),S=[];for(let x=0;x<t;x++)for(let R=0;R<t;R++)S.push(Vi(_.get(x,R)));return _.clean(),{encrypt:(x,R)=>b(y.map(D=>D.slice()),(D,P)=>S[D*t+P].slice(),x,R),clean:()=>X(y,S)}},decrypt:(w,y)=>{let[E,_]=h.decode(w),S=m.decode(y),x=new Uint16Array(Ee);for(let D=0;D<t;D++)tr(x,lo(S[D],Re.NTT.encode(E[D])));Jd(_,Re.NTT.decode(x));let R=u.encode(_);return X(x,S,E,_),R}}};function zd(r){let e=r,t=Xd(e),{HASH256:n,HASH512:s,KDF:o}=e,{secretCoder:i,lengths:c}=t,a=er("secretKey",c.secretKey,c.publicKey,32,32),l=32,u=64,d=(f,m)=>{let h=f.subarray(0,384*e.K),g=i.encode(i.decode(mt(h))),b=qt(g,h);if(X(g),!b)throw new Error(`ML-KEM.${m}: wrong publicKey modulus`)},p=Object.freeze({...c,seed:64,msg:l,msgRand:l,secretKey:a.bytesLen});return Object.freeze({info:Object.freeze({type:"ml-kem"}),lengths:p,keygen:f=>{let m=f===void 0,h=m?ft(u):f,g,b;try{Je(h,u,"seed");let w=t.keygen(h.subarray(0,32)),y=w.publicKey;g=w.secretKey,b=n(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:f=>{let[m,h,g,b]=a.decode(f);return Uint8Array.from(h)},encapsulate:(f,m)=>{let h=m===void 0,g=h?ft(l):m,b;try{return Je(f,c.publicKey,"publicKey"),Je(g,l,"message"),d(f,"encapsulate"),b=s.create().update(g).update(n(f)).digest(),{cipherText:t.encrypt(f,g,b.subarray(32,64)),sharedSecret:b.subarray(0,32)}}finally{b!==void 0&&X(b.subarray(32)),h&&X(g)}},decapsulate:(f,m)=>{Je(m,a.bytesLen,"secretKey"),Je(f,c.cipherText,"cipherText");let h=a.bytesLen-96,g=h+32,b=n(m.subarray(h/2,g));if(!qt(b,m.subarray(g,g+32)))throw new Error("invalid secretKey: hash check failed");let[w,y,E,_]=a.decode(m),S=t.decrypt(f,w),x=s.create().update(S).update(E).digest(),R=x.subarray(0,32),D=t.encrypt(y,S,x.subarray(32,64)),P=qt(f,D),k=o.create({dkLen:32}).update(_).update(f).digest();return X(S,D,x.subarray(32),P?k:R),P?R:k},prepare:f=>{Je(f,c.publicKey,"publicKey"),d(f,"prepare");let m=mt(f),h=n(m),g=t.prepare(m);return Object.freeze({publicKey:m,encapsulate:b=>{let w=b===void 0,y=w?ft(l):b,E;try{return Je(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)=>{Je(w,a.bytesLen,"secretKey"),Je(b,c.cipherText,"cipherText");let[y,E,_,S]=a.decode(w);if(!qt(E,m)||!qt(_,h))throw new Error("ML-KEM.decapsulate: secretKey does not match prepared publicKey");let x=t.decrypt(b,y),R=s.create().update(x).update(h).digest(),D=R.subarray(0,32),P=g.encrypt(x,R.subarray(32,64)),k=qt(b,P),N=o.create({dkLen:32}).update(S).update(b).digest();return X(x,P,R.subarray(32),k?N:D),k?D:N},clean:g.clean})}})}function Qd(r,e,t){return $r.create({dkLen:r}).update(e).update(new Uint8Array([t])).digest()}var Zd={HASH256:io,HASH512:jc,KDF:$r,XOF:Yc,PRF:Qd},qd=r=>zd({...Zd,...r});var Xc=qd(Wd[768]);var ep=(r,e)=>{let t=ji(r,e);return ji(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 Kr(r,e){let t=le(r,e);if(t===0)throw new RangeError(`"${e}" expected integer greater than 0, got 0`);return t}function Gn(r,e){let t=er(e,...r.map(n=>{if(typeof n.lengths[e]!="number")throw new Error("wrong length: "+e);return Kr(n.lengths[e],e)}));return Kr(t.bytesLen,e),t}function tp(r,e,...t){let n=e,s=t,o=Gn(s,"seed"),i=Gn(s,"publicKey"),c=Kr(r===void 0?o.bytesLen:r,"realSeedLen");function a(u){Y(u,c);let d=n(u,o.bytesLen),p=d.buffer===u.buffer?mt(d):d,f=[],m=[],h=[],g=[],b=!1;try{for(let w of o.decode(p))f.push(mt(w));for(let w=0;w<s.length;w++){let y=s[w].keygen(f[w]);m.push(y.secretKey),h.push(mt(y.secretKey)),g.push(y.publicKey)}return b=!0,{secretKey:h,publicKey:g}}finally{X(p,f,m),b||X(h)}}let l=u=>{let d=u===void 0?ft(c):mt(u),p;try{let{publicKey:f,secretKey:m}=a(d);try{p={secretKey:d,publicKey:i.encode(f)}}finally{X(f,m)}return p}finally{p||X(d)}};return{info:{lengths:{seed:c,publicKey:i.bytesLen,secretKey:c}},getPublicKey:u=>{let d=l(u);return X(d.secretKey),d.publicKey},keygen:l,expandDecapsulationKey:a,realSeedLen:c}}function rp(r,e,t,n,...s){if(r!==void 0&&Kr(r,"realSeedLen"),e!==void 0&&Kr(e,"realMsgLen"),typeof t!="function")throw new TypeError('"expandSeed" expected function, got type='+typeof t);if(typeof n!="function")throw new TypeError('"combiner" expected function, got type='+typeof n);let o=n,i=s;if(i.length===0)throw new RangeError("combineKEMS requires at least one KEM");for(let m=0;m<i.length;m++)ep(i[m],`kems[${m}]`);let c=tp(r,t,...i),a=Gn(i,"cipherText"),l=Gn(i,"publicKey"),u=Gn(i,"msg"),d=Kr(e===void 0?u.bytesLen:e,"realMsgLen"),p=Object.freeze({...c.info.lengths,msg:d,msgRand:u.bytesLen,cipherText:a.bytesLen}),f=(m,h,g)=>{let b=o(m,h,g);try{return mt(Y(b,d,"sharedSecret"))}catch(w){if(Xt(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:p,getPublicKey:c.getPublicKey,keygen:c.keygen,encapsulate(m,h=ft(u.bytesLen)){let g=l.decode(m),b=u.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:f(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 f(b,g,y)}finally{X(w,y)}}})}function np(r,e,t,n){let s=r.Point.Fn;if(!s)throw new Error("no Point.Fn");function o(c){let a;for(let d=0,p=e;;d=p,p+=e){if(p>c.length)throw new Error("rejection sampling failed");if(a=s.fromBytes(c.subarray(d,p),!0),s.isValidNot0(a))break}let l=s.toBytes(s.create(a)),u=r.getPublicKey(l,!1);return{secretKey:l,publicKey:u}}let i=(c,a)=>r.getSharedSecret(a,c).subarray(1);return{lengths:{secretKey:e,publicKey:t,seed:n,msg:n,cipherText:t},keygen(c=ft(n)){return Y(c,n,"seed"),o(c)},getPublicKey(c){return r.getPublicKey(c,!1)},encapsulate(c,a=ft(n)){Y(a,n,"rand");let l;try{l=o(a).secretKey;let u=i(c,l),d=r.getPublicKey(l,!1);return{sharedSecret:u,cipherText:d}}finally{l&&X(l)}},decapsulate:i}}function sp(r,e,t,n){let{secretKey:s,publicKeyUncompressed:o}=t.lengths;if(!s||!o)throw new Error("wrong curve");let i=np(t,s,o,n),a=64+n;return rp(32,32,l=>(Y(l,32),$r(l,{dkLen:a})),(l,u,d)=>io(We(d[0],d[1],u[1],l[1],Qa(r))),e,i)}var zc=sp("MLKEM768-P256",Xc,Uc,128);function Qc(r){let e=zc.encapsulate(r);return{kemCtBase64:Yt(e.cipherText),sharedSecret:e.sharedSecret}}async function Zc(r){let e=crypto.subtle,t=await e.importKey("raw",r,{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 qc(r,e){let t=crypto.getRandomValues(new Uint8Array(12)),n=new TextEncoder().encode(JSON.stringify(e)),s=await crypto.subtle.encrypt({name:"AES-GCM",iv:t},r,n),o={iv:Yt(t),ciphertext:Yt(s)};return JSON.stringify(o)}var op=3600*1e3,po=new Map,uo=new Map;function el(r){return po.get(r)||null}async function tl(r,e,t){let n=Date.now(),s=po.get(e);if(s&&s.expiresAt>n)return s;let o=uo.get(e);if(o)return await o;let i=(async()=>{try{return await ip(r,e,t)}finally{uo.delete(e)}})();return uo.set(e,i),await i}async function ip(r,e,t){let n=Date.now(),s=Math.floor(n/1e3),o=s+3600,i=$s(t),{kemCtBase64:c,sharedSecret:a}=Qc(i),l=await Zc(a),u=`kem_${On()}`;try{await r.prepare("INSERT INTO kem_keys (id, profile_id, kem_ct, created_at, expires_at) VALUES (?, ?, ?, ?, ?)").bind(u,e,c,s,o).run()}catch(p){console.error(`[DekManager] Failed to persist kem_key ${u} to D1:`,p)}let d={kemKeyId:u,dek:l,profileId:e,createdAt:n,expiresAt:n+op};return po.set(e,d),d}function rl(r){po.delete(r),uo.delete(r)}var Gi=new Map;async function ap(r,e){let t=Date.now(),n=Gi.get(e);if(n&&n.expiresAt>t)return n.key;try{let s=null;try{s=await r.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 r.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=300*1e3;return Gi.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 nr(r){Gi.delete(r),rl(r)}var rr=[],nl=50,sl=15e3,Ji=3600,fo=0,Yn=!1,ol=Date.now();async function cp(r){let e=Date.now();if(fo>e)return!0;if(r)try{let t=await v.get(r,"d1:write_quota_tripped");if(t&&t>Math.floor(e/1e3))return fo=t*1e3,!0}catch{}return!1}async function lp(r){let t=Math.floor(Date.now()/1e3)+Ji;if(fo=t*1e3,rr.length=0,Yn=!1,console.warn(`[LogBatcher] D1 write quota limit reached! Silencing log writes for ${Ji}s.`),r)try{await v.set(r,"d1:write_quota_tripped",t,Ji)}catch{}}async function mo(r,e){if(Yn=!1,ol=Date.now(),rr.length===0)return;let t=caches.default;if(await cp(t)){rr.length=0;return}let n=rr.splice(0,nl);if(n.length===0)return;let s=new Ie(r.DB),o=[],i=Array.from(new Set(n.map(l=>l.profile_id))),c=new Map,a=new Map;await Promise.all(i.map(async l=>{let u=await ap(r.DB,l);if(u&&(c.set(l,u),"pqc_pk"in u)){let d=el(l);d||(d=await tl(r.DB,l,u.pqc_pk)),d&&a.set(l,d)}}));for(let l of n){let u=c.get(l.profile_id);if(u)try{let d={domain:l.domain,client_ip:l.client_ip,geo_country:l.geo_country,answer:l.answer,dest_geoip:l.dest_geoip,dest_country_code:l.dest_country_code,dest_country:l.dest_country,dest_isp:l.dest_isp,ecs:l.ecs,upstream:l.upstream,reason:l.reason};if("pqc_pk"in u){let p=a.get(l.profile_id);if(p){let f=await qc(p.dek,d);l.encrypt_version=2,l.kem_key_id=p.kemKeyId,l.encrypted_payload=f}}else if("kty"in u){let p=await Ka(u,d);l.encrypt_version=1,l.kem_key_id=null,l.encrypted_payload=p}l.encrypt_version&&l.encrypt_version>0&&(l.domain="",l.client_ip="",l.geo_country="",l.answer=void 0,l.dest_geoip=void 0,l.dest_country_code=null,l.dest_country=null,l.dest_isp=null,l.ecs=void 0,l.upstream=void 0,l.reason=void 0)}catch(d){console.error(`[LogBatcher] Encryption failed for profile ${l.profile_id}:`,d)}else l.encrypt_version=0,l.kem_key_id=null;o.push(s.createInsertStatement(l))}try{await r.DB.batch(o)}catch(l){let u=String(l?.message||l);u.includes("exceeded D1's free tier daily row write limit")||u.includes("row write limit")||u.includes("daily write limit")?await lp(t):console.warn(`[LogBatcher] Batch write failed (${o.length} stmts):`,u)}rr.length>0&&il(r,e)}function il(r,e){if(Yn)return;Yn=!0;let t=new Promise(n=>setTimeout(n,sl)).then(()=>mo(r,e)).catch(n=>{Yn=!1,console.error("[LogBatcher] Deferred flush error:",n)});e&&typeof e.waitUntil=="function"&&e.waitUntil(t)}function Xn(r,e,t,n){if(e&&Number(e.log_retention_days)===0)return;let s=(r.action||"PASS").toUpperCase();if(e?.skip_log_on_pass&&s==="PASS"||fo>Date.now())return;r.id||(r.id=On()),rr.push(r);let o=Date.now();rr.length>=nl||o-ol>=sl?n.waitUntil(mo(t,n)):il(t,n)}async function al(r,e,t,n,s,o,i,c,a){let l=r.headers.get("CF-Connecting-IP")||"127.0.0.1",u,d=i||"";if(s==="REDIRECT"&&i)if(c==="CNAME"&&(e.type==="A"||e.type==="AAAA")&&a)try{let f=Kt(i,e.type),m={name:i,type:e.type,raw:f},h=await a(r,m,t,n,"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});u=si(e.raw,b,0)}else u=_e(e.raw,c,i)}catch(f){console.error("CNAME resolution failed:",f),u=_e(e.raw,c,i)}else u=_e(e.raw,c||e.type,i);else{let f=n.block_mode||"NULL_IP";if(f==="NXDOMAIN")u=_e(e.raw,e.type,"",3600,3),d="NXDOMAIN";else if(f==="NODATA")u=_e(e.raw,e.type,"",3600,0),d="NODATA";else if(f==="CUSTOM_IP"){let m=e.type==="AAAA"?n.custom_block_ipv6||"::":n.custom_block_ipv4||"0.0.0.0";u=_e(e.raw,e.type,m),d=m}else{let m=e.type==="AAAA"?"::":"0.0.0.0";u=_e(e.raw,e.type,m),d=m}}let p=Date.now()-t.startTime;return t.ctx.waitUntil((async()=>{try{let f=await Gt(r,l);Xn({profile_id:t.profileId,access_point_id:t.accessPointId,timestamp:Math.floor(Date.now()/1e3),client_ip:l,geo_country:f,domain:e.name,record_type:e.type,action:s,reason:o,answer:d,latency:p},n,t.env,t.ctx)}catch{}})()),{answer:u,ttl:3600,action:s,reason:o,latency:p}}function cl(r,e,t,n,s,o,i,c,a,l,u){let d=r.headers.get("CF-Connecting-IP")||"127.0.0.1";t.ctx.waitUntil((async()=>{try{let p=Gt(r,d),f=i.find(E=>E.type==="A"||E.type==="AAAA")?.data,m="",h=null,g=null,b=null;if(f){let E=await Ln(f);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 p,y=Date.now()-t.startTime;Xn({profile_id:t.profileId,access_point_id:t.accessPointId,timestamp:Math.floor(Date.now()/1e3),client_ip:d,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:u},n,t.env,t.ctx),c.length>0&&Sr.set(`${t.profileId}:${e.name}:${e.type}`,{answer:c,ttl:a,action:s,reason:o,expiresAt:Date.now()+a*1e3})}catch{}})())}function ll(r,e,t,n,s,o,i,c,a){let l=0,u,d=o instanceof Error?o.message:String(o),p,f;if(o instanceof kr)l=o.status,u=o.statusText||void 0,p=o.responseBodySnippet||void 0,f=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);d+=` (Cause: ${y})`}let m=l>0?`Upstream HTTP ${l}${u?` ${u}`:""}`:`Upstream Error: ${d}`,h=r.headers.get("CF-Connecting-IP")||"127.0.0.1";t.ctx.waitUntil((async()=>{try{let w=await Gt(r,h);Xn({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},n,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:u,error_detail:d,response_body:p,cf_ray:f}}}var nt={async resolve(r,e,t,n,s,o){let i=n.upstream[0]||"https://security.cloudflare-dns.com/dns-query";if(!lt(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}=Ba(r,e,n),l;try{l=At(i);let u=await Dt(l,c),d=ke(u.answer),p=await Fa(e,d,u.answer,t,n,r,nt.resolve,o),f=p.answer,m=p.parsedAnswers,h=p.effectiveReason,g=m.length>0?Math.max(10,Math.min(...m.map(b=>b.ttl))):60;return cl(r,e,t,n,s,h,m,f,g,i,a),{answer:f,ttl:g,action:s,reason:h,latency:Date.now()-t.startTime,timings:{upstream_fetch:u.latency},diagnostics:{upstream_url:i.startsWith("sdns://")?`${i} (${u.diagTarget})`:u.diagTarget,method:u.diagMethod,status:200,status_text:"OK"}}}catch(u){return ll(r,e,t,n,i,u,a,l?.diagTarget,l?.diagMethod)}},async block(r,e,t,n,s,o,i,c){return al(r,e,t,n,s,o,i,c,nt.resolve)}};var Wr=class{static isMatch(e,t){let n=e.toLowerCase(),s=t.toLowerCase();return n===s||n.endsWith(`.${s}`)}static findMatch(e,t){for(let n of t)if(this.isMatch(e,n.pattern))return n;return null}};var ul={async match(r,e,t,n,s,o,i){let c=e.name.toLowerCase(),a=s.filter(f=>f.type==="ALLOW");if(Wr.findMatch(e.name,a))return i("local_rules"),nt.resolve(r,e,t,n,"PASS","Whitelist");let l=s.filter(f=>f.type==="REDIRECT"),u=Wr.findMatch(e.name,l);if(u){let f,m=e.type;if(e.type==="A"?(f=u.v_a,!f&&u.v_cname&&(f=u.v_cname,m="CNAME")):e.type==="AAAA"?(f=u.v_aaaa,!f&&u.v_cname&&(f=u.v_cname,m="CNAME")):e.type==="TXT"?f=u.v_txt:e.type==="CNAME"&&(f=u.v_cname),f)return i("local_rules"),await nt.block(r,e,t,n,"REDIRECT",`Rule: ${u.pattern}`,f,m)}let d=s.filter(f=>f.type==="BLOCK"),p=Wr.findMatch(e.name,d);if(p)return i("local_rules"),nt.block(r,e,t,n,"BLOCK",`Blacklist: ${p.pattern}`);if(i("local_rules"),o){let f=c;for(;f;){if(o.test(f))return i("bloom_check"),nt.block(r,e,t,n,"BLOCK",`External List: ${f}`);let m=f.indexOf(".");if(m===-1)break;f=f.substring(m+1)}i("bloom_check")}return null}};var ce={clearCache:_s.clear,async process(r,e,t){let n={},s=t.startTime,o=u=>{let d=Date.now();n[u]=(n[u]||0)+(d-s),s=d};if(e.name.toLowerCase()==="obex"&&e.type==="TXT")return{answer:_e(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=Sr.get(`${t.profileId}:${e.name}:${e.type}`);if(i&&Date.now()<i.expiresAt&&i.answer instanceof Uint8Array){let u=new Uint8Array(i.answer);u.length>=2&&e.raw.length>=2&&(u[0]=e.raw[0],u[1]=e.raw[1]);let d=Date.now()-t.startTime;return{answer:u,ttl:Math.ceil((i.expiresAt-Date.now())/1e3),action:i.action,reason:i.reason,latency:d,timings:{dns_cache_mem:d}}}let c=await Oa.load(t,o);if(!c)return{answer:new Uint8Array,ttl:0,action:"FAIL",reason:"Profile Not Found"};let a=await ul.match(r,e,t,c.settings,c.rules,c.bloom,o);if(a)return{...a,timings:{...n,...a.timings}};if(c.settings.default_policy==="BLOCK"){let u=await nt.block(r,e,t,c.settings,"BLOCK","Default Policy");return{...u,timings:{...n,...u.timings}}}let l=await nt.resolve(r,e,t,c.settings,"PASS");return{...l,timings:{...n,...l.timings}}}};function up(r){if(!r||typeof r!="object")return null;let e=0;for(let t of Object.keys(r)){let n=t.match(/^KEK_[vV](\d+)$/);if(n){let s=r[t];if(s!=null&&s!==""){let o=parseInt(n[1],10);!isNaN(o)&&o>e&&(e=o)}}}return e>0?`v${e}`:null}function ho(r,e){if(!e)return null;let t=e[`KEK_${r}`]||e[`KEK_${r.toUpperCase()}`];return t&&typeof t=="string"&&t.trim()!==""?t:(r==="v0"||r==="default")&&e.JWT_SECRET&&typeof e.JWT_SECRET=="string"&&e.JWT_SECRET.trim()!==""?e.JWT_SECRET:null}function jr(r){let e="",t=r.byteLength;for(let n=0;n<t;n++)e+=String.fromCharCode(r[n]);return btoa(e)}function Vr(r){let e=atob(r),t=e.length,n=new Uint8Array(t);for(let s=0;s<t;s++)n[s]=e.charCodeAt(s);return n}async function go(r){let t=new TextEncoder().encode(r.trim()),n=await crypto.subtle.digest("SHA-256",t);return await crypto.subtle.importKey("raw",n,{name:"AES-GCM"},!1,["encrypt","decrypt"])}async function dl(r){return await crypto.subtle.importKey("raw",r,{name:"AES-GCM"},!1,["encrypt","decrypt"])}async function Ot(r,e){let t=up(e);if(!t)return null;let n=ho(t,e);if(!n||typeof n!="string"||n.trim()==="")throw new Error(`KEK version ${t} is missing or invalid in environment variables`);let s=await go(n),o=new Uint8Array(32);crypto.getRandomValues(o);let i=await dl(o),c=new Uint8Array(12);crypto.getRandomValues(c);let l=new TextEncoder().encode(r),u=await crypto.subtle.encrypt({name:"AES-GCM",iv:c},i,l),d={ciphertext:jr(new Uint8Array(u)),iv:jr(c)},p=new Uint8Array(12);crypto.getRandomValues(p);let f=await crypto.subtle.encrypt({name:"AES-GCM",iv:p},s,o),m={ciphertext:jr(new Uint8Array(f)),iv:jr(p),kek_version:t};return{dataEncrypted:JSON.stringify(d),dekEncrypted:JSON.stringify(m)}}async function Yi(r,e,t){let n,s;try{n=JSON.parse(r),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=ho(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 go(c),l=Vr(s.ciphertext),u=Vr(s.iv),d=await crypto.subtle.decrypt({name:"AES-GCM",iv:u},a,l),p=new Uint8Array(d),f=await dl(p),m=Vr(n.ciphertext),h=Vr(n.iv),g=await crypto.subtle.decrypt({name:"AES-GCM",iv:h},f,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 Xi(r,e){if(!e)return null;let t;try{t=JSON.parse(r)}catch{return null}let n=t.kek_version,s=parseInt(n.replace(/^v/,""),10);if(isNaN(s))return null;let i=`v${s+1}`,c=ho(i,e);if(!c||typeof c!="string"||c.trim()==="")return null;let a=ho(n,e);if(!a||typeof a!="string"||a.trim()==="")throw new Error(`Current KEK version ${n} required for rotation is missing or invalid in environment`);let l=await go(a),u=Vr(t.ciphertext),d=Vr(t.iv),p=await crypto.subtle.decrypt({name:"AES-GCM",iv:d},l,u),f=new Uint8Array(p),m=await go(c),h=new Uint8Array(12);crypto.getRandomValues(h);let g=await crypto.subtle.encrypt({name:"AES-GCM",iv:h},m,f),b={ciphertext:jr(new Uint8Array(g)),iv:jr(h),kek_version:i};return JSON.stringify(b)}var yo=class{constructor(e,t){this.db=e;this.env=t}db;env;async processUserSecrets(e){if(!e)return null;let t={},n=!1,s=e.totp_secret;if(e.totp_secret_encrypted&&e.totp_secret_dek)try{s=await Yi(e.totp_secret_encrypted,e.totp_secret_dek,this.env);let i=await Xi(e.totp_secret_dek,this.env);i&&(t.totp_secret_dek=i,n=!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 Ot(e.totp_secret,this.env);i&&(t.totp_secret_encrypted=i.dataEncrypted,t.totp_secret_dek=i.dekEncrypted,t.totp_secret=null,n=!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 Yi(e.totp_recovery_keys_encrypted,e.totp_recovery_keys_dek,this.env);let i=await Xi(e.totp_recovery_keys_dek,this.env);i&&(t.totp_recovery_keys_dek=i,n=!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 Ot(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,n=!0)}catch(i){console.error(`[Envelope Encryption] Migration failed for totp_recovery_keys of user ${e.id}:`,i)}if(n)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 wo=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(`
|
|
324
|
+
`,a=[e,n,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(u=>({name:u.name||"Unknown",count:u.count}))}};var Hs=class{constructor(e,t){this.db=e;this.traffic=new Us(e),this.domains=new Ms(e),this.clients=new Bs(e),this.destinations=new Fs(e)}db;traffic;domains;clients;destinations;async getSummary(e,t,n,s,o){return this.traffic.getSummary(e,t,n,s,o)}async getTrend(e,t,n,s,o){return this.traffic.getTrend(e,t,n,s,o)}async getTopAllowed(e,t,n,s){return this.domains.getTopAllowed(e,t,n,s)}async getTopBlocked(e,t,n,s){return this.domains.getTopBlocked(e,t,n,s)}async getClients(e,t,n,s){return this.clients.getClients(e,t,n,s)}async getDestinations(e,t,n,s,o=250){return this.destinations.getDestinations(e,t,n,s,o)}async getISPByCountry(e,t,n,s,o,i=250){return this.destinations.getISPByCountry(e,t,n,s,o,i)}async getAnalytics(e,t,n,s,o){let[i,c,a,l,u,d]=await Promise.all([this.getSummary(e,t,n,void 0,o),this.getTrend(e,t,n,s,o),this.getTopAllowed(e,t,n,o),this.getTopBlocked(e,t,n,o),this.getClients(e,t,n,o),this.getDestinations(e,t,n,o)]);return{summary:i,trend:c,top_allowed:a,top_blocked:l,clients:u,destinations:d}}};var Ue=class{constructor(e){this.db=e;this.core=new Os(e),this.aggregation=new Ns(e),this.retention=new Is(e),this.analytics=new Hs(e,this.aggregation),this.kemKeys=new Lr(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,n){return this.core.getLog(e,t,n)}async deleteByOwner(e){return this.core.deleteByOwner(e)}async cleanup(e,t,n=1e3){return this.core.cleanup(e,t,n)}async cleanupGlobal(e=30,t=1e3,n=2e4){return this.retention.cleanupGlobal(e,t,n)}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,n=2){return this.aggregation.aggregateHourlyRollups(e,t,n)}async getSummary(e,t,n,s,o){return this.analytics.getSummary(e,t,n,s,o)}async getTrend(e,t,n,s,o){return this.analytics.getTrend(e,t,n,s,o)}async getTopAllowed(e,t,n,s){return this.analytics.getTopAllowed(e,t,n,s)}async getTopBlocked(e,t,n,s){return this.analytics.getTopBlocked(e,t,n,s)}async getClients(e,t,n,s){return this.analytics.getClients(e,t,n,s)}async getDestinations(e,t,n,s,o=250){return this.analytics.getDestinations(e,t,n,s,o)}async getISPByCountry(e,t,n,s,o,i=250){return this.analytics.getISPByCountry(e,t,n,s,o,i)}async getAnalytics(e,t,n,s,o){return this.analytics.getAnalytics(e,t,n,s,o)}};ge();function Yt(r){let e=r instanceof Uint8Array?r:new Uint8Array(r);if(typeof Buffer<"u")return Buffer.from(e).toString("base64");let t="";for(let n=0;n<e.length;n++)t+=String.fromCharCode(e[n]);return btoa(t)}function $s(r){if(typeof Buffer<"u")return new Uint8Array(Buffer.from(r,"base64"));let e=atob(r),t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n);return t}async function Ka(r,e){let t=crypto.subtle,n=await t.generateKey({name:"ECDH",namedCurve:"P-256"},!0,["deriveKey"]),s=await t.importKey("jwk",r,{name:"ECDH",namedCurve:"P-256"},!1,[]),o=await t.deriveKey({name:"ECDH",public:s,$public:s},n.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),u={ephem_pk:await t.exportKey("jwk",n.publicKey),iv:Yt(i),ciphertext:Yt(a)};return JSON.stringify(u)}function Xt(r){return r instanceof Uint8Array||ArrayBuffer.isView(r)&&r.constructor.name==="Uint8Array"&&"BYTES_PER_ELEMENT"in r&&r.BYTES_PER_ELEMENT===1}var Ks=r=>r?`"${r}" `:"";function le(r,e=""){if(typeof r!="number")throw new TypeError(Ks(e)+"expected number, got "+typeof r);if(!Number.isSafeInteger(r)||r<0)throw new RangeError(Ks(e)+"expected integer >= 0, got "+r);return r}function Va(r,e=""){if(typeof r!="boolean")throw new TypeError(Ks(e)+"expected boolean, got type="+typeof r);return r}function Y(r,e,t=""){if(Xt(r)&&(e===void 0||r.length===e))return r;e!==void 0&&le(e,"length");let n=Xt(r),s=e!==void 0?` of length ${e}`:"",o=n?`length=${r.length}`:`type=${typeof r}`,i=Ks(t)+"expected Uint8Array"+s+", got "+o;throw n?new RangeError(i):new TypeError(i)}function Or(r){if(typeof r!="function"||typeof r.create!="function")throw new TypeError("expected hash wrapped by utils.createHasher");if(le(r.outputLen),le(r.blockLen),r.outputLen<1||r.blockLen<1)throw new Error("hash blockLen / outputLen must be >= 1")}var Ju=(r,e)=>{if(r===null||typeof r!="object"||Array.isArray(r))throw new TypeError((e==="object"?"":`"${e}" `)+"expected object, got type="+typeof r)},Wa=(r,e)=>{Ju(r,e);let t=Object.getPrototypeOf(r);if(t!==Object.prototype&&t!==null)throw new TypeError(`"${e}" expected plain object`);if(Object.hasOwn(r,"__proto__"))throw new TypeError(`"${e}.__proto__" is not allowed`)};function dt(r,e=!0){if(r.destroyed)throw new Error("hash was destroyed");if(e&&r.finished)throw new Error("digest() was already called")}function Nr(r,e){Y(r,void 0,"output");let t=e.outputLen;if(!(r.length>=t))throw new RangeError('"output" expected length >= '+t)}function In(r){return new Uint32Array(r.buffer,r.byteOffset,Math.floor(r.byteLength/4))}function vt(...r){for(let e=0;e<r.length;e++)r[e].fill(0)}function Ws(r){return new DataView(r.buffer,r.byteOffset,r.byteLength)}function We(r,e){return r<<32-e|r>>>e}var Ja=new Uint8Array(new Uint32Array([287454020]).buffer)[0]===68;function Gu(r){return r<<24&4278190080|r<<8&16711680|r>>>8&65280|r>>>24&255}function Yu(r){for(let e=0;e<r.length;e++)r[e]=Gu(r[e]);return r}var Ir=Ja?r=>r:Yu,Ga=typeof Uint8Array.from([]).toHex=="function"&&typeof Uint8Array.fromHex=="function",Xu=Array.from({length:256},(r,e)=>e.toString(16).padStart(2,"0"));function Un(r){if(Y(r),Ga)return r.toHex();let e="";for(let t=0;t<r.length;t++)e+=Xu[r[t]];return e}function ja(r){return r>=48&&r<=57?r-48:r>=65&&r<=70?r-55:r>=97&&r<=102?r-87:void 0}function wi(r){if(typeof r!="string")throw new TypeError("hex string expected, got "+typeof r);if(Ga)try{return Uint8Array.fromHex(r)}catch(s){throw s instanceof SyntaxError?new RangeError(s.message):s}let e=r.length,t=e/2;if(e%2)throw new RangeError("hex string expected, got unpadded hex of length "+e);let n=new Uint8Array(t);for(let s=0,o=0;s<t;s++,o+=2){let i=ja(r.charCodeAt(o)),c=ja(r.charCodeAt(o+1));if(i===void 0||c===void 0){let a=r[o]+r[o+1];throw new RangeError('hex string expected, got non-hex character "'+a+'" at index '+o)}n[s]=i*16+c}return n}function bi(...r){let e=0;for(let n=0;n<r.length;n++){let s=r[n];Y(s),e+=s.length}let t=new Uint8Array(e);for(let n=0,s=0;n<r.length;n++){let o=r[n];t.set(o,s),s+=o.length}return t}function Ei(r,e,t="opts"){return Wa(r,"defaults"),e!==void 0&&Wa(e,t),Object.assign(Object.create(null),r,e)}function Mn(r,e={}){if(typeof r!="function")throw new TypeError('"hashCons" expected function, got type='+typeof r);e=Ei({},e,"info");let t=(s,o)=>r(o).update(s).digest(),n=r(void 0);return t.outputLen=n.outputLen,t.blockLen=n.blockLen,t.canXOF=n.canXOF,t.create=s=>r(s),Object.assign(t,e),Object.freeze(t)}function js(r=32){le(r,"bytesLength");let e=typeof globalThis=="object"?globalThis.crypto:null;if(typeof e?.getRandomValues!="function")throw new Error("crypto.getRandomValues must be defined");if(r>65536)throw new RangeError(`"bytesLength" expected <= 65536, got ${r}`);return e.getRandomValues(new Uint8Array(r))}var zt=r=>({oid:Uint8Array.from([6,9,96,134,72,1,101,3,4,2,r])});function Bn(r,e,t=()=>{}){if(!Array.isArray(r))throw new TypeError(`"${e}" expected array, got type=${typeof r}`);for(let n=0;n<r.length;n++)t(r[n],`${e}[${n}]`);return r}var fe=(r,e,t)=>Y(r,e,t),_i=le;function Xa(r,e=""){if(typeof r!="string"){let t=e&&`"${e}" `;throw new TypeError(t+"expected string, got type="+typeof r)}return r}function Pt(r,e="object"){if(r===null||typeof r!="object"||Array.isArray(r))throw new TypeError(e==="object"?"expected valid options object":`"${e}" expected object, got type=${typeof r}`);return r}function Me(r,e){if(typeof r!="function")throw new TypeError(`"${e}" is invalid: expected function, got ${typeof r}`);return r}var Si=Un,je=(...r)=>bi(...r),Js=r=>wi(r),Ur=Xt,Gs=r=>js(r),Vs=BigInt(0),Ya=BigInt(1),zu=r=>r?`"${r}" `:"";function Ve(r,e=""){if(typeof r!="boolean")throw new TypeError(zu(e)+"expected boolean, got type="+typeof r);return r}function Ys(r){if(typeof r=="bigint"){if(!Ct(r))throw new RangeError("positive bigint expected, got "+r)}else _i(r);return r}function Qt(r,e=""){if(typeof r!="number"){let t=e&&`"${e}" `;throw new TypeError(t+"expected number, got type="+typeof r)}if(!Number.isSafeInteger(r)){let t=e&&`"${e}" `;throw new RangeError(t+"expected safe integer, got "+r)}}function Fn(r){let e=Ys(r).toString(16);return e.length&1?"0"+e:e}function za(r){if(typeof r!="string")throw new TypeError("hex string expected, got "+typeof r);return r===""?Vs:BigInt("0x"+r)}function Je(r){return za(Un(r))}function Xs(r){return za(Un(Qu(Y(r)).reverse()))}function Hn(r,e){if(le(e),e===0)throw new Error("zero output length is invalid");r=Ys(r);let t=e*2,n=r.toString(16);if(n.length>t)throw new RangeError("number is too large");return wi(n.padStart(t,"0"))}function Ti(r,e){return Hn(r,e).reverse()}function Qu(r){return Uint8Array.from(fe(r))}function Qa(r){if(typeof r!="string")throw new TypeError("ascii string expected, got "+typeof r);return Uint8Array.from(r,(e,t)=>{let n=e.charCodeAt(0);if(e.length!==1||n>127)throw new RangeError(`string contains non-ASCII character "${r[t]}" with code ${n} at position ${t}`);return n})}function Ct(r){return typeof r=="bigint"&&Vs<=r}function Ri(r,e,t){return Ct(r)&&Ct(e)&&Ct(t)&&e<=r&&r<t}function xi(r,e,t,n){if(!Ri(e,t,n))throw new RangeError("expected valid "+r+": "+t+" <= n < "+n+", got "+e)}function Mr(r){if(r<Vs)throw new Error("expected non-negative bigint, got "+r);return r===Vs?0:r.toString(2).length}var $n=r=>(Qt(r,"n"),(Ya<<BigInt(r))-Ya);function Za(r,e,t){if(le(r,"hashLen"),le(e,"qByteLen"),typeof t!="function")throw new TypeError("hmacFn must be a function");let n=g=>new Uint8Array(g),s=Uint8Array.of(),o=Uint8Array.of(0),i=Uint8Array.of(1),c=1e3,a=n(r),l=n(r),u=0,d=()=>{a.fill(1),l.fill(0),u=0},p=(...g)=>t(l,je(a,...g)),f=(g=s)=>{l=p(o,g),a=p(),g.length!==0&&(l=p(i,g),a=p())},m=()=>{if(u++>=c)throw new Error("drbg: tried max amount of iterations");let g=0,w=[];for(;g<e;){a=p();let b=a.slice();w.push(b),g+=a.length}return je(...w)};return(g,w)=>{d(),f(g);let b;for(;(b=w(m()))===void 0;)f();return d(),b}}function nt(r,e={},t={},n="object"){Pt(r,n),Pt(e,"fields"),Pt(t,"optFields");function s(i,c,a){let l=n==="object"?`param "${String(i)}"`:`"${n}.${String(i)}"`,u=r[i];if(!Object.hasOwn(r,i)&&(a?u!==void 0:c!=="function"))throw new TypeError(`${l} is invalid: expected own property`);if(a&&u===void 0)return;let d=typeof u;if(d!==c||u===null)throw new TypeError(`${l} is invalid: expected ${c}, got ${d}`)}let o=(i,c)=>Object.entries(i).forEach(([a,l])=>s(a,l,c));o(e,!1),o(t,!0)}var ye=BigInt(0),Q=BigInt(1),kt=BigInt(2),rc=BigInt(3),Ai=BigInt(4),nc=BigInt(5),Zu=BigInt(7),sc=BigInt(8),qu=BigInt(9),ed=BigInt(15),oc=BigInt(16),td=BigInt("0x10000000000000000");function Pe(r,e){if(e<=ye)throw new Error("mod: expected positive modulus, got "+e);let t=r%e;return t>=ye?t:e+t}function ic(r,e,t){if(t<=Q)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 Q;if(e===Q)return r;let n=r%t;if(n<ye&&(n+=t),e<td){let c=Q;for(;e>ye;)e&Q&&(c=c*n%t),n=n*n%t,e>>=Q;return c}let s=[];for(;e>ye;)s.push(Number(e&ed)),e>>=Ai;let o=new Array(16);o[0]=Q,o[1]=n;for(let c=2;c<16;c++)o[c]=o[c-1]*n%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 qa(r,e){if(r===ye)throw new Error("invert: expected non-zero number");if(e<=Q)throw new Error("invert: expected modulus > 1, got "+e);let t=Pe(r,e),n=e,s=ye,o=Q;for(;t!==ye;){let c=n/t,a=n-t*c,l=s-o*c;n=t,t=a,s=o,o=l}if(n!==Q)throw new Error("invert: does not exist");return Pe(s,e)}function ac(r,e){if(e<=Q)throw new Error("invertCt: expected prime modulus > 1, got "+e);let t=Pe(r,e);if(t===ye)throw new Error("invertCt: expected non-zero number");let n=ic(t,e-kt,e);if(Pe(t*n,e)!==Q)throw new Error("invertCt: does not exist");return n}function Di(r,e,t){let n=r;if(!n.eql(n.sqr(e),t))throw new Error("Cannot find square root")}function vi(r,e){if((r&Q)===ye)throw new Error(e+": expected odd modulus, got "+r)}function cc(r,e){let t=r,n=(t.ORDER+Q)/Ai,s=t.pow(e,n);return Di(t,s,e),s}function rd(r,e){let t=r,n=(t.ORDER-nc)/sc,s=t.mul(e,kt),o=t.pow(s,n),i=t.mul(e,o),c=t.mul(t.mul(i,kt),o),a=t.mul(i,t.sub(c,t.ONE));return Di(t,a,e),a}function nd(r){let e=Qs(r),t=lc(r),n=t(e,e.neg(e.ONE)),s=t(e,n),o=t(e,e.neg(n)),i=(r+Zu)/oc;return((c,a)=>{let l=c,u=l.pow(a,i),d=l.mul(u,n),p=l.mul(u,s),f=l.mul(u,o),m=l.eql(l.sqr(d),a),h=l.eql(l.sqr(p),a);u=l.cmov(u,d,m),d=l.cmov(f,p,h);let g=l.eql(l.sqr(d),a),w=l.cmov(u,d,g);return Di(l,w,a),w})}function lc(r){if(r<rc)throw new Error("sqrt is not defined for small field");vi(r,"tonelliShanks");let e=r-Q,t=0;for(;e%kt===ye;)e/=kt,t++;let n=kt,s=Qs(r);for(;ec(s,n)===1;)if(n++>1e3)throw new Error("Cannot find square root: probably non-prime P");if(t===1)return cc;let o=s.pow(n,e),i=(e+Q)/kt;return function(a,l){let u=a;if(u.is0(l))return l;if(ec(u,l)!==1)throw new Error("Cannot find square root");let d=t,p=u.mul(u.ONE,o),f=u.pow(l,e),m=u.pow(l,i);for(;!u.eql(f,u.ONE);){if(u.is0(f))throw new Error("Cannot find square root: probably non-prime P");let h=1,g=u.sqr(f);for(;!u.eql(g,u.ONE);)if(h++,g=u.sqr(g),h===d)throw new Error("Cannot find square root");let w=Q<<BigInt(d-h-1),b=u.pow(p,w);d=h,p=u.sqr(b),f=u.mul(f,p),m=u.mul(m,b)}return m}}function sd(r){return vi(r,"Fp.sqrt"),r%Ai===rc?cc:r%sc===nc?rd:r%oc===qu?nd(r):lc(r)}var od=["create","isValid","is0","neg","inv","sqrt","sqr","eql","add","sub","mul","pow","div","addN","subN","mulN","sqrN"];function Br(r){if(Pt(r,"field"),typeof r.ORDER!="bigint")throw new TypeError('param "ORDER" is invalid: expected bigint, got '+typeof r.ORDER);Qt(r.BYTES,"BYTES"),Qt(r.BITS,"BITS");for(let e of od)Me(r[e],"field."+e);if(r.BYTES<1||r.BITS<1)throw new Error("invalid field: expected BYTES/BITS > 0");if(r.ORDER<=Q)throw new Error("invalid field: expected ORDER > 1, got "+r.ORDER);return r}function Pi(r,e,t=!1){Br(r),Bn(e,"nums"),Ve(t,"passZero");let n=r,s=new Array(e.length).fill(t?n.ZERO:void 0),o=e.reduce((c,a,l)=>n.is0(a)?c:(s[l]=c,n.mul(c,a)),n.ONE),i=n.inv(o);return e.reduceRight((c,a,l)=>n.is0(a)?c:(s[l]=n.mul(c,s[l]),n.mul(c,a)),i),s}function ec(r,e){Br(r);let t=r;vi(t.ORDER,"FpLegendre");let n=(t.ORDER-Q)/kt,s=t.pow(e,n),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 id(r,e){if(e!==void 0&&_i(e),r<=ye)throw new Error("invalid n length: expected positive n, got "+r);if(e!==void 0&&e<1)throw new Error("invalid n length: expected positive bit length, got "+e);let t=Mr(r);if(e!==void 0&&e<t)throw new Error(`invalid n length: expected nBitLength (${e}) >= bitLen(n) (${t})`);let n=e!==void 0?e:t,s=Math.ceil(n/8);return{nBitLength:n,nByteLength:s}}var tc=new WeakMap,zs=class{ORDER;BITS;BYTES;isLE;ZERO=ye;ONE=Q;_lengths;_mod;constructor(e,t={}){if(e<=Q)throw new Error("invalid field: expected ORDER > 1, got "+e);let n;this.isLE=!1,t!=null&&typeof t=="object"&&(typeof t.BITS=="number"&&(n=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}=id(e,n);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&Q)===Q}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 ic(e,t,this.ORDER)}div(e,t){return Pe(e*qa(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 qa(e,this.ORDER)}sqrt(e){let t=tc.get(this);return t||tc.set(this,t=sd(this.ORDER)),t(this,e)}toBytes(e){return this.isLE?Ti(e,this.BYTES):Hn(e,this.BYTES)}fromBytes(e,t=!1){fe(e);let{_lengths:n,BYTES:s,isLE:o,ORDER:i,_mod:c}=this;if(n){if(e.length<1||!n.includes(e.length)||e.length>s)throw new Error("Field.fromBytes: expected "+n+" 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?Xs(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 Pi(this,e,!0)}cmov(e,t,n){return Ve(n,"condition"),n?t:e}};function Qs(r,e={}){return Object.freeze(zs.prototype),new zs(r,e)}function uc(r){if(typeof r!="bigint")throw new Error("field order must be bigint");if(r<=Q)throw new Error("field order must be greater than 1");let e=Mr(r-Q);return Math.ceil(e/8)}function Zs(r){let e=uc(r);return e+Math.ceil(e/2)}function Ci(r,e,t=!1){fe(r);let n=r.length,s=uc(e),o=Math.max(Zs(e),16);if(n<o||n>1024)throw new Error("expected "+o+"-1024 bytes of input, got "+n);let i=t?Xs(r):Je(r),c=Pe(i,e-Q)+Q;return t?Ti(c,s):Hn(c,s)}var Oi=BigInt(0),Kn=BigInt(1),ad=BigInt(4),ki=16,dc=128,cd=5,pc=2**31;function Fr(r){let e=r;if(typeof e!="function")throw new TypeError('"Point" expected constructor, got type='+typeof r);Me(e.fromAffine,"Point.fromAffine"),Me(e.fromBytes,"Point.fromBytes"),Me(e.fromHex,"Point.fromHex"),Pt(e.BASE,"Point.BASE"),Pt(e.ZERO,"Point.ZERO"),Br(e.Fp),Br(e.Fn)}function mc(r,e){Fr(r),hc(e,r);let t=Pi(r.Fp,e.map(n=>n.Z));return e.map((n,s)=>r.fromAffine(n.toAffine(t[s])))}function ld(r,e,t=1){if(!Number.isSafeInteger(r)||r<t||r>e)throw new Error("invalid window size, expected ["+t+".."+e+"], got W="+r)}function ud(r,e){let t=r*(4*e+128);if(t>pc)throw new Error("invalid window size: table would need ~"+Math.ceil(t/2**20)+" MiB, max "+pc/2**20+" MiB")}function Ni(r,e){if(r!==void 0){Me(r,"randomBytes");try{let t=r(e);if(!Ur(t)||t.length!==e)return}catch{return}return r}}function hc(r,e){Bn(r,"points"),r.forEach((t,n)=>{if(!(t instanceof e))throw new Error("invalid point at index "+n)})}function dd(r,e,t){if(!Array.isArray(r))throw new Error("array of scalars expected");r.forEach((n,s)=>{if(!(t===void 0?e.isValid(n):Ct(n)&&n<t))throw new Error("invalid scalar at index "+s)})}var gc=new WeakMap;function Li(r){return gc.get(r)||1}function pd(r,e){let t=r.double(),n=[r];for(let s=1;s<e;s++)n.push(n[s-1].add(t));return n}function fd(r,e){let t=2**e,n=t/2,s=BigInt(t-1),o=[];for(;r>Oi;){let i=0;r&Kn&&(i=Number(r&s),i>=n&&(i-=t),r-=BigInt(i)),o.push(i),r>>=Kn}return o}function md(r,e,t){let n=2**e,s=n/2,o=BigInt(n-1),i=BigInt(e),c=[];for(let a=0;a<t;a++){let l=Number(r&o);r>>=i,l>s&&(l-=n,r+=Kn),c.push(l)}if(r!==Oi)throw new Error("invalid wnaf");return c}function hd(r,e,t){let n=0;for(let o of t)n=Math.max(n,o.length);let s=r;for(let o=n-1;o>=0;o--){o!==n-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 qs=class{Point;BASE;ZERO;randomBytes;wnafPrecomputes=new WeakMap;baseCanBeBlinded;bits;constructor(e,t){Fr(e),this.randomBytes=Ni(t,ki),this.Point=e,this.BASE=e.BASE,this.ZERO=e.ZERO,this.bits=e.Fn.BITS}buildWnafTable(e,t,n){let s=Math.ceil(n/t)+1,o=2**(t-1),i=[],c=e;for(let a=0;a<s;a++){let l=c;for(let u=0;u<o;u++)i.push(l),l=l.add(c);c=i[i.length-1].double()}return{W:t,bits:n,windows:s,comp:i}}wnafCachedCT(e,t){let{W:n,windows:s,comp:o}=e,i=2**(n-1),c=md(t,n,s),a=this.ZERO,l=this.BASE;for(let u=0;u<s;u++){let d=c[u],p=u*i,f=Math.abs(d)-1,m=o[p];for(let g=1;g<i;g++)m=g===f?o[p+g]:m;let h=m.negate();d===0?l=l.add(o[p]):a=a.add(d<0?h:m)}return{p:a,f:l}}getWnafPrecomputes(e,t,n,s){let o=this.wnafPrecomputes.get(t),i=o?.find(c=>c.W===e&&c.bits===n);return i||(i=this.buildWnafTable(t,e,n),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),!Ri(t,Kn,this.Point.Fn.ORDER))throw new Error("invalid scalar")}runCT(e,t,n,s){let o=Li(e);return o===1?this.fixedWindowCT(e,t,n):this.wnafCachedCT(this.getWnafPrecomputes(o,e,n,s),t)}mulCT(e,t,n){return this.validateMulInput(e,t),this.runCT(e,t,this.bits,n)}mulCTBlinded(e,t,n){if(this.validateMulInput(e,t),this.randomBytes===void 0)throw new Error("randomBytes is required for scalar blinding");let s=this.Point.Fn.BITS+dc,o=this.randomBytes(ki);if(!Ur(o)||o.length!==ki)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,n)}fixedWindowCT(e,t,n){let s=cd,o=1<<s,i=$n(s),c=new Array(o);c[0]=this.ZERO;for(let u=1;u<o;u++)c[u]=c[u-1].add(e);let a=Math.ceil(n/s),l=this.ZERO;for(let u=a-1;u>=0;u--){if(u!==a-1)for(let f=0;f<s;f++)l=l.double();let d=Number(t>>BigInt(u*s)&i),p=c[0];for(let f=1;f<o;f++)p=f===d?c[f]:p;l=l.add(p)}return{p:l,f:l}}shouldBlind(e,t){return this.randomBytes===void 0?!1:t===Kn?!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,n,s){return this.shouldBlind(e,n)?this.mulCTBlinded(e,t,s):this.mulCT(e,t,s)}mulUnsafe(e,t,n){if(this.assertPoint(e),!Ct(t))throw new Error("invalid scalar");let s=Li(e);if(s===1||t>=this.Point.Fn.ORDER)return eo(this.Point,[e],[t],!0);let o=this.getWnafPrecomputes(s,e,this.bits,n);return this.wnafCachedCT(o,t).p}setWindowSize(e,t){this.assertPoint(e),ld(t,this.bits);let n=Math.ceil((this.bits+dc)/t)+1;ud(n*2**(t-1),this.Point.Fp.BYTES),gc.set(e,t),this.wnafPrecomputes.delete(e)}hasWindowSize(e){return Li(e)!==1}};function eo(r,e,t,n=!1){if(Fr(r),hc(e,r),Ve(n,"allowOversized"),dd(t,r.Fn,n?r.Fn.ORDER**ad:void 0),e.length!==t.length)throw new Error("arrays of points and scalars must have equal length");let s=e.map(i=>pd(i,4)),o=t.map(i=>fd(i,4));return hd(r.ZERO,s,o)}function fc(r,e,t){if(e){if(e.ORDER!==r)throw new Error("Field.ORDER must match order: Fp == p, Fn == n");return Br(e),e}else return Qs(r,{isLE:t})}function yc(r,e,t={},n){if(r!=="weierstrass"&&r!=="edwards")throw new Error('expected curve type "weierstrass" or "edwards"');if(n===void 0&&(n=r==="edwards"),!e||typeof e!="object")throw new Error(`expected valid ${r} CURVE object`);nt(t);for(let a of["p","n","h"]){let l=e[a];if(!(Ct(l)&&l!==Oi))throw new Error(`CURVE.${a} must be positive bigint`)}let s=fc(e.p,t.Fp,n),o=fc(e.n,t.Fn,n),c=["Gx","Gy","a",r==="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 wc(r,e){return function(n){let s=r(n);return{secretKey:s,publicKey:e(s)}}}var to=class{oHash;iHash;blockLen;outputLen;canXOF=!1;finished=!1;destroyed=!1;constructor(e,t){if(Or(e),Y(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 n=this.blockLen,s=new Uint8Array(n);s.set(t.length>n?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),vt(s)}update(e){return dt(this),this.iHash.update(e),this}digestInto(e){dt(this),Nr(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:n,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=n._cloneInto(e.iHash),e}clone(){return this._cloneInto()}destroy(){this.destroyed=!0,this.oHash.destroy(),this.iHash.destroy()}},bc=(()=>{let r=((e,t,n)=>new to(e,t).update(n).digest());return r.create=(e,t)=>new to(e,t),r})();var gd=BigInt(0),Ii=class extends Error{constructor(e=""){super(e)}},pt={Err:Ii,_tlv:{encode:(r,e)=>{let{Err:t}=pt;if(Qt(r,"tag"),r<0||r>255)throw new t("tlv.encode: wrong tag");if(Xa(e,"data"),e.length&1)throw new t("tlv.encode: unpadded data");let n=e.length/2,s=Fn(n);if(s.length/2&128)throw new t("tlv.encode: long form length too big");let o=n>127?Fn(s.length/2|128):"";return Fn(r)+o+s+e},decode(r,e){let{Err:t}=pt;e=fe(e,void 0,"DER data");let n=0;if(r<0||r>255)throw new t("tlv.decode: wrong tag");if(e.length<2||e[n++]!==r)throw new t("tlv.decode: wrong tlv");let s=e[n++],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(n,n+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 u of l)i=i<<8|u;if(n+=a,i<128)throw new t("tlv.decode(long): not minimal encoding")}let c=e.subarray(n,n+i);if(c.length!==i)throw new t("tlv.decode: wrong value length");return{v:c,l:e.subarray(n+i)}}},_int:{encode(r){let{Err:e}=pt;if(Ys(r),r<gd)throw new e("integer: negative integers are not allowed");let t=Fn(r);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(r){let{Err:e}=pt;if(r.length<1)throw new e("invalid signature integer: empty");if(r[0]&128)throw new e("invalid signature integer: negative");if(r.length>1&&r[0]===0&&!(r[1]&128))throw new e("invalid signature integer: unnecessary leading zero");return Je(r)}},toSig(r,e){let{Err:t,_int:n,_tlv:s}=pt;if(e!==void 0&&(Qt(e,"maxScalarBytes"),e<1))throw new t("invalid signature: maxScalarBytes must be positive");let o=fe(r,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:u,l:d}=s.decode(2,l);if(d.length)throw new t("invalid signature: left bytes after parsing");if(e!==void 0&&(a.length>e||u.length>e))throw new t("invalid signature: integer too large");return{r:n.decode(a),s:n.decode(u)}},hexFromSig(r){let{_tlv:e,_int:t}=pt;nt(r,{r:"bigint",s:"bigint"},{},"sig");let n=e.encode(2,t.encode(r.r)),s=e.encode(2,t.encode(r.s)),o=n+s;return e.encode(48,o)}},ro=(Object.freeze(pt._tlv),Object.freeze(pt._int),Object.freeze(pt));var Ec=(r,e)=>(r+(r>=0?e:-e)/_c)/e;function yd(r,e,t){xi("scalar",r,ft,t);let[[n,s],[o,i]]=e,c=Ec(i*r,t),a=Ec(-s*r,t),l=r-c*n-a*o,u=-c*s-a*i,d=l<ft,p=u<ft;d&&(l=-l),p&&(u=-u);let f=$n(Math.ceil(Mr(t)/2))+Zt;if(l<ft||l>=f||u<ft||u>=f)throw new Error("splitScalar (endomorphism): failed for k");return{k1neg:d,k1:l,k2neg:p,k2:u}}function Bi(r){if(!["compact","recovered","der"].includes(r))throw new Error('Signature format must be "compact", "recovered", or "der"');return r}function Ui(r,e){nt(r);let t={};for(let n of Object.keys(e))t[n]=r[n]===void 0?e[n]:r[n];return Ve(t.lowS,"lowS"),Ve(t.prehash,"prehash"),t.format!==void 0&&Bi(t.format),t}var ft=BigInt(0),Zt=BigInt(1),_c=BigInt(2),Mi=BigInt(3),wd=BigInt(4);function Sc(r,e={}){let t=yc("weierstrass",r,e),n=t.Fp,s=t.Fn,o=t.CURVE,{h:i,n:c}=o;nt(e,{},{allowInfinityPoint:"boolean",clearCofactor:"function",isTorsionFree:"function",fromBytes:"function",toBytes:"function",endo:"object",randomBytes:"function"});let{endo:a,allowInfinityPoint:l,clearCofactor:u,isTorsionFree:d,fromBytes:p,toBytes:f}=e,m=e.randomBytes===void 0?Gs:e.randomBytes;if(a&&(!n.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(L=>[...L])}:void 0,g=Rc(n,s);function w(){if(!n.isOdd)throw new Error("compression is not supported: Field does not have .isOdd()")}function b(L,T,A){if(T.is0()){if(!l)throw new Error("bad point: ZERO");return Uint8Array.of(0)}let{x:C,y:I}=T.toAffine(),M=n.toBytes(C);if(Ve(A,"isCompressed"),A){w();let B=!n.isOdd(I);return je(Tc(B),M)}else return je(Uint8Array.of(4),M,n.toBytes(I))}function y(L){fe(L,void 0,"Point");let{publicKey:T,publicKeyUncompressed:A}=g,C=L.length,I=L[0],M=L.subarray(1);if(l&&C===1&&I===0)return{x:n.ZERO,y:n.ZERO};if(C===T&&(I===2||I===3)){let B=n.fromBytes(M);if(!n.isValid(B))throw new Error("bad point: is not on curve, wrong x");let $=R(B),F;try{F=n.sqrt($)}catch(W){let J=W instanceof Error?": "+W.message:"";throw new Error("bad point: is not on curve, sqrt error"+J)}w();let H=n.isOdd(F);return(I&1)===1!==H&&(F=n.neg(F)),{x:B,y:F}}else if(C===A&&I===4){let B=n.BYTES,$=n.fromBytes(M.subarray(0,B)),F=n.fromBytes(M.subarray(B,B*2));if(!D($,F))throw new Error("bad point: is not on curve");return{x:$,y:F}}else throw new Error(`bad point: got length ${C}, expected compressed=${T} or uncompressed=${A}`)}let E=f===void 0?b:f,_=p===void 0?y:p,S=n.mul(o.b,Mi),x=n.is0(o.a)?L=>n.ZERO:L=>n.mul(o.a,L);function R(L){let T=n.sqr(L),A=n.mul(T,L);return n.add(n.add(A,n.mul(L,o.a)),o.b)}function D(L,T){let A=n.sqr(T),C=R(L);return n.eql(A,C)}if(!D(o.Gx,o.Gy))throw new Error("bad curve params: generator point");let P=n.mul(n.pow(o.a,Mi),wd),k=n.mul(n.sqr(o.b),BigInt(27));if(n.is0(n.add(P,k)))throw new Error("bad curve params: a or b");function N(L,T,A=!1){if(!n.isValid(T)||A&&n.is0(T))throw new Error(`bad point coordinate ${L}`);return typeof T=="object"&&T!==null?n.create(T):T}function V(L){if(!(L instanceof K))throw new Error("Weierstrass Point expected")}function z(L){if(!h||!h.basises)throw new Error("no endo");return yd(L,h.basises,s.ORDER)}function ue(L,T,A,C){if(!s.isValid(C))throw new RangeError("invalid scalar: out of range");if(h){let{k1neg:I,k1:M,k2neg:B,k2:$}=z(C),F=new K(n.mul(A.X,h.beta),A.Y,A.Z);L.push(I?A.negate():A,B?F.negate():F),T.push(M,$)}else L.push(A),T.push(C)}let Ae=new WeakSet;class K{static BASE=new K(o.Gx,o.Gy,n.ONE);static ZERO=new K(n.ZERO,n.ONE,n.ZERO);static Fp=n;static Fn=s;X;Y;Z;constructor(T,A,C){this.X=N("x",T),this.Y=N("y",A,!0),this.Z=N("z",C),Object.freeze(this)}static CURVE(){return o}static fromAffine(T){let{x:A,y:C}=T||{};if(!T||!n.isValid(A)||!n.isValid(C))throw new Error("invalid affine point");if(T instanceof K)throw new Error("projective point not allowed");return n.is0(A)&&n.is0(C)?K.ZERO:new K(A,C,n.ONE)}static fromBytes(T){let A=K.fromAffine(_(fe(T,void 0,"point")));return A.assertValidity(),A}static fromHex(T){return K.fromBytes(Js(T))}get x(){return this.toAffine().x}get y(){return this.toAffine().y}precompute(T=6,A=!0){return we.setWindowSize(this,T),A||this.multiply(Mi),this}assertValidity(){let T=this;if(T.is0()){if(l&&n.is0(T.X)&&n.eql(T.Y,n.ONE)&&n.is0(T.Z))return;throw new Error("bad point: ZERO")}if(Ae.has(T))return;let{x:A,y:C}=T.toAffine();if(!n.isValid(A)||!n.isValid(C))throw new Error("bad point: x or y not field elements");if(!D(A,C))throw new Error("bad point: equation left != right");if(!T.isTorsionFree())throw new Error("bad point: not in prime-order subgroup");Ae.add(T)}hasEvenY(){let{y:T}=this.toAffine();if(!n.isOdd)throw new Error("Field doesn't support isOdd");return!n.isOdd(T)}equals(T){V(T);let{X:A,Y:C,Z:I}=this,{X:M,Y:B,Z:$}=T,F=n.eql(n.mul(A,$),n.mul(M,I)),H=n.eql(n.mul(C,$),n.mul(B,I));return F&&H}negate(){return new K(this.X,n.neg(this.Y),this.Z)}double(){let{X:T,Y:A,Z:C}=this,I=n.ZERO,M=n.ZERO,B=n.ZERO,$=n.mul(T,T),F=n.mul(A,A),H=n.mul(C,C),U=n.mul(T,A);return U=n.add(U,U),B=n.mul(T,C),B=n.add(B,B),I=x(B),M=n.mul(S,H),M=n.add(I,M),I=n.sub(F,M),M=n.add(F,M),M=n.mul(I,M),I=n.mul(U,I),B=n.mul(S,B),H=x(H),U=n.sub($,H),U=x(U),U=n.add(U,B),B=n.add($,$),$=n.add(B,$),$=n.add($,H),$=n.mul($,U),M=n.add(M,$),H=n.mul(A,C),H=n.add(H,H),$=n.mul(H,U),I=n.sub(I,$),B=n.mul(H,F),B=n.add(B,B),B=n.add(B,B),new K(I,M,B)}add(T){V(T);let{X:A,Y:C,Z:I}=this,{X:M,Y:B,Z:$}=T,F=n.ZERO,H=n.ZERO,U=n.ZERO,W=n.mul(A,M),J=n.mul(C,B),Z=n.mul(I,$),ke=n.add(A,C),te=n.add(M,B);ke=n.mul(ke,te),te=n.add(W,J),ke=n.sub(ke,te),te=n.add(A,I);let ie=n.add(M,$);return te=n.mul(te,ie),ie=n.add(W,Z),te=n.sub(te,ie),ie=n.add(C,I),F=n.add(B,$),ie=n.mul(ie,F),F=n.add(J,Z),ie=n.sub(ie,F),U=x(te),F=n.mul(S,Z),U=n.add(F,U),F=n.sub(J,U),U=n.add(J,U),H=n.mul(F,U),J=n.add(W,W),J=n.add(J,W),Z=x(Z),te=n.mul(S,te),J=n.add(J,Z),Z=n.sub(W,Z),Z=x(Z),te=n.add(te,Z),W=n.mul(J,te),H=n.add(H,W),W=n.mul(ie,te),F=n.mul(ke,F),F=n.sub(F,W),W=n.mul(ke,J),U=n.mul(ie,U),U=n.add(U,W),new K(F,H,U)}subtract(T){return V(T),this.add(T.negate())}is0(){return this.equals(K.ZERO)}multiply(T){if(!s.isValidNot0(T))throw new RangeError("invalid scalar: out of range");let{p:A,f:C}=we.mulSecret(this,T,i,se);return se([A,C])[0]}multiplyUnsafe(T){let A=this,C=T;if(!s.isValid(C))throw new RangeError("invalid scalar: out of range");if(C===ft||A.is0())return K.ZERO;if(C===Zt)return A;if(we.hasWindowSize(this))return we.mulUnsafe(A,C,se);let I=[],M=[];return ue(I,M,A,C),eo(K,I,M)}mulAddUnsafe(T,A,C){V(A);let I=[],M=[];return ue(I,M,this,T),ue(I,M,A,C),eo(K,I,M)}toAffine(T){let A=this,C=T;if(C!=null&&!n.isValid(C))throw new RangeError('"invertedZ" expected valid field element');let{X:I,Y:M,Z:B}=A;if(n.eql(B,n.ONE))return{x:I,y:M};let $=A.is0();C==null&&(C=$?n.ONE:n.inv(B));let F=n.mul(I,C),H=n.mul(M,C),U=n.mul(B,C);if($)return{x:n.ZERO,y:n.ZERO};if(!n.eql(U,n.ONE))throw new Error("invZ was invalid");return{x:F,y:H}}isTorsionFree(){return i===Zt?!0:d?d(K,this):we.mulUnsafe(this,c).is0()}clearCofactor(){return i===Zt?this:u?u(K,this):this.multiplyUnsafe(i)}isSmallOrder(){return i===Zt?this.is0():this.clearCofactor().is0()}toBytes(T=!0){return Ve(T,"isCompressed"),this.assertValidity(),E(K,this,T)}toHex(T=!0){return Si(this.toBytes(T))}toString(){return`<Point ${this.is0()?"ZERO":this.toHex()}>`}}let se=L=>mc(K,L),we=new qs(K,m);return we.bits>=6&&K.BASE.precompute(6),Object.freeze(K.prototype),Object.freeze(K),K}function Tc(r){return Uint8Array.of(r?2:3)}function Rc(r,e){return{secretKey:e.BYTES,publicKey:1+r.BYTES,publicKeyUncompressed:1+2*r.BYTES,publicKeyHasPrefix:!0,signature:2*e.BYTES}}function bd(r,e={}){Fr(r);let{Fn:t}=r,n=e.randomBytes===void 0?Gs:e.randomBytes,s=Object.assign(Rc(r.Fp,t),{seed:Math.max(Zs(t.ORDER),16)});function o(f){try{let m=t.fromBytes(f);return t.isValidNot0(m)}catch{return!1}}function i(f,m){let{publicKey:h,publicKeyUncompressed:g}=s;try{let w=f.length;return m===!0&&w!==h||m===!1&&w!==g?!1:!r.fromBytes(f).is0()}catch{return!1}}function c(f){return f=f===void 0?n(s.seed):f,Ci(fe(f,s.seed,"seed"),t.ORDER)}function a(f,m=!0){return r.BASE.multiply(t.fromBytes(f)).toBytes(m)}function l(f){let{secretKey:m,publicKey:h,publicKeyUncompressed:g}=s,w=t._lengths;if(!Ur(f))return;let b=fe(f,void 0,"key").length,y=b===h||b===g,E=b===m||!!w?.includes(b);if(!(y&&E))return y}function u(f,m,h=!0){if(l(f)===!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(f),w=r.fromBytes(m);if(w.is0())throw new Error("invalid public key: point at infinity");return w.multiply(g).toBytes(h)}let d={isValidSecretKey:o,isValidPublicKey:i,randomSecretKey:c},p=wc(c,a);return Object.freeze(d),Object.freeze(s),Object.freeze({getPublicKey:a,getSharedSecret:u,keygen:p,Point:r,utils:d,lengths:s})}function xc(r,e,t={}){Fr(r);let n=e;Or(n),nt(t,{},{hmac:"function",lowS:"boolean",randomBytes:"function",bits2int:"function",bits2int_modN:"function"});let s=Object.assign({},t),o=s.randomBytes===void 0?Gs:s.randomBytes,i=s.hmac===void 0?(L,T)=>bc(n,L,T):s.hmac,{Fp:c,Fn:a}=r,{ORDER:l,BITS:u}=a,d=Zs(l),p=Ni(o,d),{keygen:f,getPublicKey:m,getSharedSecret:h,utils:g,lengths:w}=bd(r,s),b={prehash:!0,lowS:typeof s.lowS=="boolean"?s.lowS:!0,format:"compact",extraEntropy:!1},y=l*_c+Zt<c.ORDER;function E(L){let T=l>>Zt;return L>T}function _(L,T){if(!a.isValidNot0(T))throw new Error(`invalid signature ${L}: out of range 1..Point.Fn.ORDER`);return T}function S(){if(!c.isOdd)throw new Error("Field doesn't support isOdd")}function x(L,T,A){return S(),(L===A?0:2)|Number(c.isOdd(T))}function R(){if(y)throw new Error('"recovered" sig type is not supported for cofactor >2 curves')}function D(L,T){Bi(T);let A=w.signature,C=T==="compact"?A:T==="recovered"?A+1:void 0;return fe(L,C)}class P{r;s;recovery;constructor(T,A,C){if(this.r=_("r",T),this.s=_("s",A),C!=null){if(R(),![0,1,2,3].includes(C))throw new Error("invalid recovery id");this.recovery=C}Object.freeze(this)}static fromBytes(T,A=b.format){D(T,A);let C;if(A==="der"){if(T.length>2*a.BYTES+16)throw new ro.Err("invalid signature: DER signature too long");let{r:$,s:F}=ro.toSig(fe(T),a.BYTES+1);return new P($,F)}A==="recovered"&&(C=T[0],A="compact",T=T.subarray(1));let I=w.signature/2,M=T.subarray(0,I),B=T.subarray(I,I*2);return new P(a.fromBytes(M),a.fromBytes(B),C)}static fromHex(T,A){return this.fromBytes(Js(T),A)}assertRecovery(){let{recovery:T}=this;if(T==null)throw new Error("invalid recovery id: must be present");return T}addRecoveryBit(T){return new P(this.r,this.s,T)}recoverPublicKey(T){let{r:A,s:C}=this,I=this.assertRecovery(),M=I===2||I===3?A+l:A;if(!c.isValid(M))throw new Error("invalid recovery id: sig.r+curve.n != R.x");let B=c.toBytes(M),$=r.fromBytes(je(Tc((I&1)===0),B)),F=a.inv(M),H=N(fe(T,void 0,"msgHash")),U=a.create(-H*F),W=a.create(C*F),J=r.BASE.mulAddUnsafe(U,$,W);if(J.is0())throw new Error("invalid recovery: point at infinify");return J.assertValidity(),J}hasHighS(){return E(this.s)}toBytes(T=b.format){if(Bi(T),T==="der")return Js(ro.hexFromSig(this));let{r:A,s:C}=this,I=a.toBytes(A),M=a.toBytes(C);return T==="recovered"?(R(),je(Uint8Array.of(this.assertRecovery()),I,M)):je(I,M)}toHex(T){return Si(this.toBytes(T))}}Object.freeze(P.prototype),Object.freeze(P);let k=s.bits2int===void 0?function(T){if(T.length>8192)throw new Error("input is too large");let A=Je(T),C=T.length*8-u;return C>0?A>>BigInt(C):A}:s.bits2int,N=s.bits2int_modN===void 0?function(T){return a.create(k(T))}:s.bits2int_modN,V=$n(u);function z(L){return xi("num < 2^"+u,L,ft,V),a.toBytes(L)}function ue(L,T){return fe(L,void 0,"message"),T?fe(n(L),void 0,"prehashed message"):L}function Ae(L,T,A){let{lowS:C,prehash:I,extraEntropy:M}=Ui(A,b);L=ue(L,I);let B=N(L),$=a.fromBytes(T);if(!a.isValidNot0($))throw new Error("invalid private key");let F=[z($),z(B)];if(M!=null&&M!==!1){let J=M===!0?o(w.secretKey):M;F.push(fe(J,void 0,"extraEntropy"))}let H=je(...F),U=B;function W(J){let Z=k(J);if(!a.isValidNot0(Z))return;let ke=r.BASE.multiply(Z).toAffine(),te=a.create(ke.x);if(te===ft)return;let ie;if(p!==void 0){let sn=Je(Ci(p(d),l)),yu=a.inv(a.mul(sn,Z)),wu=a.mul(sn,U),bu=a.mul(sn,$);ie=a.create(yu*a.create(wu+bu*te))}else{let sn=ac(Z,l);ie=a.create(sn*a.create(U+te*$))}if(ie===ft)return;let Bo=x(ke.x,ke.y,te),ua=ie;return C&&E(ie)&&(ua=a.neg(ie),Bo^=1),new P(te,ua,y?void 0:Bo)}return{seed:H,k2sig:W}}function K(L,T,A={}){let{seed:C,k2sig:I}=Ae(L,T,A);return Za(n.outputLen,a.BYTES,i)(C,I).toBytes(A.format)}function se(L,T,A,C={}){let{lowS:I,prehash:M,format:B}=Ui(C,b);if(A=fe(A,void 0,"publicKey"),T=ue(T,M),!Ur(L)){let $=L instanceof P?", use sig.toBytes()":"";throw new Error("verify expects Uint8Array signature"+$)}D(L,B);try{let $=P.fromBytes(L,B),F=r.fromBytes(A);if(F.is0()||I&&$.hasHighS())return!1;let{r:H,s:U}=$,W=N(T),J=a.inv(U),Z=a.create(W*J),ke=a.create(H*J),te=r.BASE.mulAddUnsafe(Z,F,ke);if(te.is0())return!1;let ie=te.toAffine();return!(a.create(ie.x)!==H||B==="recovered"&&$.recovery!==x(ie.x,ie.y,H))}catch{return!1}}function we(L,T,A={}){let{prehash:C}=Ui(A,b);return T=ue(T,C),P.fromBytes(L,"recovered").recoverPublicKey(T).toBytes()}return Object.freeze({keygen:f,getPublicKey:m,getSharedSecret:h,utils:g,lengths:w,Point:r,sign:K,verify:se,recoverPublicKey:we,Signature:P,hash:n})}var no=BigInt(4294967295),Ac=BigInt(32);function Ed(r,e=!1){return e?{h:Number(r&no),l:Number(r>>Ac&no)}:{h:Number(r>>Ac&no)|0,l:Number(r&no)|0}}function Dc(r,e=!1){let t=r.length,n=new Uint32Array(t),s=new Uint32Array(t);for(let o=0;o<t;o++){let{h:i,l:c}=Ed(r[o],e);[n[o],s[o]]=[i,c]}return[n,s]}var _d=r=>r/2**32|0,Sd=r=>r>>>0;function vc(r,e,t,n){let s=_d(t),o=Sd(t);r.setUint32(e,n?o:s,n),r.setUint32(e+4,n?s:o,n)}function Pc(r,e,t){return r&e^~r&t}function Cc(r,e,t){return r&e^r&t^e&t}var so=class{blockLen;outputLen;canXOF=!1;padOffset;isLE;buffer;view;finished=!1;length=0;pos=0;destroyed=!1;constructor(e,t,n,s){this.blockLen=e,this.outputLen=t,this.padOffset=n,this.isLE=s,this.buffer=new Uint8Array(e),this.view=Ws(this.buffer)}update(e){dt(this),Y(e);let{view:t,buffer:n,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=Ws(e);for(;s<=o-c;c+=s)this.process(l,c);i=!0;continue}n.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){dt(this),Nr(e,this),this.finished=!0;let{buffer:t,view:n,blockLen:s,isLE:o}=this,{pos:i}=this;t[i++]=128,t.fill(0,i),this.padOffset>s-i&&(this.process(n,0),t.fill(0)),vc(n,s-8,this.length*8,o),this.process(n,0),this.roundClean();let c=e===t?n:Ws(e),a=this.outputLen,l=a/4,u=this.get();if(a%4||l>u.length)throw new Error("invalid outputLen");for(let d=0;d<l;d++)c.setUint32(4*d,u[d],o)}digest(){let{buffer:e,outputLen:t}=this;this.digestInto(e);let n=e.slice(0,t);return this.destroy(),n}_cloneIntoMeta(e){let{buffer:t,length:n,finished:s,destroyed:o,pos:i}=this;return e.destroyed=o,e.finished=s,e.length=n,e.pos=i,i&&e.buffer.set(t),e}clone(){return this._cloneInto()}},kc=Uint32Array.from([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]);var Td=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]),Lt=new Uint32Array(64),Fi=class extends so{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:n,D:s,E:o,F:i,G:c,H:a}=this;return[e,t,n,s,o,i,c,a]}set(e,t,n,s,o,i,c,a){this.A=e|0,this.B=t|0,this.C=n|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 d=0;d<16;d++,t+=4)Lt[d]=e.getUint32(t,!1);for(let d=16;d<64;d++){let p=Lt[d-15],f=Lt[d-2],m=We(p,7)^We(p,18)^p>>>3,h=We(f,17)^We(f,19)^f>>>10;Lt[d]=h+Lt[d-7]+m+Lt[d-16]|0}let{A:n,B:s,C:o,D:i,E:c,F:a,G:l,H:u}=this;for(let d=0;d<64;d++){let p=We(c,6)^We(c,11)^We(c,25),f=u+p+Pc(c,a,l)+Td[d]+Lt[d]|0,h=(We(n,2)^We(n,13)^We(n,22))+Cc(n,s,o)|0;u=l,l=a,a=c,c=i+f|0,i=o,o=s,s=n,n=f+h|0}n=n+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,u=u+this.H|0,this.set(n,s,o,i,c,a,l,u)}roundClean(){vt(Lt)}destroy(){this.destroyed=!0,this.set(0,0,0,0,0,0,0,0),vt(this.buffer)}},Hi=class extends Fi{constructor(){super(32,kc)}};var Lc=Mn(()=>new Hi,zt(1));function Wn(r,e="n"){if(typeof r!="number")throw new TypeError(`wrong u32 integer "${e}": expected number, got type=${typeof r}`);if(!Number.isSafeInteger(r)||r<0||r>4294967295)throw new RangeError(`wrong u32 integer "${e}": expected 0..4294967295, got ${r}`);return r}function Nc(r){return Wn(r,"x"),(r&r-1)===0&&r!==0}function $i(r,e){if(Wn(r),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 n=0;n<e;n++,r>>>=1)t=t<<1|r&1;return t>>>0}function Ic(r){return Wn(r),31-Math.clz32(r)}function Oc(r){if(!r||typeof r!="object"||typeof r.length!="number")throw new TypeError('"values" expected array-like, got type='+typeof r);let e=r.length;if(!Nc(e))throw new Error("expected positive power-of-two length, got "+e);let t=Ic(e);for(let n=0;n<e;n++){let s=$i(n,t);if(n<s){let o=r[n];r[n]=r[s],r[s]=o}}return r}var Ki=(r,e)=>{nt(e,{N:"number",roots:"object",dit:"boolean"},{invertButterflies:"boolean",skipStages:"number",brp:"boolean"},"coreOpts");let{N:t,roots:n,dit:s,invertButterflies:o=!1,skipStages:i=0,brp:c=!0}=e;Wn(t,"coreOpts.N");let a=Ic(t);if(!Nc(t))throw new Error("FFT: Polynomial size should be power of two");Wn(i,"coreOpts.skipStages");let l=a===0?0:a-1;if(i>l)throw new Error(`FFT: wrong skipStages: expected 0 <= skipStages <= ${l}`);if(n.length!==t)throw new Error(`FFT: wrong roots length: expected ${t}, got ${n.length}`);let u=s!==o;return d=>{if(d.length!==t)throw new Error("FFT: wrong Polynomial length");s&&c&&Oc(d);for(let p=0,f=1;p<a-i;p++){let m=s?p+1+i:a-p,h=1<<m,g=h>>1,w=t>>m;for(let b=0;b<t;b+=h)for(let y=0,E=f++;y<g;y++){let _=o?s?t-E:E:y*w,S=b+y,x=b+y+g,R=n[_],D=d[x],P=d[S];if(u){let k=r.mul(D,R);d[S]=r.add(P,k),d[x]=r.sub(P,k)}else o?(d[S]=r.add(D,P),d[x]=r.mul(r.sub(D,P),R)):(d[S]=r.add(P,D),d[x]=r.mul(r.sub(P,D),R))}}return!s&&c&&Oc(d),d}};var Rd={p:BigInt("0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"),n:BigInt("0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"),h:BigInt(1),a:BigInt("0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc"),b:BigInt("0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b"),Gx:BigInt("0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"),Gy:BigInt("0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5")};var xd=Sc(Rd),Uc=xc(xd,Lc);var Ad=BigInt(0),jn=BigInt(1),Dd=BigInt(2),vd=BigInt(7),Pd=BigInt(256),Cd=BigInt(113),Fc=[],Hc=[],$c=[];for(let r=0,e=jn,t=1,n=0;r<24;r++){[t,n]=[n,(2*t+3*n)%5],Fc.push(2*(5*n+t)),Hc.push((r+1)*(r+2)/2%64);let s=Ad;for(let o=0;o<7;o++)e=(e<<jn^(e>>vd)*Cd)%Pd,e&Dd&&(s^=jn<<(jn<<BigInt(o))-jn);$c.push(s)}var Kc=Dc($c,!0),kd=Kc[0],Ld=Kc[1],Od=(r,e,t)=>r<<t|e>>>32-t,Nd=(r,e,t)=>e<<t|r>>>32-t,Id=(r,e,t)=>e<<t-32|r>>>64-t,Ud=(r,e,t)=>r<<t-32|e>>>64-t,Mc=(r,e,t)=>t>32?Id(r,e,t):Od(r,e,t),Bc=(r,e,t)=>t>32?Ud(r,e,t):Nd(r,e,t),Hr=new Uint32Array(10);function Md(r,e=24){if(!(r instanceof Uint32Array))throw new TypeError('"s" expected Uint32Array(50), got type='+typeof r);if(r.length!==50)throw new RangeError('"s" expected Uint32Array(50), got length='+r.length);if(le(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++)Hr[o]=r[o]^r[o+10]^r[o+20]^r[o+30]^r[o+40];for(let o=0;o<10;o+=2){let i=(o+8)%10,c=(o+2)%10,a=Hr[c],l=Hr[c+1],u=Mc(a,l,1)^Hr[i],d=Bc(a,l,1)^Hr[i+1];for(let p=0;p<50;p+=10)r[o+p]^=u,r[o+p+1]^=d}let n=r[2],s=r[3];for(let o=0;o<24;o++){let i=Hc[o],c=Mc(n,s,i),a=Bc(n,s,i),l=Fc[o];n=r[l],s=r[l+1],r[l]=c,r[l+1]=a}for(let o=0;o<50;o+=10){let i=r[o],c=r[o+1],a=r[o+2],l=r[o+3];r[o]^=~r[o+2]&r[o+4],r[o+1]^=~r[o+3]&r[o+5],r[o+2]^=~r[o+4]&r[o+6],r[o+3]^=~r[o+5]&r[o+7],r[o+4]^=~r[o+6]&r[o+8],r[o+5]^=~r[o+7]&r[o+9],r[o+6]^=~r[o+8]&i,r[o+7]^=~r[o+9]&c,r[o+8]^=~i&a,r[o+9]^=~c&l}r[0]^=kd[t],r[1]^=Ld[t]}vt(Hr)}var oo=class r{state;pos=0;posOut=0;finished=!1;state32;destroyed=!1;blockLen;suffix;outputLen;canXOF;enableXOF=!1;rounds;constructor(e,t,n,s=!1,o=24){if(le(e,"blockLen"),le(t,"suffix"),le(o,"rounds"),Va(s,"enableXOF"),this.blockLen=e,this.suffix=t,this.outputLen=n,this.enableXOF=s,this.canXOF=s,this.rounds=o,le(n,"outputLen"),!(0<e&&e<200))throw new Error('"blockLen" must be 1..199');this.state=new Uint8Array(200),this.state32=In(this.state)}clone(){return this._cloneInto()}keccak(){Ir(this.state32),Md(this.state32,this.rounds),Ir(this.state32),this.posOut=0,this.pos=0}update(e){dt(this),Y(e);let{blockLen:t,state:n,state32:s}=this,o=e.length,i=t%4===0&&e.byteOffset%4===0,c=t/4,a=i&&o>=t?In(e):void 0;for(let l=0;l<o;){if(a!==void 0&&this.pos===0&&l%4===0&&o-l>=t){for(let d=0,p=l/4;d<c;d++)s[d]^=a[p+d];l+=t,this.pos=t,this.keccak();continue}let u=Math.min(t-this.pos,o-l);for(let d=0;d<u;d++)n[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:n,blockLen:s}=this;e[n]^=t,(t&128)!==0&&n===s-1&&this.keccak(),e[s-1]^=128,this.keccak()}writeInto(e){dt(this,!1),Y(e),this.finish();let t=this.state,{blockLen:n}=this;for(let s=0,o=e.length;s<o;){this.posOut>=n&&this.keccak();let i=Math.min(n-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 le(e),this.xofInto(new Uint8Array(e))}digestInto(e){if(Nr(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,vt(this.state)}_cloneInto(e){let{blockLen:t,suffix:n,outputLen:s,rounds:o,enableXOF:i}=this;return e||=new r(t,n,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=n,e.outputLen=s,e.enableXOF=i,e.canXOF=this.canXOF,e.destroyed=this.destroyed,e}},Wc=(r,e,t,n={})=>Mn(()=>new oo(e,r,t),n);var io=Wc(6,136,32,zt(8));var jc=Wc(6,72,64,zt(10));var Vc=(r,e,t,n={})=>Mn((s={})=>(s=Ei({},s),new oo(e,r,s.dkLen===void 0?t:s.dkLen,!0)),n),Jc=Vc(31,168,16,zt(11)),$r=Vc(31,136,32,zt(12));var Ge=Y;var mt=js;function Bd(r,e,t=()=>{}){if(!Array.isArray(r))throw new TypeError(`"${e}" expected array, got type=${typeof r}`);for(let n=0;n<r.length;n++)t(r[n],`${e}[${n}]`);return r}function Wi(r,e="object"){if(r===null||typeof r!="object"||Array.isArray(r))throw new TypeError(e==="object"?"expected valid options object":`"${e}" expected object, got type=${typeof r}`);return r}function qt(r,e){if(r=Y(r),e=Y(e),r.length!==e.length)return!1;let t=0;for(let n=0;n<r.length;n++)t|=r[n]^e[n];return t===0}function ht(r){return new Uint8Array(Y(r))}function er(r,...e){let t=s=>typeof s=="number"?s:s.bytesLen,n=e.reduce((s,o)=>s+t(o),0);return{bytesLen:n,encode:s=>{let o=new Uint8Array(n);for(let i=0,c=0;i<e.length;i++){let a=e[i],l=t(a),u=typeof a=="number"?s[i]:a.encode(s[i]);Y(u,l,r),o.set(u,c),typeof a!="number"&&u.fill(0),c+=l}return o},decode:s=>{Y(s,n,r);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 ao(r,e){let t=r,n=e*t.bytesLen;return{bytesLen:n,encode:s=>{let o=Bd(s,"u");if(o.length!==e)throw new RangeError(`vecCoder.encode: wrong length=${o.length}. Expected: ${e}`);let i=new Uint8Array(n);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=>{Y(s,n);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(...r){for(let e of r)if(Array.isArray(e))for(let t of e)t.fill(0);else e.fill(0)}function co(r){if(le(r,"bits"),r>32)throw new RangeError('"bits" expected <= 32, got '+r);return r===32?4294967295:~(-1<<r)>>>0}var Gc=r=>{let{newPoly:e,N:t,Q:n,F:s,ROOT_OF_UNITY:o,brvBits:i,isKyber:c}=r,a=(y,E=n)=>{let _=y%E|0;return(_>=0?_|0:E+_|0)|0},l=(y,E=n)=>{let _=a(y,E)|0;return(_>E>>1?_-E|0:_)|0};function u(){let y=e(t);for(let E=0;E<t;E++){let _=$i(E,i),S=BigInt(o)**BigInt(_)%BigInt(n);y[E]=Number(S)|0}return y}let d=u(),p=y=>{throw new Error("not implemented")},f=c?{add:(y,E)=>{let _=y+E|0;return _>=n?_-n|0:_},sub:(y,E)=>{let _=y-E|0;return _<0?_+n|0:_},mul:(y,E)=>a((y|0)*(E|0))|0,inv:p}:{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:p},m={N:t,roots:d,invertButterflies:!0,skipStages:c?1:0,brp:!1},h=Ki(f,{dit:!1,...m}),g=Ki(f,{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:d,NTT:{encode:y=>w.encode(y),decode:y=>w.decode(y)},bitsCoder:(y,E)=>{for(let x=0,R=0;x<t;x++)R+=y,R>32&&co(R),R%=8;let _=co(y),S=y*(t/8);return{bytesLen:S,encode:x=>{let R=x,D=new Uint8Array(S);for(let P=0,k=0,N=0,V=0;P<R.length;P++)for(k|=(E.encode(R[P])&_)<<N,N+=y;N>=8;N-=8,k>>=8)D[V++]=k&255;return D},decode:x=>{let R=e(t);for(let D=0,P=0,k=0,N=0;D<x.length;D++)for(P|=x[D]<<k,k+=8;k>=y;k-=y,P>>=y)R[N++]=E.decode(P&_);return R}}}}},Fd=r=>(e,t)=>{t||(t=r.blockLen);let n=new Uint8Array(e.length+2);n.set(e);let s=e.length,o=new Uint8Array(t),i=r.create({}),c=0,a=0;return{stats:()=>({calls:c,xofs:a}),get:(l,u)=>(n[s+0]=l,n[s+1]=u,i.destroy(),i=r.create({}).update(n),c++,()=>(a++,i.xofInto(o))),clean:()=>{i.destroy(),X(o,n)}}},Yc=Fd(Jc);var Ee=256,be=3329,Hd=3303,$d=17,Re=Gc({N:Ee,Q:be,F:Hd,ROOT_OF_UNITY:$d,newPoly:r=>new Uint16Array(r),brvBits:7,isKyber:!0}),Kd=Object.freeze({512:Object.freeze({N:Ee,Q:be,K:2,ETA1:3,ETA2:2,du:10,dv:4,RBGstrength:128}),768:Object.freeze({N:Ee,Q:be,K:3,ETA1:2,ETA2:2,du:10,dv:4,RBGstrength:192}),1024:Object.freeze({N:Ee,Q:be,K:4,ETA1:2,ETA2:2,du:11,dv:5,RBGstrength:256})}),Wd=r=>{if(r>=12)return{encode:t=>t,decode:t=>t>=be?t-be:t};let e=2**(r-1);return{encode:t=>((t<<r)+be/2)/be,decode:t=>t*be+e>>>r}},jd=r=>Re.bitsCoder(r,r===12?{encode:e=>e,decode:e=>e>=be?e-be:e}:{encode:e=>e,decode:e=>e}),Vn=r=>r===12?jd(12):Re.bitsCoder(r,Wd(r));function tr(r,e){let t=r,n=e;for(let s=0;s<Ee;s++){let o=t[s]+n[s];t[s]=o>=be?o-be:o}}function Vd(r,e){let t=r,n=e;for(let s=0;s<Ee;s++){let o=t[s]-n[s];t[s]=o<0?o+be:o}}function Jd(r,e,t,n,s){let o=Re.mod(Re.mod(e*n)*s+r*t),i=Re.mod(r*n+e*t);return{c0:o,c1:i}}function lo(r,e){let t=r,n=e;for(let s=0;s<Ee/2;s++){let o=Re.nttZetas[64+(s>>1)];s&1&&(o=-o);let{c0:i,c1:c}=Jd(t[2*s+0],t[2*s+1],n[2*s+0],n[2*s+1],o);t[2*s+0]=i,t[2*s+1]=c}return t}function ji(r){let e=r,t=new Uint16Array(Ee);for(let n=0;n<Ee;){let s=e();if(s.length%3)throw new Error("SampleNTT: unaligned block");for(let o=0;n<Ee&&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<be&&(t[n++]=i),n<Ee&&c<be&&(t[n++]=c)}}return t}var Gd=(r,e)=>{let t=new Uint16Array(Ee),n=In(r);Ir(n);let s=0;for(let o=0,i=0,c=0,a=0;o<n.length;o++){let l=n[o];for(let u=0;u<32;u++)c+=l&1,l>>=1,s+=1,s===e?(a=c,c=0):s===2*e&&(t[i++]=Re.mod(a-c),c=0,s=0)}if(Ir(n),s)throw new Error(`sampleCBD: leftover bits: ${s}`);return t};function Jn(r,e,t,n){return Gd(r(n*Ee/4,e,t),n)}var Yd=r=>{let e=r,{K:t,PRF:n,XOF:s,HASH512:o,ETA1:i,ETA2:c,du:a,dv:l}=e,u=Vn(1),d=Vn(l),p=Vn(a),f=er("publicKey",ao(Vn(12),t),32),m=ao(Vn(12),t),h=er("ciphertext",ao(p,t),d),g=er("seed",32,32),w=(b,y,E,_)=>{let S=[];for(let k=0;k<t;k++)S.push(Re.NTT.encode(Jn(n,_,k,i)));let x=new Uint16Array(Ee),R=[];for(let k=0;k<t;k++){let N=Jn(n,_,t+k,c),V=new Uint16Array(Ee);for(let z=0;z<t;z++){let ue=y(k,z);tr(V,lo(ue,S[z]))}tr(N,Re.NTT.decode(V)),R.push(N),tr(x,lo(b[k],S[k])),X(V)}let D=Jn(n,_,2*t,c);tr(D,Re.NTT.decode(x));let P=u.decode(E);return tr(P,D),X(b,S,x,D),h.encode([R,P])};return{secretCoder:m,lengths:{secretKey:m.bytesLen,publicKey:f.bytesLen,cipherText:h.bytesLen},keygen:b=>{Ge(b,32,"seed");let y=new Uint8Array(33);y.set(b),y[32]=t;let E=o(y),[_,S]=g.decode(E),x=[],R=[];for(let k=0;k<t;k++)x.push(Re.NTT.encode(Jn(n,S,k,i)));let D=s(_);for(let k=0;k<t;k++){let N=Re.NTT.encode(Jn(n,S,t+k,i));for(let V=0;V<t;V++){let z=ji(D.get(V,k));tr(N,lo(z,x[V]))}R.push(N)}D.clean();let P={publicKey:f.encode([R,_]),secretKey:m.encode(x)};return X(_,S,x,R,y,E),P},encrypt:(b,y,E)=>{let[_,S]=f.decode(b),x=s(S),R=w(_,(D,P)=>ji(x.get(D,P)),y,E);return x.clean(),R},prepare:b=>{let[y,E]=f.decode(b),_=s(E),S=[];for(let x=0;x<t;x++)for(let R=0;R<t;R++)S.push(ji(_.get(x,R)));return _.clean(),{encrypt:(x,R)=>w(y.map(D=>D.slice()),(D,P)=>S[D*t+P].slice(),x,R),clean:()=>X(y,S)}},decrypt:(b,y)=>{let[E,_]=h.decode(b),S=m.decode(y),x=new Uint16Array(Ee);for(let D=0;D<t;D++)tr(x,lo(S[D],Re.NTT.encode(E[D])));Vd(_,Re.NTT.decode(x));let R=u.encode(_);return X(x,S,E,_),R}}};function Xd(r){let e=r,t=Yd(e),{HASH256:n,HASH512:s,KDF:o}=e,{secretCoder:i,lengths:c}=t,a=er("secretKey",c.secretKey,c.publicKey,32,32),l=32,u=64,d=(f,m)=>{let h=f.subarray(0,384*e.K),g=i.encode(i.decode(ht(h))),w=qt(g,h);if(X(g),!w)throw new Error(`ML-KEM.${m}: wrong publicKey modulus`)},p=Object.freeze({...c,seed:64,msg:l,msgRand:l,secretKey:a.bytesLen});return Object.freeze({info:Object.freeze({type:"ml-kem"}),lengths:p,keygen:f=>{let m=f===void 0,h=m?mt(u):f,g,w;try{Ge(h,u,"seed");let b=t.keygen(h.subarray(0,32)),y=b.publicKey;g=b.secretKey,w=n(y);let E=a.encode([g,y,w,h.subarray(32)]);return{publicKey:y,secretKey:E}}finally{g!==void 0&&X(g),w!==void 0&&X(w),m&&X(h)}},getPublicKey:f=>{let[m,h,g,w]=a.decode(f);return Uint8Array.from(h)},encapsulate:(f,m)=>{let h=m===void 0,g=h?mt(l):m,w;try{return Ge(f,c.publicKey,"publicKey"),Ge(g,l,"message"),d(f,"encapsulate"),w=s.create().update(g).update(n(f)).digest(),{cipherText:t.encrypt(f,g,w.subarray(32,64)),sharedSecret:w.subarray(0,32)}}finally{w!==void 0&&X(w.subarray(32)),h&&X(g)}},decapsulate:(f,m)=>{Ge(m,a.bytesLen,"secretKey"),Ge(f,c.cipherText,"cipherText");let h=a.bytesLen-96,g=h+32,w=n(m.subarray(h/2,g));if(!qt(w,m.subarray(g,g+32)))throw new Error("invalid secretKey: hash check failed");let[b,y,E,_]=a.decode(m),S=t.decrypt(f,b),x=s.create().update(S).update(E).digest(),R=x.subarray(0,32),D=t.encrypt(y,S,x.subarray(32,64)),P=qt(f,D),k=o.create({dkLen:32}).update(_).update(f).digest();return X(S,D,x.subarray(32),P?k:R),P?R:k},prepare:f=>{Ge(f,c.publicKey,"publicKey"),d(f,"prepare");let m=ht(f),h=n(m),g=t.prepare(m);return Object.freeze({publicKey:m,encapsulate:w=>{let b=w===void 0,y=b?mt(l):w,E;try{return Ge(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)),b&&X(y)}},decapsulate:(w,b)=>{Ge(b,a.bytesLen,"secretKey"),Ge(w,c.cipherText,"cipherText");let[y,E,_,S]=a.decode(b);if(!qt(E,m)||!qt(_,h))throw new Error("ML-KEM.decapsulate: secretKey does not match prepared publicKey");let x=t.decrypt(w,y),R=s.create().update(x).update(h).digest(),D=R.subarray(0,32),P=g.encrypt(x,R.subarray(32,64)),k=qt(w,P),N=o.create({dkLen:32}).update(S).update(w).digest();return X(x,P,R.subarray(32),k?N:D),k?D:N},clean:g.clean})}})}function zd(r,e,t){return $r.create({dkLen:r}).update(e).update(new Uint8Array([t])).digest()}var Qd={HASH256:io,HASH512:jc,KDF:$r,XOF:Yc,PRF:zd},Zd=r=>Xd({...Qd,...r});var Xc=Zd(Kd[768]);var qd=(r,e)=>{let t=Wi(r,e);return Wi(t.lengths,`${e}.lengths`),Me(t.keygen,`${e}.keygen`),Me(t.getPublicKey,`${e}.getPublicKey`),Me(t.encapsulate,`${e}.encapsulate`),Me(t.decapsulate,`${e}.decapsulate`),t};function Kr(r,e){let t=le(r,e);if(t===0)throw new RangeError(`"${e}" expected integer greater than 0, got 0`);return t}function Gn(r,e){let t=er(e,...r.map(n=>{if(typeof n.lengths[e]!="number")throw new Error("wrong length: "+e);return Kr(n.lengths[e],e)}));return Kr(t.bytesLen,e),t}function ep(r,e,...t){let n=e,s=t,o=Gn(s,"seed"),i=Gn(s,"publicKey"),c=Kr(r===void 0?o.bytesLen:r,"realSeedLen");function a(u){Y(u,c);let d=n(u,o.bytesLen),p=d.buffer===u.buffer?ht(d):d,f=[],m=[],h=[],g=[],w=!1;try{for(let b of o.decode(p))f.push(ht(b));for(let b=0;b<s.length;b++){let y=s[b].keygen(f[b]);m.push(y.secretKey),h.push(ht(y.secretKey)),g.push(y.publicKey)}return w=!0,{secretKey:h,publicKey:g}}finally{X(p,f,m),w||X(h)}}let l=u=>{let d=u===void 0?mt(c):ht(u),p;try{let{publicKey:f,secretKey:m}=a(d);try{p={secretKey:d,publicKey:i.encode(f)}}finally{X(f,m)}return p}finally{p||X(d)}};return{info:{lengths:{seed:c,publicKey:i.bytesLen,secretKey:c}},getPublicKey:u=>{let d=l(u);return X(d.secretKey),d.publicKey},keygen:l,expandDecapsulationKey:a,realSeedLen:c}}function tp(r,e,t,n,...s){if(r!==void 0&&Kr(r,"realSeedLen"),e!==void 0&&Kr(e,"realMsgLen"),typeof t!="function")throw new TypeError('"expandSeed" expected function, got type='+typeof t);if(typeof n!="function")throw new TypeError('"combiner" expected function, got type='+typeof n);let o=n,i=s;if(i.length===0)throw new RangeError("combineKEMS requires at least one KEM");for(let m=0;m<i.length;m++)qd(i[m],`kems[${m}]`);let c=ep(r,t,...i),a=Gn(i,"cipherText"),l=Gn(i,"publicKey"),u=Gn(i,"msg"),d=Kr(e===void 0?u.bytesLen:e,"realMsgLen"),p=Object.freeze({...c.info.lengths,msg:d,msgRand:u.bytesLen,cipherText:a.bytesLen}),f=(m,h,g)=>{let w=o(m,h,g);try{return ht(Y(w,d,"sharedSecret"))}catch(b){if(Xt(w)){let y=_=>w.buffer===_.buffer&&w.byteOffset<_.byteOffset+_.byteLength&&_.byteOffset<w.byteOffset+w.byteLength;m.some(y)||h.some(y)||X(w)}throw b}};return Object.freeze({lengths:p,getPublicKey:c.getPublicKey,keygen:c.keygen,encapsulate(m,h=mt(u.bytesLen)){let g=l.decode(m),w=u.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:f(g,y,b),cipherText:E}}finally{X(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 f(w,g,y)}finally{X(b,y)}}})}function rp(r,e,t,n){let s=r.Point.Fn;if(!s)throw new Error("no Point.Fn");function o(c){let a;for(let d=0,p=e;;d=p,p+=e){if(p>c.length)throw new Error("rejection sampling failed");if(a=s.fromBytes(c.subarray(d,p),!0),s.isValidNot0(a))break}let l=s.toBytes(s.create(a)),u=r.getPublicKey(l,!1);return{secretKey:l,publicKey:u}}let i=(c,a)=>r.getSharedSecret(a,c).subarray(1);return{lengths:{secretKey:e,publicKey:t,seed:n,msg:n,cipherText:t},keygen(c=mt(n)){return Y(c,n,"seed"),o(c)},getPublicKey(c){return r.getPublicKey(c,!1)},encapsulate(c,a=mt(n)){Y(a,n,"rand");let l;try{l=o(a).secretKey;let u=i(c,l),d=r.getPublicKey(l,!1);return{sharedSecret:u,cipherText:d}}finally{l&&X(l)}},decapsulate:i}}function np(r,e,t,n){let{secretKey:s,publicKeyUncompressed:o}=t.lengths;if(!s||!o)throw new Error("wrong curve");let i=rp(t,s,o,n),a=64+n;return tp(32,32,l=>(Y(l,32),$r(l,{dkLen:a})),(l,u,d)=>io(je(d[0],d[1],u[1],l[1],Qa(r))),e,i)}var zc=np("MLKEM768-P256",Xc,Uc,128);function Qc(r){let e=zc.encapsulate(r);return{kemCtBase64:Yt(e.cipherText),sharedSecret:e.sharedSecret}}async function Zc(r){let e=crypto.subtle,t=await e.importKey("raw",r,{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 qc(r,e){let t=crypto.getRandomValues(new Uint8Array(12)),n=new TextEncoder().encode(JSON.stringify(e)),s=await crypto.subtle.encrypt({name:"AES-GCM",iv:t},r,n),o={iv:Yt(t),ciphertext:Yt(s)};return JSON.stringify(o)}var sp=3600*1e3,Vi=new Map,uo=new Map;async function el(r,e,t){let n=Date.now(),s=Vi.get(e);if(s&&s.expiresAt>n)return s;let o=uo.get(e);if(o)return await o;let i=(async()=>{try{return await op(r,e,t)}finally{uo.delete(e)}})();return uo.set(e,i),await i}async function op(r,e,t){let n=Date.now(),s=Math.floor(n/1e3),o=s+3600,i=$s(t),{kemCtBase64:c,sharedSecret:a}=Qc(i),l=await Zc(a),u=`kem_${On()}`;try{await r.prepare("INSERT INTO kem_keys (id, profile_id, kem_ct, created_at, expires_at) VALUES (?, ?, ?, ?, ?)").bind(u,e,c,s,o).run()}catch(p){console.error(`[DekManager] Failed to persist kem_key ${u} to D1:`,p)}let d={kemKeyId:u,dek:l,profileId:e,createdAt:n,expiresAt:n+sp};return Vi.set(e,d),d}function tl(r){Vi.delete(r),uo.delete(r)}var Gi=new Map;async function ip(r,e){let t=Date.now(),n=Gi.get(e);if(n&&n.expiresAt>t)return n.key;try{let s=null;try{s=await r.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 r.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=300*1e3;return Gi.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 nr(r){Gi.delete(r),tl(r)}var rr=[],rl=50,nl=15e3,Ji=3600,po=0,Yn=!1,sl=Date.now();async function ap(r){let e=Date.now();if(po>e)return!0;if(r)try{let t=await v.get(r,"d1:write_quota_tripped");if(t&&t>Math.floor(e/1e3))return po=t*1e3,!0}catch{}return!1}async function cp(r){let t=Math.floor(Date.now()/1e3)+Ji;if(po=t*1e3,rr.length=0,Yn=!1,console.warn(`[LogBatcher] D1 write quota limit reached! Silencing log writes for ${Ji}s.`),r)try{await v.set(r,"d1:write_quota_tripped",t,Ji)}catch{}}async function fo(r,e){if(Yn=!1,sl=Date.now(),rr.length===0)return;let t=caches.default;if(await ap(t)){rr.length=0;return}let n=rr.splice(0,rl);if(n.length===0)return;let s=new Ue(r.DB),o=[],i=Array.from(new Set(n.map(l=>l.profile_id))),c=new Map,a=new Map;await Promise.all(i.map(async l=>{let u=await ip(r.DB,l);if(u&&(c.set(l,u),"pqc_pk"in u)){let d=await el(r.DB,l,u.pqc_pk);d&&a.set(l,d)}}));for(let l of n){let u=c.get(l.profile_id);if(u)try{let d={domain:l.domain,client_ip:l.client_ip,geo_country:l.geo_country,answer:l.answer,dest_geoip:l.dest_geoip,dest_country_code:l.dest_country_code,dest_country:l.dest_country,dest_isp:l.dest_isp,ecs:l.ecs,upstream:l.upstream,reason:l.reason};if("pqc_pk"in u){let p=a.get(l.profile_id);if(p){let f=await qc(p.dek,d);l.encrypt_version=2,l.kem_key_id=p.kemKeyId,l.encrypted_payload=f}}else if("kty"in u){let p=await Ka(u,d);l.encrypt_version=1,l.kem_key_id=null,l.encrypted_payload=p}l.encrypt_version&&l.encrypt_version>0&&(l.domain="",l.client_ip="",l.geo_country="",l.answer=void 0,l.dest_geoip=void 0,l.dest_country_code=null,l.dest_country=null,l.dest_isp=null,l.ecs=void 0,l.upstream=void 0,l.reason=void 0)}catch(d){console.error(`[LogBatcher] Encryption failed for profile ${l.profile_id}:`,d)}else l.encrypt_version=0,l.kem_key_id=null;o.push(s.createInsertStatement(l))}try{await r.DB.batch(o)}catch(l){let u=String(l?.message||l);u.includes("exceeded D1's free tier daily row write limit")||u.includes("row write limit")||u.includes("daily write limit")?await cp(t):console.warn(`[LogBatcher] Batch write failed (${o.length} stmts):`,u)}rr.length>0&&ol(r,e)}function ol(r,e){if(Yn)return;Yn=!0;let t=new Promise(n=>setTimeout(n,nl)).then(()=>fo(r,e)).catch(n=>{Yn=!1,console.error("[LogBatcher] Deferred flush error:",n)});e&&typeof e.waitUntil=="function"&&e.waitUntil(t)}function Xn(r,e,t,n){if(e&&Number(e.log_retention_days)===0)return;let s=(r.action||"PASS").toUpperCase();if(e?.skip_log_on_pass&&s==="PASS"||po>Date.now())return;r.id||(r.id=On()),rr.push(r);let o=Date.now();rr.length>=rl||o-sl>=nl?n.waitUntil(fo(t,n)):ol(t,n)}async function il(r,e,t,n,s,o,i,c,a){let l=r.headers.get("CF-Connecting-IP")||"127.0.0.1",u,d=i||"";if(s==="REDIRECT"&&i)if(c==="CNAME"&&(e.type==="A"||e.type==="AAAA")&&a)try{let f=Kt(i,e.type),m={name:i,type:e.type,raw:f},h=await a(r,m,t,n,"PASS");if(h.answer&&h.answer.length>0){let g=Le(h.answer),w=[{type:"CNAME",value:i,ttl:60}];for(let b of g)(b.type===e.type||b.type==="CNAME")&&w.push({name:b.name,type:b.type,value:b.data,ttl:b.ttl});u=ni(e.raw,w,0)}else u=_e(e.raw,c,i)}catch(f){console.error("CNAME resolution failed:",f),u=_e(e.raw,c,i)}else u=_e(e.raw,c||e.type,i);else{let f=n.block_mode||"NULL_IP";if(f==="NXDOMAIN")u=_e(e.raw,e.type,"",3600,3),d="NXDOMAIN";else if(f==="NODATA")u=_e(e.raw,e.type,"",3600,0),d="NODATA";else if(f==="CUSTOM_IP"){let m=e.type==="AAAA"?n.custom_block_ipv6||"::":n.custom_block_ipv4||"0.0.0.0";u=_e(e.raw,e.type,m),d=m}else{let m=e.type==="AAAA"?"::":"0.0.0.0";u=_e(e.raw,e.type,m),d=m}}let p=Date.now()-t.startTime;return t.ctx.waitUntil((async()=>{try{let f=await Gt(r,l);Xn({profile_id:t.profileId,access_point_id:t.accessPointId,timestamp:Math.floor(Date.now()/1e3),client_ip:l,geo_country:f,domain:e.name,record_type:e.type,action:s,reason:o,answer:d,latency:p},n,t.env,t.ctx)}catch{}})()),{answer:u,ttl:3600,action:s,reason:o,latency:p}}function al(r,e,t,n,s,o,i,c,a,l,u){let d=r.headers.get("CF-Connecting-IP")||"127.0.0.1";t.ctx.waitUntil((async()=>{try{let p=Gt(r,d),f=i.find(E=>E.type==="A"||E.type==="AAAA")?.data,m="",h=null,g=null,w=null;if(f){let E=await Ln(f);E&&(m=JSON.stringify(E),h=E.country_code?E.country_code.toUpperCase():null,g=E.country||null,w=E.isp||null)}let b=await p,y=Date.now()-t.startTime;Xn({profile_id:t.profileId,access_point_id:t.accessPointId,timestamp:Math.floor(Date.now()/1e3),client_ip:d,geo_country:b,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:w,upstream:l,latency:y,ecs:u},n,t.env,t.ctx),c.length>0&&_r.set(`${t.profileId}:${e.name}:${e.type}`,{answer:c,ttl:a,action:s,reason:o,expiresAt:Date.now()+a*1e3})}catch{}})())}function cl(r,e,t,n,s,o,i,c,a){let l=0,u,d=o instanceof Error?o.message:String(o),p,f;if(o instanceof kr)l=o.status,u=o.statusText||void 0,p=o.responseBodySnippet||void 0,f=o.cfRay;else if(o&&typeof o=="object"&&"cause"in o&&o.cause){let b=o.cause,y=typeof b=="object"&&b&&"message"in b?String(b.message):String(b);d+=` (Cause: ${y})`}let m=l>0?`Upstream HTTP ${l}${u?` ${u}`:""}`:`Upstream Error: ${d}`,h=r.headers.get("CF-Connecting-IP")||"127.0.0.1";t.ctx.waitUntil((async()=>{try{let b=await Gt(r,h);Xn({profile_id:t.profileId,access_point_id:t.accessPointId,timestamp:Math.floor(Date.now()/1e3),client_ip:h,geo_country:b,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},n,t.env,t.ctx)}catch{}})());let g=c||s,w=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:w,status:l,status_text:u,error_detail:d,response_body:p,cf_ray:f}}}var st={async resolve(r,e,t,n,s,o){let i=n.upstream[0]||"https://security.cloudflare-dns.com/dns-query";if(!ut(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}=Ba(r,e,n),l;try{l=At(i);let u=await Dt(l,c),d=Le(u.answer),p=await Fa(e,d,u.answer,t,n,r,st.resolve,o),f=p.answer,m=p.parsedAnswers,h=p.effectiveReason,g=m.length>0?Math.max(10,Math.min(...m.map(w=>w.ttl))):60;return al(r,e,t,n,s,h,m,f,g,i,a),{answer:f,ttl:g,action:s,reason:h,latency:Date.now()-t.startTime,timings:{upstream_fetch:u.latency},diagnostics:{upstream_url:i.startsWith("sdns://")?`${i} (${u.diagTarget})`:u.diagTarget,method:u.diagMethod,status:200,status_text:"OK"}}}catch(u){return cl(r,e,t,n,i,u,a,l?.diagTarget,l?.diagMethod)}},async block(r,e,t,n,s,o,i,c){return il(r,e,t,n,s,o,i,c,st.resolve)}};var Wr=class{static isMatch(e,t){let n=e.toLowerCase(),s=t.toLowerCase();return n===s||n.endsWith(`.${s}`)}static findMatch(e,t){for(let n of t)if(this.isMatch(e,n.pattern))return n;return null}};var ll={async match(r,e,t,n,s,o,i){let c=e.name.toLowerCase(),a=s.filter(f=>f.type==="ALLOW");if(Wr.findMatch(e.name,a))return i("local_rules"),st.resolve(r,e,t,n,"PASS","Whitelist");let l=s.filter(f=>f.type==="REDIRECT"),u=Wr.findMatch(e.name,l);if(u){let f,m=e.type;if(e.type==="A"?(f=u.v_a,!f&&u.v_cname&&(f=u.v_cname,m="CNAME")):e.type==="AAAA"?(f=u.v_aaaa,!f&&u.v_cname&&(f=u.v_cname,m="CNAME")):e.type==="TXT"?f=u.v_txt:e.type==="CNAME"&&(f=u.v_cname),f)return i("local_rules"),await st.block(r,e,t,n,"REDIRECT",`Rule: ${u.pattern}`,f,m)}let d=s.filter(f=>f.type==="BLOCK"),p=Wr.findMatch(e.name,d);if(p)return i("local_rules"),st.block(r,e,t,n,"BLOCK",`Blacklist: ${p.pattern}`);if(i("local_rules"),o){let f=c;for(;f;){if(o.test(f))return i("bloom_check"),st.block(r,e,t,n,"BLOCK",`External List: ${f}`);let m=f.indexOf(".");if(m===-1)break;f=f.substring(m+1)}i("bloom_check")}return null}};var ce={clearCache:_s.clear,async process(r,e,t){let n={},s=t.startTime,o=u=>{let d=Date.now();n[u]=(n[u]||0)+(d-s),s=d};if(e.name.toLowerCase()==="obex"&&e.type==="TXT")return{answer:_e(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=_r.get(`${t.profileId}:${e.name}:${e.type}`);if(i&&Date.now()<i.expiresAt&&i.answer instanceof Uint8Array){let u=new Uint8Array(i.answer);u.length>=2&&e.raw.length>=2&&(u[0]=e.raw[0],u[1]=e.raw[1]);let d=Date.now()-t.startTime;return{answer:u,ttl:Math.ceil((i.expiresAt-Date.now())/1e3),action:i.action,reason:i.reason,latency:d,timings:{dns_cache_mem:d}}}let c=await Oa.load(t,o);if(!c)return{answer:new Uint8Array,ttl:0,action:"FAIL",reason:"Profile Not Found"};let a=await ll.match(r,e,t,c.settings,c.rules,c.bloom,o);if(a)return{...a,timings:{...n,...a.timings}};if(c.settings.default_policy==="BLOCK"){let u=await st.block(r,e,t,c.settings,"BLOCK","Default Policy");return{...u,timings:{...n,...u.timings}}}let l=await st.resolve(r,e,t,c.settings,"PASS");return{...l,timings:{...n,...l.timings}}}};function lp(r){if(!r||typeof r!="object")return null;let e=0;for(let t of Object.keys(r)){let n=t.match(/^KEK_[vV](\d+)$/);if(n){let s=r[t];if(s!=null&&s!==""){let o=parseInt(n[1],10);!isNaN(o)&&o>e&&(e=o)}}}return e>0?`v${e}`:null}function mo(r,e){if(!e)return null;let t=e[`KEK_${r}`]||e[`KEK_${r.toUpperCase()}`];return t&&typeof t=="string"&&t.trim()!==""?t:(r==="v0"||r==="default")&&e.JWT_SECRET&&typeof e.JWT_SECRET=="string"&&e.JWT_SECRET.trim()!==""?e.JWT_SECRET:null}function jr(r){let e="",t=r.byteLength;for(let n=0;n<t;n++)e+=String.fromCharCode(r[n]);return btoa(e)}function Vr(r){let e=atob(r),t=e.length,n=new Uint8Array(t);for(let s=0;s<t;s++)n[s]=e.charCodeAt(s);return n}async function ho(r){let t=new TextEncoder().encode(r.trim()),n=await crypto.subtle.digest("SHA-256",t);return await crypto.subtle.importKey("raw",n,{name:"AES-GCM"},!1,["encrypt","decrypt"])}async function ul(r){return await crypto.subtle.importKey("raw",r,{name:"AES-GCM"},!1,["encrypt","decrypt"])}async function Ot(r,e){let t=lp(e);if(!t)return null;let n=mo(t,e);if(!n||typeof n!="string"||n.trim()==="")throw new Error(`KEK version ${t} is missing or invalid in environment variables`);let s=await ho(n),o=new Uint8Array(32);crypto.getRandomValues(o);let i=await ul(o),c=new Uint8Array(12);crypto.getRandomValues(c);let l=new TextEncoder().encode(r),u=await crypto.subtle.encrypt({name:"AES-GCM",iv:c},i,l),d={ciphertext:jr(new Uint8Array(u)),iv:jr(c)},p=new Uint8Array(12);crypto.getRandomValues(p);let f=await crypto.subtle.encrypt({name:"AES-GCM",iv:p},s,o),m={ciphertext:jr(new Uint8Array(f)),iv:jr(p),kek_version:t};return{dataEncrypted:JSON.stringify(d),dekEncrypted:JSON.stringify(m)}}async function Yi(r,e,t){let n,s;try{n=JSON.parse(r),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=mo(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 ho(c),l=Vr(s.ciphertext),u=Vr(s.iv),d=await crypto.subtle.decrypt({name:"AES-GCM",iv:u},a,l),p=new Uint8Array(d),f=await ul(p),m=Vr(n.ciphertext),h=Vr(n.iv),g=await crypto.subtle.decrypt({name:"AES-GCM",iv:h},f,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 Xi(r,e){if(!e)return null;let t;try{t=JSON.parse(r)}catch{return null}let n=t.kek_version,s=parseInt(n.replace(/^v/,""),10);if(isNaN(s))return null;let i=`v${s+1}`,c=mo(i,e);if(!c||typeof c!="string"||c.trim()==="")return null;let a=mo(n,e);if(!a||typeof a!="string"||a.trim()==="")throw new Error(`Current KEK version ${n} required for rotation is missing or invalid in environment`);let l=await ho(a),u=Vr(t.ciphertext),d=Vr(t.iv),p=await crypto.subtle.decrypt({name:"AES-GCM",iv:d},l,u),f=new Uint8Array(p),m=await ho(c),h=new Uint8Array(12);crypto.getRandomValues(h);let g=await crypto.subtle.encrypt({name:"AES-GCM",iv:h},m,f),w={ciphertext:jr(new Uint8Array(g)),iv:jr(h),kek_version:i};return JSON.stringify(w)}var go=class{constructor(e,t){this.db=e;this.env=t}db;env;async processUserSecrets(e){if(!e)return null;let t={},n=!1,s=e.totp_secret;if(e.totp_secret_encrypted&&e.totp_secret_dek)try{s=await Yi(e.totp_secret_encrypted,e.totp_secret_dek,this.env);let i=await Xi(e.totp_secret_dek,this.env);i&&(t.totp_secret_dek=i,n=!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 Ot(e.totp_secret,this.env);i&&(t.totp_secret_encrypted=i.dataEncrypted,t.totp_secret_dek=i.dekEncrypted,t.totp_secret=null,n=!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 Yi(e.totp_recovery_keys_encrypted,e.totp_recovery_keys_dek,this.env);let i=await Xi(e.totp_recovery_keys_dek,this.env);i&&(t.totp_recovery_keys_dek=i,n=!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 Ot(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,n=!0)}catch(i){console.error(`[Envelope Encryption] Migration failed for totp_recovery_keys of user ${e.id}:`,i)}if(n)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 yo=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(`
|
|
325
325
|
SELECT
|
|
326
326
|
u.id,
|
|
327
327
|
u.username,
|
|
@@ -334,7 +334,7 @@ SQL: ${this.sql}`),t}}},zo=class{constructor(e,t){this.rawDb=e;this.dbPath=t}raw
|
|
|
334
334
|
u.last_active_at as last_resolve_at
|
|
335
335
|
FROM users u
|
|
336
336
|
ORDER BY u.created_at DESC
|
|
337
|
-
`).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
|
|
337
|
+
`).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 wo=class{constructor(e){this.db=e}db;async updatePassword(e,t,n=2){return(await this.db.prepare("UPDATE users SET hashed_password = ?, password_version = ? WHERE id = ?").bind(t,n,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 bo=class{constructor(e,t){this.db=e;this.env=t}db;env;async updateTOTP(e,t,n){let s=JSON.stringify(n),o=await Ot(t,this.env),i=await Ot(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 n=JSON.stringify(t),s=await Ot(n,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(n,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,n){let s=n.filter((c,a)=>a!==t),o=JSON.stringify(s),i=await Ot(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 Eo=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,n=e-2160*3600,s=this.db.prepare(`
|
|
338
338
|
DELETE FROM logs
|
|
339
339
|
WHERE profile_id IN (
|
|
340
340
|
SELECT id FROM profiles
|
|
@@ -359,27 +359,27 @@ SQL: ${this.sql}`),t}}},zo=class{constructor(e,t){this.rawDb=e;this.dbPath=t}raw
|
|
|
359
359
|
FROM user_activity_log
|
|
360
360
|
WHERE user_id = users.id
|
|
361
361
|
) < ?
|
|
362
|
-
`).bind(n),c=await this.db.batch([s,o,i]);return{clearedProfiles:c[1].meta.changes||0,deletedUsers:c[2].meta.changes||0}}};var G=class{secrets;core;security;mfa;lifecycle;constructor(e,t){this.secrets=new
|
|
362
|
+
`).bind(n),c=await this.db.batch([s,o,i]);return{clearedProfiles:c[1].meta.changes||0,deletedUsers:c[2].meta.changes||0}}};var G=class{secrets;core;security;mfa;lifecycle;constructor(e,t){this.secrets=new go(e,t),this.core=new yo(e,this.secrets),this.security=new wo(e),this.mfa=new bo(e,t),this.lifecycle=new Eo(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,n=2){return this.security.updatePassword(e,t,n)}async updatePinHash(e,t){return this.security.updatePinHash(e,t)}async updateSessionLockTimeout(e,t){return this.security.updateSessionLockTimeout(e,t)}async updateTOTP(e,t,n){return this.mfa.updateTOTP(e,t,n)}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,n){return this.mfa.consumeRecoveryKey(e,t,n)}async updateLastActiveByProfile(e,t){return this.lifecycle.updateLastActiveByProfile(e,t)}async applyInactivityPolicy(e){return this.lifecycle.applyInactivityPolicy(e)}};ge();var zi=new Map;async function up(r){try{if(r.method==="GET"){let t=new URL(r.url).searchParams.get("dns");if(!t)return null;let n=t.replace(/-/g,"+").replace(/_/g,"/");for(;n.length%4;)n+="=";let s=atob(n),o=new Uint8Array(s.length);for(let i=0;i<s.length;i++)o[i]=s.charCodeAt(i);return o}else if(r.method==="POST"){let e=await r.clone().arrayBuffer();return new Uint8Array(e)}}catch{return null}return null}async function Jr(r,e,t){let n=caches.default,s=Date.now(),o=_n.get(r);if(o&&s-o.ts<3e5)return o.data;let i=`doh_key_v1:${r}`;try{let c=await v.get(n,i);if(c)return _n.set(r,{data:c,ts:s}),c}catch{}try{let a=await new q(e.DB).findByKey(r);if(a)return _n.set(r,{data:a,ts:s}),t.waitUntil(v.set(n,i,a,3600)),a}catch(c){if(console.warn(`[DoH] D1 profile lookup failed for key ${r}:`,c.message||c),o?.data)return o.data;let a=e.FAIL_OPEN_UPSTREAM||De;return console.warn(`[DoH] D1 unavailable. Providing emergency fallback profile for key ${r} -> ${a}`),{id:r,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 dl(r,e){let t=Date.now();if(Sr&&t-Sr.ts<3e5)return Sr.data;let n=r.SERVERFULL_DEFAULT_PROFILE_KEY||r.DEFAULT_PROFILE_KEY;if(n){let i=await Jr(n,r,e);if(i)return ii({data:i,ts:t}),i}let s=r.FAIL_OPEN_UPSTREAM||De,o={id:"default",name:"Default Profile",settings:JSON.stringify({upstream:[s],default_policy:"ALLOW",log_retention_days:0,ecs:{enabled:!0,use_client_ip:!0}}),owner_id:"system",created_at:Math.floor(t/1e3),updated_at:Math.floor(t/1e3)};return ii({data:o,ts:t}),o}async function pl(r,e,t,n){let s=caches.default,o=null;try{let i=await Jr(n,e,t);if(!i)return new Response("Invalid Profile Key",{status:404});let c=i.id,a=await Qo(r);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},u=await ce.process(r,a,l);return t.waitUntil((async()=>{try{let d=r.headers.get("CF-Connecting-IP")||"127.0.0.1",p=Number(e.ACTIVE_DNS_CACHE_TTL)||60;await v.set(s,`active_dns:${d}`,c,p);let f=Math.floor(Date.now()/1e3),m=Number(e.THROTTLE_ACTIVE_SEC)||3600,h=zi.get(c);if(h&&f-h<m)return;let g=`active_throttle:${c}`,w=await v.get(s,g);if(w&&f-w<m){zi.set(c,w);return}zi.set(c,f);try{await new q(e.DB).updateLastActive(c,f),await new G(e.DB,e).updateLastActiveByProfile(c,f)}catch{}await v.set(s,g,f,m)}catch(d){console.error(`[Background Task] Error for ${c}:`,d)}})()),new Response(u.answer,{headers:{"Content-Type":"application/dns-message","Cache-Control":`max-age=${u.ttl}`}})}catch(i){console.error("[DoH Pipeline] Internal Error:",i);try{let c=e.FAIL_OPEN_UPSTREAM||De,a=o||await up(r);if(a&&a.length>0){let l=At(c),u=await Dt(l,a);return new Response(u.answer,{headers:{"Content-Type":"application/dns-message","Cache-Control":"max-age=60"}})}if(c.startsWith("http://")||c.startsWith("https://")){let l=new URL(c),u=new URL(r.url);return l.search=u.search,await fetch(l.toString(),{method:r.method,headers:{Accept:r.headers.get("Accept")||"application/dns-message","Content-Type":r.headers.get("Content-Type")||"application/dns-message"},body:r.method==="POST"?r.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 fl from"node:fs";import{execSync as sr}from"node:child_process";function dp(r,e){try{let t=e.toLowerCase(),n=sr(`netstat -ano -p ${t}`,{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:3e3}),s=null,o=n.split(/\r?\n/);for(let a of o){let l=a.trim();if(!l.toUpperCase().startsWith(e))continue;let u=l.split(/\s+/);if(u.length<4)continue;let d=u[1];if(!d)continue;if(d.endsWith(`:${r}`)||d.endsWith(`]:${r}`)){if(e==="TCP"&&u[3]!=="LISTENING")continue;let f=u[u.length-1],m=parseInt(f,10);if(!isNaN(m)&&m>0){s=m;break}}}if(!s)return null;let i=`PID ${s}`,c;try{let l=sr(`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 pp(r,e){try{let n=sr(`ss ${e==="TCP"?"-lptn":"-lpun"} "sport = :${r}"`,{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:3e3});for(let s of n.split(/\r?\n/)){let i=s.trim().match(/users:\(\("([^"]+)",pid=(\d+)/);if(i)return{processName:i[1],pid:parseInt(i[2],10)}}if(r===53&&n.includes("127.0.0.53"))return{processName:"systemd-resolved",serviceName:"DNSStubListener (127.0.0.53)"}}catch{}try{let t=e==="TCP"?`-iTCP:${r} -sTCP:LISTEN`:`-iUDP:${r}`,s=sr(`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=sr(`fuser ${r}/${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{fl.existsSync(`/proc/${o}/comm`)&&(i=fl.readFileSync(`/proc/${o}/comm`,"utf-8").trim())}catch{}return{pid:o,processName:i}}}catch{}if(r===53)try{if(sr("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 fp(r,e){try{let t=e==="TCP"?`-iTCP:${r} -sTCP:LISTEN`:`-iUDP:${r}`,s=sr(`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 or(r,e){return process.platform==="win32"?dp(r,e):process.platform==="linux"?pp(r,e):fp(r,e)}function ir(r){let e=r.processName;return r.pid&&(e+=` (PID ${r.pid})`),r.serviceName&&r.serviceName!==r.processName&&(e+=` [${r.serviceName}]`),e}function Gr(r,e=" "){return r?`
|
|
363
363
|
Tip:
|
|
364
364
|
${Array.isArray(r)?r.map(n=>`${e}${n}`).join(`
|
|
365
365
|
`):`${e}${r}`}
|
|
366
|
-
`:""}function
|
|
367
|
-
${
|
|
366
|
+
`:""}function ml(r){let{name:e,description:t,usage:n,commands:s,options:o,services:i,envVars:c,tip:a}=r,l=" ",u=4,d=[...s||[],...o||[]],p=Math.max(...d.map(w=>w.label.length),0),f=(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+u)}${S.desc}`);return`
|
|
367
|
+
${w}:
|
|
368
368
|
${_.join(`
|
|
369
|
-
`)}`},m=Array.isArray(n)?n.map(
|
|
369
|
+
`)}`},m=Array.isArray(n)?n.map(w=>`${l}${w}`).join(`
|
|
370
370
|
`):`${l}${n}`,h=a?Gr(a,l).trimEnd():"";return[`${e} - ${t}`,`
|
|
371
371
|
Usage:
|
|
372
372
|
${m}`,f("Commands",s,p),f("Options",o,p),f("Current Service Ports",i),f("Environment Variables",c),h].filter(Boolean).join(`
|
|
373
373
|
`)+`
|
|
374
|
-
`}function
|
|
374
|
+
`}function _o(r){let{title:e,items:t,indent:n=" ",gap:s=4}=r;if(!t||t.length===0)return"";let o=Math.max(...t.map(c=>c.command.length),0),i=t.map(c=>`${n}${c.command.padEnd(o+s)}# ${c.desc}`);return e?`${e}
|
|
375
375
|
${i.join(`
|
|
376
376
|
`)}
|
|
377
377
|
`:i.join(`
|
|
378
378
|
`)+`
|
|
379
|
-
`}function
|
|
379
|
+
`}function So(r){let{title:e,content:t,borderChar:n="-",minWidth:s=60,tip:o}=r,i=`[${e}]`,c=Math.max(s,i.length+8),a=n.repeat(c),l=3,u=Math.max(3,c-i.length-l-2),p=[`${n.repeat(l)} ${i} ${n.repeat(u)}`,t,a];return o&&p.push(`Tip: ${o}`),`
|
|
380
380
|
`+p.join(`
|
|
381
381
|
`)+`
|
|
382
|
-
`}function
|
|
382
|
+
`}function Ye(r){let{title:e,bullet:t="\u2022 ",items:n,indent:s=" ",gap:o=2}=r;if(!n||n.length===0)return"";let i=Math.max(...n.map(a=>a.label.length),0),c=n.map(a=>`${s}${t}${a.label.padEnd(i+o)}: ${a.value}`);return e?`${e}
|
|
383
383
|
${c.join(`
|
|
384
384
|
`)}`:c.join(`
|
|
385
385
|
`)}function xe(r){let{title:e,subtitle:t,borderChar:n="-",bullet:s="\u2022 ",minWidth:o=54,items:i}=r,c=[e.length+6,t?t.length+6:0,...(i||[]).map(p=>p.label.length+p.value.length+10)],a=Math.max(o,...c),l=n.repeat(a),u=p=>{let f=Math.max(0,Math.floor((a-p.length)/2));return" ".repeat(f)+p},d=[l,u(e)];if(t&&d.push(u(t)),d.push(l),i&&i.length>0){let p=Math.max(...i.map(m=>m.label.length),0),f=i.map(m=>` ${s}${m.label.padEnd(p+2)}: ${m.value}`);d.push(...f),d.push(l)}return d.join(`
|
|
@@ -393,7 +393,7 @@ ${u}`)}return`
|
|
|
393
393
|
`)+`
|
|
394
394
|
`}function ar(r){let{serviceName:e,protocol:t,port:n,err:s,alternateOption:o,disableOption:i}=r,c=s?.code;if(c==="EADDRINUSE"){let l=t==="UDP"?"UDP":"TCP",u=r.occupant!==void 0?r.occupant:or(n,l),d=u?ir(u):null,p=[],f=[],m=[];if(d&&f.push(`Occupying Program: ${d}`),t==="UDP"&&n===53)if(u?.processName.includes("systemd-resolve"))p.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(u?.serviceName==="SharedAccess")p.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(u){if(p.push(`Program '${d}' is currently listening on UDP port 53.`),u.pid){let g=process.platform==="win32"?`taskkill /PID ${u.pid} /F`:`sudo kill ${u.pid}`;m.push(`Terminate conflicting process: '${g}'`)}}else p.push("Linux: systemd-resolved or another DNS server (bind9, dnsmasq, AdGuard Home) is listening on port 53."),p.push("Windows: Internet Connection Sharing (ICS) or another service is listening on port 53.");else if(u){if(p.push(`Program '${d}' is currently listening on ${t} port ${n}.`),u.pid){let g=process.platform==="win32"?`taskkill /PID ${u.pid} /F`:`sudo kill ${u.pid}`;m.push(`Terminate conflicting process: '${g}'`)}}else p.push(`Another service or application is already listening on ${t} port ${n}.`);m.push(`Use ${o} to specify an alternate port.`),i&&m.push(`Or use ${i} to disable this transport.`);let h=d?`${e} port ${n} is already in use by ${d}.`:`${e} port ${n} is already in use.`;return O({level:"error",title:"Port Conflict",message:h,details:f.length>0?f:void 0,causes:p,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."],u=process.platform==="linux",d=[u?"Run persistently as systemd service (Recommended): 'sudo dns-worker service install' (enables port 53 via CAP_NET_BIND_SERVICE)":"Run with elevated Administrator privileges.",u?"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 ${n}.`,causes:l,solutions:d})}let a=s instanceof Error?s.message:String(s);return`
|
|
395
395
|
[${e}] Startup Error: ${a}
|
|
396
|
-
`}var Ro=class{constructor(e){this.options=e}options;socket=null;isRunning=!1;start(){return new Promise((e,t)=>{try{this.socket=hp.createSocket("udp4");let n=s=>{try{this.socket?.close()}catch{}this.socket=null,console.error(ar({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",n),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",n),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(n){t(n)}})}async handleMessage(e,t){try{let n=new Uint8Array(e.buffer,e.byteOffset,e.byteLength),s=br(n);if(!s)return;let o=this.options.env,i={waitUntil(f){f.catch(m=>console.error("[UDP Background Task Error]:",m))},passThroughOnException(){}},c=null;if(this.options.defaultProfileKey&&(c=await Jr(this.options.defaultProfileKey,o,i)),c||(c=await pl(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,u=new Request(`http://${l}/dns-query`,{headers:{"CF-Connecting-IP":t.address,Accept:"application/dns-message","Content-Type":"application/dns-message"}}),d=await ce.process(u,s,a);if(!d||!d.answer||d.answer.length===0)return;let p=d.answer;if(p.length>512){let f=new Uint8Array(p);f[2]|=2,p=f.slice(0,512)}this.socket?.send(p,t.port,t.address,f=>{f&&console.warn(`[UDP DNS] Failed to send answer to ${t.address}:${t.port}:`,f.message)})}catch(n){console.error("[UDP DNS] Message handling exception:",n);try{let s=this.options.env.FAIL_OPEN_UPSTREAM||De,o=new Uint8Array(e.buffer,e.byteOffset,e.byteLength),i=At(s),a=(await Dt(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 xo from"node:fs";import yp from"node:tls";import{Buffer as Ao}from"node:buffer";import zn from"node:fs";import gp from"node:crypto";function Yr(r,e){if(!!!(r&&e))return{configured:!1,filesExist:!1,certPath:r||"",keyPath:e||"",isWildcard:!1,domains:[],expiresAt:null};let n=!1,s=!1,o;try{zn.accessSync(r,zn.constants.R_OK),n=!0}catch(c){let a=c?.code,l=c instanceof Error?c.message:String(c);a==="EACCES"?o=`Permission denied (EACCES) reading certPath: ${r}`:a==="ENOENT"?o=`Certificate file not found: ${r}`:o=`Cannot read certPath (${r}): ${l}`}try{zn.accessSync(e,zn.constants.R_OK),s=!0}catch(c){let a=c?.code,l=c instanceof Error?c.message:String(c),u=a==="EACCES"?`Permission denied (EACCES) reading keyPath: ${e}`:a==="ENOENT"?`Private key file not found: ${e}`:`Cannot read keyPath (${e}): ${l}`;o=o?`${o}; ${u}`:u}if(!(n&&s))return{configured:!0,filesExist:!1,certPath:r,keyPath:e,isWildcard:!1,domains:[],expiresAt:null,error:o};try{let c=zn.readFileSync(r,"utf-8"),a=new gp.X509Certificate(c),l=[],u=!1;if(a.subjectAltName){let p=a.subjectAltName.split(",").map(f=>f.trim());for(let f of p)if(f.startsWith("DNS:")){let m=f.slice(4).trim().toLowerCase();l.includes(m)||l.push(m),m.startsWith("*.")&&(u=!0)}}if(a.subject){let p=a.subject.match(/CN=([^,\n\/]+)/i);if(p){let f=p[1].trim().toLowerCase();l.includes(f)||l.push(f),f.startsWith("*.")&&(u=!0)}}let d=new Date(a.validTo);return{configured:!0,filesExist:!0,certPath:r,keyPath:e,isWildcard:u,domains:l,expiresAt:d}}catch(c){let a=c instanceof Error?c.message:String(c);return{configured:!0,filesExist:!0,certPath:r,keyPath:e,isWildcard:!1,domains:[],expiresAt:null,error:a}}}function Qn(r){let e=r?r.replace(/^\*\./,"").trim():"your.domain";return`certbot certonly -d *.${e} -d ${e} --manual --preferred-challenges dns`}function Qi(r,e){let t=Qn(e);return r==="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 Do=class{constructor(e){this.options=e}options;server=null;isRunning=!1;start(){return new Promise((e,t)=>{let{tlsKeyPath:n,tlsCertPath:s,port:o,host:i}=this.options;if(!n||!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(!xo.existsSync(n)||!xo.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 : ${n}`,`Cert path : ${s}`],solutions:["Verify the file paths or generate TLS certificates before enabling DoT."]})),e();return}if(!Yr(s,n).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:",` ${Qn(this.options.dotDomain)}`,"Install the wildcard certificate and restart dns-worker to resume DoT service."]})),e();return}try{let a={key:xo.readFileSync(n),cert:xo.readFileSync(s),ALPNProtocols:["dot"],sessionIdContext:"dns-worker-dot"};this.server=yp.createServer(a,u=>{this.handleConnection(u)});let l=u=>{this.server=null,console.error(ar({serviceName:"DNS over TLS (DoT)",protocol:"DoT",port:o,err:u,alternateOption:"--dot-port <port> (e.g. --dot-port 8853)",disableOption:"--disable-dot"})),t(u)};this.server.once("error",l),this.server.listen(o,i,()=>{this.server?.removeListener("error",l),this.server?.on("error",d=>{console.error("[DoT] Runtime error:",d)}),this.isRunning=!0;let u=this.options.dotDomain?` (${this.options.dotDomain})`:"";console.log(`[DoT] DNS over TLS listening on tls://${i}:${o}${u}`),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",n=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];Vt.test(l)?o=l:Vt.test(a)&&(o=a)}}if(!o&&s){let a=s.split(".")[0];Vt.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(n.length+a.length>c){e.destroy();return}for(n=Ao.concat([n,a]);n.length>=2;){let l=n.readUInt16BE(0);if(n.length<2+l)break;let u=n.subarray(2,2+l);n=n.subarray(2+l),await this.processQuery(e,u,t,o)}})}async processQuery(e,t,n,s){try{let o=br(t);if(!o)return;let i=this.options.env,c={waitUntil(f){f.catch(m=>console.error("[DoT Background Task Error]:",m))},passThroughOnException(){}};if(!s){e.destroy();return}let a=await Jr(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},u=n.includes(":")?`[${n}]`:n,d=new Request(`http://${u}/dns-query`,{headers:{"CF-Connecting-IP":n,Accept:"application/dns-message","Content-Type":"application/dns-message"}}),p=await ce.process(d,o,l);if(!p||!p.answer||p.answer.length===0)return;if(!e.destroyed&&e.writable){let f=p.answer,m=Ao.allocUnsafe(2+f.length);m.writeUInt16BE(f.length,0),m.set(f,2),e.write(m)}}catch(o){console.error("[DoT] Query processing exception:",o);try{let i=this.options.env.FAIL_OPEN_UPSTREAM||De,c=At(i),a=await Dt(c,t);if(!e.destroyed&&e.writable){let l=a.answer,u=Ao.allocUnsafe(2+l.length);u.writeUInt16BE(l.length,0),u.set(l,2),e.write(u)}}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 vp from"node:http";import Pp from"node:https";import nu from"node:fs";import Zi from"node:fs";import vo from"node:path";var wp={".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 qi(r,e){if(r.ASSETS)return;let t=e||vo.join(st(),"static");r.ASSETS={fetch:async n=>{try{let s=new URL(n.url),o=decodeURIComponent(s.pathname);(o==="/"||o==="")&&(o="/index.html");let i=vo.normalize(o).replace(/^(\.\.[\/\\])+/,""),c=vo.join(t,i);if(Zi.existsSync(c)&&Zi.statSync(c).isFile()){let a=vo.extname(c).toLowerCase(),l=wp[a]||"application/octet-stream",u=Zi.readFileSync(c);return new Response(u,{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})}}}}import{Buffer as ru}from"node:buffer";pe();function gl(r,e){return`#!/bin/bash
|
|
396
|
+
`}var To=class{constructor(e){this.options=e}options;socket=null;isRunning=!1;start(){return new Promise((e,t)=>{try{this.socket=mp.createSocket("udp4");let n=s=>{try{this.socket?.close()}catch{}this.socket=null,console.error(ar({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",n),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",n),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(n){t(n)}})}async handleMessage(e,t){try{let n=new Uint8Array(e.buffer,e.byteOffset,e.byteLength),s=wr(n);if(!s)return;let o=this.options.env,i={waitUntil(f){f.catch(m=>console.error("[UDP Background Task Error]:",m))},passThroughOnException(){}},c=null;if(this.options.defaultProfileKey&&(c=await Jr(this.options.defaultProfileKey,o,i)),c||(c=await dl(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,u=new Request(`http://${l}/dns-query`,{headers:{"CF-Connecting-IP":t.address,Accept:"application/dns-message","Content-Type":"application/dns-message"}}),d=await ce.process(u,s,a);if(!d||!d.answer||d.answer.length===0)return;let p=d.answer;if(p.length>512){let f=new Uint8Array(p);f[2]|=2,p=f.slice(0,512)}this.socket?.send(p,t.port,t.address,f=>{f&&console.warn(`[UDP DNS] Failed to send answer to ${t.address}:${t.port}:`,f.message)})}catch(n){console.error("[UDP DNS] Message handling exception:",n);try{let s=this.options.env.FAIL_OPEN_UPSTREAM||De,o=new Uint8Array(e.buffer,e.byteOffset,e.byteLength),i=At(s),a=(await Dt(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 Ro from"node:fs";import gp from"node:tls";import{Buffer as xo}from"node:buffer";import zn from"node:fs";import hp from"node:crypto";function Yr(r,e){if(!!!(r&&e))return{configured:!1,filesExist:!1,certPath:r||"",keyPath:e||"",isWildcard:!1,domains:[],expiresAt:null};let n=!1,s=!1,o;try{zn.accessSync(r,zn.constants.R_OK),n=!0}catch(c){let a=c?.code,l=c instanceof Error?c.message:String(c);a==="EACCES"?o=`Permission denied (EACCES) reading certPath: ${r}`:a==="ENOENT"?o=`Certificate file not found: ${r}`:o=`Cannot read certPath (${r}): ${l}`}try{zn.accessSync(e,zn.constants.R_OK),s=!0}catch(c){let a=c?.code,l=c instanceof Error?c.message:String(c),u=a==="EACCES"?`Permission denied (EACCES) reading keyPath: ${e}`:a==="ENOENT"?`Private key file not found: ${e}`:`Cannot read keyPath (${e}): ${l}`;o=o?`${o}; ${u}`:u}if(!(n&&s))return{configured:!0,filesExist:!1,certPath:r,keyPath:e,isWildcard:!1,domains:[],expiresAt:null,error:o};try{let c=zn.readFileSync(r,"utf-8"),a=new hp.X509Certificate(c),l=[],u=!1;if(a.subjectAltName){let p=a.subjectAltName.split(",").map(f=>f.trim());for(let f of p)if(f.startsWith("DNS:")){let m=f.slice(4).trim().toLowerCase();l.includes(m)||l.push(m),m.startsWith("*.")&&(u=!0)}}if(a.subject){let p=a.subject.match(/CN=([^,\n\/]+)/i);if(p){let f=p[1].trim().toLowerCase();l.includes(f)||l.push(f),f.startsWith("*.")&&(u=!0)}}let d=new Date(a.validTo);return{configured:!0,filesExist:!0,certPath:r,keyPath:e,isWildcard:u,domains:l,expiresAt:d}}catch(c){let a=c instanceof Error?c.message:String(c);return{configured:!0,filesExist:!0,certPath:r,keyPath:e,isWildcard:!1,domains:[],expiresAt:null,error:a}}}function Qn(r){let e=r?r.replace(/^\*\./,"").trim():"your.domain";return`certbot certonly -d *.${e} -d ${e} --manual --preferred-challenges dns`}function Qi(r,e){let t=Qn(e);return r==="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 Ao=class{constructor(e){this.options=e}options;server=null;isRunning=!1;start(){return new Promise((e,t)=>{let{tlsKeyPath:n,tlsCertPath:s,port:o,host:i}=this.options;if(!n||!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(!Ro.existsSync(n)||!Ro.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 : ${n}`,`Cert path : ${s}`],solutions:["Verify the file paths or generate TLS certificates before enabling DoT."]})),e();return}if(!Yr(s,n).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:",` ${Qn(this.options.dotDomain)}`,"Install the wildcard certificate and restart dns-worker to resume DoT service."]})),e();return}try{let a={key:Ro.readFileSync(n),cert:Ro.readFileSync(s),ALPNProtocols:["dot"],sessionIdContext:"dns-worker-dot"};this.server=gp.createServer(a,u=>{this.handleConnection(u)});let l=u=>{this.server=null,console.error(ar({serviceName:"DNS over TLS (DoT)",protocol:"DoT",port:o,err:u,alternateOption:"--dot-port <port> (e.g. --dot-port 8853)",disableOption:"--disable-dot"})),t(u)};this.server.once("error",l),this.server.listen(o,i,()=>{this.server?.removeListener("error",l),this.server?.on("error",d=>{console.error("[DoT] Runtime error:",d)}),this.isRunning=!0;let u=this.options.dotDomain?` (${this.options.dotDomain})`:"";console.log(`[DoT] DNS over TLS listening on tls://${i}:${o}${u}`),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",n=xo.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];Vt.test(l)?o=l:Vt.test(a)&&(o=a)}}if(!o&&s){let a=s.split(".")[0];Vt.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(n.length+a.length>c){e.destroy();return}for(n=xo.concat([n,a]);n.length>=2;){let l=n.readUInt16BE(0);if(n.length<2+l)break;let u=n.subarray(2,2+l);n=n.subarray(2+l),await this.processQuery(e,u,t,o)}})}async processQuery(e,t,n,s){try{let o=wr(t);if(!o)return;let i=this.options.env,c={waitUntil(f){f.catch(m=>console.error("[DoT Background Task Error]:",m))},passThroughOnException(){}};if(!s){e.destroy();return}let a=await Jr(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},u=n.includes(":")?`[${n}]`:n,d=new Request(`http://${u}/dns-query`,{headers:{"CF-Connecting-IP":n,Accept:"application/dns-message","Content-Type":"application/dns-message"}}),p=await ce.process(d,o,l);if(!p||!p.answer||p.answer.length===0)return;if(!e.destroyed&&e.writable){let f=p.answer,m=xo.allocUnsafe(2+f.length);m.writeUInt16BE(f.length,0),m.set(f,2),e.write(m)}}catch(o){console.error("[DoT] Query processing exception:",o);try{let i=this.options.env.FAIL_OPEN_UPSTREAM||De,c=At(i),a=await Dt(c,t);if(!e.destroyed&&e.writable){let l=a.answer,u=xo.allocUnsafe(2+l.length);u.writeUInt16BE(l.length,0),u.set(l,2),e.write(u)}}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 Dp from"node:http";import vp from"node:https";import ru from"node:fs";import Zi from"node:fs";import Do from"node:path";var yp={".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 qi(r,e){if(r.ASSETS)return;let t=e||Do.join(ot(),"static");r.ASSETS={fetch:async n=>{try{let s=new URL(n.url),o=decodeURIComponent(s.pathname);(o==="/"||o==="")&&(o="/index.html");let i=Do.normalize(o).replace(/^(\.\.[\/\\])+/,""),c=Do.join(t,i);if(Zi.existsSync(c)&&Zi.statSync(c).isFile()){let a=Do.extname(c).toLowerCase(),l=yp[a]||"application/octet-stream",u=Zi.readFileSync(c);return new Response(u,{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})}}}}import{Buffer as tu}from"node:buffer";pe();function hl(r,e){return`#!/bin/bash
|
|
397
397
|
sudo curl -L 'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64' -o /usr/local/bin/cloudflared
|
|
398
398
|
sudo chmod +x /usr/local/bin/cloudflared
|
|
399
399
|
sudo tee /etc/systemd/system/cloudflared-dns.service > /dev/null <<EOF
|
|
@@ -413,15 +413,15 @@ sudo systemctl daemon-reload
|
|
|
413
413
|
sudo systemctl enable --now cloudflared-dns
|
|
414
414
|
echo "DNS Worker DoH Proxy installed successfully."
|
|
415
415
|
echo "Please change your system DNS to 127.0.0.1"
|
|
416
|
-
`}Zn();async function
|
|
417
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).bind(t,e.userId,e.name,e.credentialId,e.publicKey,e.algorithm,e.signCount,s,e.aaguid||null,n,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:n,last_used_at:null}}async updateName(e,t,n){return(await this.db.prepare("UPDATE passkeys SET name = ? WHERE id = ? AND user_id = ?").bind(n,e,t).run()).success}async updateUsage(e,t){let n=Math.floor(Date.now()/1e3);return(await this.db.prepare("UPDATE passkeys SET sign_count = ?, last_used_at = ? WHERE id = ?").bind(t,n,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 ht(r){let e=r instanceof Uint8Array?r:new Uint8Array(r),t="";for(let n=0;n<e.length;n++)t+=String.fromCharCode(e[n]);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function It(r){let e=r.replace(/-/g,"+").replace(/_/g,"/");for(;e.length%4!==0;)e+="=";let t=atob(e),n=new Uint8Array(t.length);for(let s=0;s<t.length;s++)n[s]=t.charCodeAt(s);return n}function ur(){let r=new Uint8Array(32);return crypto.getRandomValues(r),ht(r)}function Sl(r){if(r[0]!==48){if(r.length===64)return r;throw new Error("Invalid ECDSA signature: expected ASN.1 SEQUENCE")}let e=2;if(r[1]&128&&(e=2+(r[1]&127)),r[e++]!==2)throw new Error("Expected INTEGER for r in signature");let t=r[e++],n=r.subarray(e,e+t);if(e+=t,r[e++]!==2)throw new Error("Expected INTEGER for s in signature");let s=r[e++],o=r.subarray(e,e+s);for(;n.length>32&&n[0]===0;)n=n.subarray(1);for(;o.length>32&&o[0]===0;)o=o.subarray(1);let i=new Uint8Array(64);return i.set(n,32-n.length),i.set(o,64-o.length),i}function sa(r){let e=0;function t(o){if(o<24)return o;if(o===24)return r[e++];if(o===25){let i=r[e]<<8|r[e+1];return e+=2,i}if(o===26){let i=(r[e]<<24>>>0)+(r[e+1]<<16)+(r[e+2]<<8)+r[e+3];return e+=4,i}if(o===27){let i=BigInt((r[e]<<24>>>0)+(r[e+1]<<16)+(r[e+2]<<8)+r[e+3]),c=BigInt((r[e+4]<<24>>>0)+(r[e+5]<<16)+(r[e+6]<<8)+r[e+7]);return e+=8,i<<32n|c}throw new Error(`Unsupported CBOR uint info: ${o}`)}function n(){if(e>=r.length)throw new Error("Unexpected end of CBOR data");let o=r[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=r.subarray(e,e+a);return e+=a,l}case 3:{let a=Number(t(c)),l=r.subarray(e,e+a);return e+=a,new TextDecoder().decode(l)}case 4:{let a=Number(t(c)),l=[];for(let u=0;u<a;u++)l.push(n());return l}case 5:{let a=Number(t(c)),l={};for(let u=0;u<a;u++){let d=n(),p=n();l[d]=p}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:n(),bytesRead:e}}async function Tp(r){if(r.length<37)throw new Error("Invalid authenticatorData length");let e=r.subarray(0,32),t=r[32],n=(r[33]<<24>>>0)+(r[34]<<16)+(r[35]<<8)+r[36];if(!!!(t&64))throw new Error("Attestation does not contain attested credential data");let o=37,i=r.subarray(o,o+16);o+=16;let c=Array.from(i).map(h=>h.toString(16).padStart(2,"0")).join(""),a=r[o]<<8|r[o+1];o+=2;let l=r.subarray(o,o+a);o+=a;let u=ht(l),d=r.subarray(o),{value:p}=sa(d),f=p[3]??-7,m="";if(f===-7){let h=p[-2],g=p[-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=ht(y)}else if(f===-257){let h=p[-1],g=p[-2];if(!h||!g)throw new Error("Invalid RSA COSE public key components");let b={kty:"RSA",n:ht(h),e:ht(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=ht(y)}else throw new Error(`Unsupported COSE algorithm: ${f}`);return{rpIdHash:e,flags:t,signCount:n,aaguid:c,credentialId:u,publicKeySpki:m,algorithm:f}}async function Tl(r){let{clientDataJSON:e,attestationObject:t,expectedChallenge:n,expectedOrigin:s,expectedRpId:o}=r,i=It(e),c=JSON.parse(new TextDecoder().decode(i));if(c.type!=="webauthn.create")throw new Error(`Invalid clientData type: ${c.type}`);if(c.challenge!==n)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 d=It(t),{value:p}=sa(d);if(!p.authData)throw new Error("Missing authData in attestationObject");let f=await Tp(p.authData),m=new Uint8Array(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(o)));for(let h=0;h<32;h++)if(f.rpIdHash[h]!==m[h])throw new Error("WebAuthn rpIdHash mismatch");if(!(f.flags&1))throw new Error("User Presence (UP) flag not set");return f}async function Ut(r){let{clientDataJSON:e,authenticatorData:t,signature:n,publicKeySpki:s,algorithm:o,expectedChallenge:i,expectedOrigin:c,expectedRpId:a,previousSignCount:l=0}=r,u=It(e),d=JSON.parse(new TextDecoder().decode(u));if(d.type!=="webauthn.get")throw new Error(`Invalid clientData type: ${d.type}`);if(d.challenge!==i)throw new Error("WebAuthn challenge mismatch");let p=new URL(d.origin),f=c.includes("://")?new URL(c):new URL(`https://${c}`);if(p.origin.toLowerCase()!==f.origin.toLowerCase())throw new Error(`WebAuthn origin mismatch: expected ${f.origin}, received ${p.origin}`);if(!(p.hostname==="localhost"||p.hostname==="127.0.0.1")&&p.protocol!=="https:")throw new Error(`WebAuthn requires HTTPS origin, received: ${p.protocol}`);let h=It(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 R=0;R<32;R++)if(g[R]!==y[R])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",u)),_=new Uint8Array(h.length+E.length);_.set(h,0),_.set(E,h.length);let S=It(n),x=It(s);if(o===-7){let R=await crypto.subtle.importKey("spki",x,{name:"ECDSA",namedCurve:"P-256"},!1,["verify"]),D=Sl(S);if(!await crypto.subtle.verify({name:"ECDSA",hash:"SHA-256"},R,D,_))throw new Error("WebAuthn signature verification failed")}else if(o===-257){let R=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"},R,S,_))throw new Error("WebAuthn signature verification failed")}else throw new Error(`Unsupported public key algorithm: ${o}`);return{signCount:w}}async function Rl(r,e){let t=new URL(r.url),n=new G(e.DB,e),s=new ne(e.DB),o=caches.default,i=r.headers.get("CF-Connecting-IP")||"127.0.0.1",c=r.headers.get("User-Agent");if(t.pathname==="/api/auth/prelogin"&&r.method==="POST"){if(await v.isRateLimited(o,`login_fail:${i}`,10,900))return new Response("Too many attempts",{status:429});let{username:a,turnstileToken:l}=await r.json(),u=new de(e.DB),[d,p]=await Promise.all([u.get("turnstile_secret_key"),u.get("turnstile_enabled_login")]);if(p==="true"&&d&&!await Qr(l,d,i))return new Response("Verification failed",{status:400});let f=await n.getByUsername(a);if(!f)return await n.isEmpty().catch(()=>!1)?new Response("no_users_registered",{status:404}):(await v.isRateLimited(o,`login_fail:${i}`,100,900),new Response("User not found",{status:404}));let m=await ks(e,f.id),h=As(m,e),g=!f.totp_skip_password,b=!!f.totp_enabled,w=f.password_version??1,E=await new oe(e.DB).listByUser(f.id),_=E.length>0,S=null,x=null;_&&(x=ur(),S={challenge:x,rpId:t.hostname,allowCredentials:E.map(k=>({id:k.credential_id,type:"public-key",transports:k.transports?JSON.parse(k.transports):void 0})),timeout:6e4,userVerification:"preferred"});let R=j(32),D=null;w===2&&f.hashed_password&&(D=Rs(f.hashed_password));let P=Number(e.PREAUTH_TTL_SECONDS)||300;return await v.set(o,`preauth_state:${m}`,{nonce:R,failedAttempts:0,passkeyChallenge:x,rpId:t.hostname},P),new Response(JSON.stringify({requires_password:g,requires_totp:b,has_passkey:_,passkey_options:S,password_version:w,nonce:R,serverSalt:D}),{headers:{"Set-Cookie":h,"Content-Type":"application/json"}})}if(t.pathname==="/api/auth/login"&&r.method==="POST"){if(r.headers.get("X-Password-Leaked")==="true"||r.headers.get("Exposed-Credential-Check")==="true")return new Response("password_leaked",{status:400});if(await v.isRateLimited(o,`login_fail:${i}`,10,900))return new Response("Too many login attempts",{status:429});let a=vs(r.headers.get("Cookie"));if(!a)return new Response("Pre-auth session missing or expired",{status:401});let l=await Ls(e,a);if(!l)return new Response("Session expired, please start over",{status:401});let u=await v.get(o,`preauth_state:${a}`);if(!u)return await vn(e,a),new Response("Session expired, please start over",{status:401});let{nonce:d}=u,p=await n.getById(l);if(!p)return new Response("User not found",{status:404});let{password:f,totpTokenHash:m,totpSalt:h,recoveryKey:g,passkeyAssertion:b,keepLoggedIn:w}=await r.json(),y=!1,E=new oe(e.DB),_=await E.listByUser(l),S=_.length>0,x=!!p.totp_enabled,R=!!p.totp_recovery_keys,D=x||S,P=S&&!!b;if(!(!!p.totp_skip_password||P)){if(!f)return new Response("Password is required",{status:400});if((p.password_version??1)===2){let H=await xs(p.hashed_password,d);if(f!==H){await v.isRateLimited(o,`login_fail:${i}`,100,900),await s.record(l,"login_fail",i,c,{reason:"wrong_password"});let U=await et(o,a,e);return U<=0?new Response("Invalid password",{status:400}):new Response(`Invalid password. ${U} attempt${U>1?"s":""} remaining.`,{status:400})}}else{if(!await bt(f,p.hashed_password,1)){await v.isRateLimited(o,`login_fail:${i}`,100,900),await s.record(l,"login_fail",i,c,{reason:"wrong_password"});let U=await et(o,a,e);return U<=0?new Response("Invalid password",{status:400}):new Response(`Invalid password. ${U} attempt${U>1?"s":""} remaining.`,{status:400})}y=!0}}let N=!1,V=!1,z=!1,ue=0,Ae;if(D)if(b&&u.passkeyChallenge){let H=b.id,U=_.find(W=>W.credential_id===H);if(!U){await s.record(l,"passkey_verify_fail",i,c,{reason:"credential_not_found"});let W=await et(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 Ut({clientDataJSON:b.response.clientDataJSON,authenticatorData:b.response.authenticatorData,signature:b.response.signature,publicKeySpki:U.public_key,algorithm:U.algorithm,expectedChallenge:u.passkeyChallenge,expectedOrigin:`${t.protocol}//${t.host}`,expectedRpId:u.rpId||t.hostname,previousSignCount:U.sign_count});await E.updateUsage(U.id,W),z=!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 et(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||R)&&g){let H=[];try{let Z=p.totp_recovery_keys;H=typeof Z=="string"?JSON.parse(Z||"[]"):Z||[],Array.isArray(H)||(H=[H])}catch{}if(await zr(g,H)===-1){await s.record(l,"totp_verify_fail",i,c,{method:"recovery_key"});let Z=await et(o,a,e);return Z<=0?new Response("Invalid recovery key",{status:400}):new Response(`Invalid recovery key. ${Z} attempt${Z>1?"s":""} remaining.`,{status:400})}let W=lr(),J=await Ye(W);await n.updateRecoveryKeys(l,[{hash:J}]),Ae=W,V=!0,ue=1}else if(x&&m){let H=await qn(p.totp_secret||"",m,h);if(!H.valid){await s.record(l,"totp_verify_fail",i,c);let U=await et(o,a,e);return U<=0?new Response("Invalid TOTP code",{status:400}):new Response(`Invalid TOTP code. ${U} attempt${U>1?"s":""} remaining.`,{status:400})}if(H.timeStep!==void 0){let U=`totp_used:${l}:${H.timeStep}`;if(await v.get(o,U))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 v.set(o,U,1,90)}N=!0}else{let H=await et(o,a,e);return H<=0?new Response("Missing MFA verification",{status:400}):new Response(`Missing MFA verification (Passkey, TOTP code, or recovery key). ${H} attempt${H>1?"s":""} remaining.`,{status:400})}await vn(e,a),await v.delete(o,`preauth_state:${a}`),await v.delete(o,`ratelimit:login_fail:${i}`);let{latitude:K,longitude:se}=Rr(r);if(K===null||se===null)return new Response("geolocation_missing",{status:400});let{session:we,refreshToken:L}=await Pr(e,l,i,c,K,se,!!w),T=await ee(we.id,l);z?await s.record(l,"passkey_verify_success",i,c,void 0,T):N?await s.record(l,"totp_verify_success",i,c,void 0,T):V&&await s.record(l,"recovery_key_used",i,c,{remaining:ue},T),await s.record(l,"login_success",i,c,void 0,T);let A=j(32),C=ct(A,e,!!w),I=await $e(e),M=await Ne(I),B=Number(e.ACCESS_TOKEN_EXPIRATION_MINUTES)||10,$=await Dr({userId:l,role:p.role,sessionId:we.id,exp:Math.floor(Date.now()/1e3)+B*60},M),F=new Headers({"Content-Type":"application/json"});return F.append("Set-Cookie",Et(L,e,!!w)),F.append("Set-Cookie",C),F.append("Set-Cookie",Ds()),new Response(JSON.stringify({success:!0,accessToken:$,needsMigration:y,rotatedRecoveryKey:Ae}),{headers:F})}return new Response("Not Found",{status:404})}pe();He();ge();async function xl(r,e){let t=caches.default,n=r.headers.get("CF-Connecting-IP")||"127.0.0.1",s=r.headers.get("User-Agent"),o=new ne(e.DB);if(await v.isRateLimited(t,`refresh_fail:${n}`,20,60))return new Response("Too many attempts",{status:429});let i=Le(r.headers.get("Cookie"));if(!i)return new Response("Refresh token missing",{status:401});let{getRequestCoordinates:c}=await Promise.resolve().then(()=>(pe(),Pn)),{latitude:a,longitude:l}=c(r),{session:u,user:d,newRefreshToken:p,reason:f}=await Cs(e,i,a,l);if(!u||!d||!p){if(d){let E=i?ve(i):null,_=E?await ee(E.sid,d.id):null;await o.record(d.id,"logout",n,s,{reason:f||"unknown"},_)}return await v.isRateLimited(t,`refresh_fail:${n}`,100,60),new Response(JSON.stringify({error:"Invalid refresh token",reason:f||"unknown"}),{status:401,headers:{"Set-Cookie":qe(),"Content-Type":"application/json"}})}let m=await $e(e),h=await Ne(m),g=Number(e.ACCESS_TOKEN_EXPIRATION_MINUTES)||10,b=await Dr({userId:d.id,role:d.role,sessionId:u.id,exp:Math.floor(Date.now()/1e3)+g*60},h),w=new Headers({"Content-Type":"application/json"}),y=u.id.startsWith("k_");return w.append("Set-Cookie",Et(p,e,y)),new Response(JSON.stringify({success:!0,accessToken:b}),{headers:w})}pe();Fe();Zn();async function Al(r,e){let t=r.headers.get("CF-Connecting-IP")||"127.0.0.1",n=r.headers.get("User-Agent"),s=new ne(e.DB),o=Le(r.headers.get("Cookie"));if(o){let c=ve(o);if(c){let l=await new ae(e.DB).getSessionUserId(c.sid);if(await St(e,c.sid),Xr(c.sid),l){let u=await ee(c.sid,l);await s.record(l,"logout",t,n,{reason:"user_active"},u)}}}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();He();Se();Fe();ge();Zn();async function Rp(r,e){try{if(await bt(r,e))return!0}catch{}try{let t=atob(e),n=new Uint8Array(t.length);for(let s=0;s<t.length;s++)n[s]=t.charCodeAt(s);if(n.length===48){let s=n.slice(0,16),o=n.slice(16),i=Array.from(s).map(u=>u.toString(16).padStart(2,"0")).join(""),c=new TextEncoder().encode(r+i),a=await crypto.subtle.digest("SHA-256",c),l=new Uint8Array(a);if(l.length===o.length){let u=0;for(let d=0;d<l.length;d++)u|=l[d]^o[d];if(u===0)return!0}}}catch{}return!1}async function Dl(r,e){let t=new URL(r.url),n=new G(e.DB,e),s=new ne(e.DB),o=caches.default,i=r.headers.get("CF-Connecting-IP")||"127.0.0.1",c=r.headers.get("User-Agent");if(t.pathname==="/api/auth/unlock-session"&&r.method==="GET"){let a=r.headers.get("Authorization")||"",l="";if(a.startsWith("Bearer ")&&(l=a.slice(7)),!l)return new Response("Unauthorized",{status:401});try{let u=await $e(e),d=await Ne(u),p=await vr(l,d);if(!p)return new Response("Unauthorized",{status:401});let f=await n.getById(p.userId),m=!!(f?.pin_hash&&!/^[a-f0-9]{64}$/.test(f.pin_hash)),h=j(32),g=`unlock_nonce:${p.sessionId}`;return await v.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"&&r.method==="POST"){let a=r.headers.get("Authorization")||"",l="";if(a.startsWith("Bearer ")&&(l=a.slice(7)),!l)return new Response("Unauthorized",{status:401});try{let u=await $e(e),d=await Ne(u),p=await vr(l,d);if(!p)return new Response("Unauthorized",{status:401});let{pinHash:f,nonce:m}=await r.json();if(!f)return new Response("Missing pinHash",{status:400});if(!m)return new Response("Missing nonce",{status:400});let h=new ae(e.DB),g=await h.getSession(p.sessionId);if(!g)return new Response("Session not found",{status:401});let b=await n.getById(p.userId);if(!b||!b.pin_hash)return new Response("PIN not configured",{status:400});let w=`unlock_nonce:${p.sessionId}`,y=await v.get(o,w);if(!y?.nonce)return new Response("Challenge expired, please start over",{status:400});let E=y.nonce,_=!!y.isLegacy;if(await v.delete(o,w),m!==E)return new Response("Invalid nonce",{status:400});let S=`unlock_fail:${g.id}`,R=(await v.get(o,S))?.count||0,D=await ee(g.id,p.userId),P=!1;if(_)P=await Rp(f,b.pin_hash),P&&await n.updatePinHash(p.userId,f);else{let N=await Pa(b.pin_hash,E);if(f.length===N.length){let V=0;for(let z=0;z<f.length;z++)V|=f.charCodeAt(z)^N.charCodeAt(z);P=V===0}}if(!P){let N=R+1;return N>=3?(await h.deleteSession(g.id),await v.delete(o,S),await s.record(p.userId,"pin_verify_fail",i,c,{reason:"too_many_attempts"},D),new Response(JSON.stringify({success:!1,error:"too_many_attempts"}),{status:401,headers:{"Content-Type":"application/json"}})):(await v.set(o,S,{count:N},900),await s.record(p.userId,"pin_verify_fail",i,c,{reason:"incorrect_pin",attempt:N},D),new Response(JSON.stringify({success:!1,error:"incorrect_pin",attemptsRemaining:3-N}),{status:400,headers:{"Content-Type":"application/json"}}))}let k=Math.floor(Date.now()/1e3);return await h.resumeSession(g.id,k),Xr(g.id),await v.delete(o,S),await s.record(p.userId,"pin_verify_success",i,c,void 0,D),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}catch(u){return console.error("Unlock session error:",u),new Response("Unauthorized",{status:401})}}if(t.pathname==="/api/auth/lock-session"&&r.method==="POST"){let a=r.headers.get("Authorization")||"",l="";if(a.startsWith("Bearer ")&&(l=a.slice(7)),!l)return new Response("Unauthorized",{status:401});try{let u=await $e(e),d=await Ne(u),p=await vr(l,d);if(!p)return new Response("Unauthorized",{status:401});let f=new ae(e.DB),m=await f.getSession(p.sessionId);return m?(await f.pauseSession(m.id),Xr(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})}Fe();ge();Se();async function vl(r,e){let t=new URL(r.url),n=t.pathname,s=new G(e.DB,e),o=new ne(e.DB),i=caches.default,c=r.headers.get("CF-Connecting-IP")||"127.0.0.1",a=r.headers.get("User-Agent");if(n==="/api/auth/forgot-password/init"&&r.method==="POST"){if(await v.isRateLimited(i,`forgot_pw_ip:${c}`,10,600))return new Response("Too many attempts",{status:429});let{username:l,turnstileToken:u}=await r.json();if(!l)return new Response("Username is required",{status:400});let d=new de(e.DB),[p,f]=await Promise.all([d.get("turnstile_secret_key"),d.get("turnstile_enabled_login")]);if(f==="true"&&p&&!await Qr(u,p,c))return new Response("Verification failed",{status:400});let m=await s.getByUsername(l);if(!m)return await v.isRateLimited(i,`forgot_pw_ip:${c}`,100,600),new Response("User not found",{status:404});let g=await new oe(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 D=typeof E=="string"?JSON.parse(E):E;y=Array.isArray(D)&&D.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&&(_=ur(),S={challenge:_,rpId:t.hostname,allowCredentials:g.map(D=>({id:D.credential_id,type:"public-key",transports:D.transports?JSON.parse(D.transports):void 0})),timeout:6e4,userVerification:"preferred"});let x=j(32),R={userId:m.id,username:m.username,passkeyChallenge:_,rpId:t.hostname,failedAttempts:0};return await v.set(i,`forgot_pw_state:${x}`,R,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(n==="/api/auth/forgot-password/verify"&&r.method==="POST"){let{recoveryToken:l,passkeyAssertion:u,totpTokenHash:d,totpSalt:p,recoveryKey:f}=await r.json();if(!l)return new Response("Recovery token is required",{status:400});let m=`forgot_pw_state:${l}`,h=await v.get(i,m);if(!h)return new Response("Recovery session expired or invalid",{status:400});if(h.failedAttempts>=3)return await v.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 v.delete(i,m),new Response("User not found",{status:404});if(u&&h.passkeyChallenge){let y=new oe(e.DB),_=(await y.listByUser(g.id)).find(S=>S.credential_id===u.id);if(!_)return h.failedAttempts++,await v.set(i,m,h,300),new Response("Passkey not recognized",{status:400});try{let{signCount:S}=await Ut({clientDataJSON:u.response.clientDataJSON,authenticatorData:u.response.authenticatorData,signature:u.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 v.set(i,m,h,300),new Response("Passkey verification failed",{status:400})}}else if(f){let y=[];try{let _=g.totp_recovery_keys;y=typeof _=="string"?JSON.parse(_||"[]"):_||[],Array.isArray(y)||(y=[y])}catch{}let E=await zr(f,y);if(E===-1)return h.failedAttempts++,await v.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(d&&g.totp_secret){let y=await qn(g.totp_secret,d,p);if(!y.valid)return h.failedAttempts++,await v.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 v.get(i,E))return h.failedAttempts++,await v.set(i,m,h,300),new Response("TOTP code already used, please wait for next code",{status:400});await v.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 v.delete(i,m);let b=j(32),w={userId:g.id,username:g.username};return await v.set(i,`forgot_pw_reset:${b}`,w,300),new Response(JSON.stringify({success:!0,resetToken:b}),{headers:{"Content-Type":"application/json"}})}if(n==="/api/auth/forgot-password/reset"&&r.method==="POST"){let{resetToken:l,newPassword:u}=await r.json();if(!l||!u)return new Response("Reset token and new password are required",{status:400});if(!Rt.test(u))return new Response("Password format error",{status:400});let d=`forgot_pw_reset:${l}`,p=await v.get(i,d);if(!p)return new Response("Reset token expired or invalid",{status:400});await v.delete(i,d);let f=await s.getById(p.userId);if(!f)return new Response("User not found",{status:404});let m=await at(u,2);return await s.updatePassword(f.id,m,2),await new ae(e.DB).deleteAllByUserId(f.id),await o.record(f.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 Pl(r,e){try{let n=new URL(r.url).pathname;return n==="/api/auth/config"||n==="/api/auth/check-username"?await wl(r,e):n==="/api/auth/signup"?await _l(r,e):n==="/api/auth/prelogin"||n==="/api/auth/login"?await Rl(r,e):n==="/api/auth/refresh"?await xl(r,e):n==="/api/auth/logout"?await Al(r,e):n.startsWith("/api/auth/forgot-password")?await vl(r,e):n==="/api/auth/unlock-session"||n==="/api/auth/lock-session"?await Dl(r,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 Zr=class{static isAdmin(e){return e.role==="admin"}static canAccessProfile(e,t){return t.owner_id===e.id}};pe();async function Cl(r,e,t,n){let s=new q(e.DB);if(r.method==="GET"){let o=await s.listByOwner(t.id);return new Response(JSON.stringify(o),{headers:{"Content-Type":"application/json"}})}if(r.method==="POST"){let o=await r.json();if(!o.name||!yi.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),u=e.MAX_LOG_RETENTION_DAYS!==void 0&&e.MAX_LOG_RETENTION_DAYS!==""?Number(e.MAX_LOG_RETENTION_DAYS):30,d=e.DEFAULT_LOG_RETENTION_DAYS!==void 0&&e.DEFAULT_LOG_RETENTION_DAYS!==""?Math.min(Number(e.DEFAULT_LOG_RETENTION_DAYS),u):Math.min(7,u),p=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),u):Math.min(7,u),f=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),p):Math.min(1,p),m=t?.role==="admin"?d:f,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 kl(r,e,t,n,s,o){let i=new q(e.DB),c=new Ie(e.DB),a=n.id;if(s.length===3){if(r.method==="DELETE")return await i.delete(a),new Response(null,{status:204});if(r.method==="PATCH"){let{name:l}=await r.json();return!l||!yi.test(l)?new Response("Invalid Profile Name format",{status:400}):(await i.updateName(a,l),o.waitUntil(ce.clearCache(a,!0,e)),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}}))}return r.method==="GET"?new Response(JSON.stringify(n),{headers:{"Content-Type":"application/json"}}):new Response("Method Not Allowed",{status:405})}if(s[3]==="rotate_key"&&r.method==="POST"){let l=j(12);return await i.rotateKey(a,l),o.waitUntil(ce.clearCache(a,!1,e)),new Response(JSON.stringify({profile_key:l}),{headers:{"Content-Type":"application/json"}})}if(s[3]==="settings"&&r.method==="PATCH"){let l=await r.json(),u=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),u):u,p=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),u):Math.min(7,u),f=t?.role==="admin"?d:p;if(l.log_retention_days!=null&&(l.log_retention_days=Math.min(Number(l.log_retention_days),f)),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://"),R=b.startsWith("sdns://"),D=!b.includes("//")&&!b.startsWith("/");if(!w&&!y&&!E&&!_&&!S&&!x&&!R&&!D)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 P=D?`tcp://${b}`:b;if(!lt(P))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(ce.clearCache(a,!1,e)),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}if(s[3]==="test"&&r.method==="POST"){let{domain:l,type:u}=await r.json(),d=Kt(l,u),p=await ce.process(r,{name:l,type:u,raw:d},{profileId:a,startTime:Date.now(),env:e,ctx:o});return new Response(JSON.stringify({action:p.action,reason:p.reason,answers:p.answer.length>0?ke(p.answer):[],diagnostics:p.diagnostics,latency:p.latency,timings:p.timings,client_ip:r.headers.get("CF-Connecting-IP")||"127.0.0.1",geo_country:await Gt(r,r.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 Co=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 n=Math.floor(Date.now()/1e3),s=j(12),o=5;for(let i=0;i<o;i++){let c=Wt(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,n,n).run(),{id:s,profile_id:e,name:t,token:c,created_at:n,updated_at:n}}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,n){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(n,s,e,t).run()).success}async rotateAccessPointToken(e,t){let n=Math.floor(Date.now()/1e3),s=5;for(let o=0;o<s;o++){let i=Wt(5);try{if(!(await this.db.prepare("UPDATE access_points SET token = ?, updated_at = ? WHERE id = ? AND profile_id = ?").bind(i,n,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 Ll(r,e,t,n,s,o){let i=new Co(e.DB);if(r.method==="GET"){let c=await i.getAccessPoints(n);return new Response(JSON.stringify(c),{headers:{"Content-Type":"application/json"}})}if(r.method==="POST"){if(s.length===6&&s[5]==="rotate_token"){let d=s[4],p=await i.rotateAccessPointToken(d,n);return new Response(JSON.stringify({token:p}),{headers:{"Content-Type":"application/json"}})}let c=await r.json();if(!c.name)return new Response("Name is required",{status:400});if(!hi.test(c.name))return new Response("Invalid Access Point name format",{status:400});let a=await i.getAccessPoints(n);if(a.some(d=>d.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 u=await i.addAccessPoint(n,c.name);return new Response(JSON.stringify(u),{status:201,headers:{"Content-Type":"application/json"}})}if(r.method==="PATCH"&&s.length===5){let c=s[4],a=await r.json();return a.name?hi.test(a.name)?(await i.getAccessPoints(n)).some(u=>u.id!==c&&u.name.toLowerCase()===a.name.toLowerCase())?new Response("Access Point name already exists",{status:400}):(await i.updateAccessPointName(c,n,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(r.method==="DELETE"&&s.length===5){let c=s[4];return await i.deleteAccessPoint(c,n),new Response(null,{status:204})}return new Response("Method Not Allowed",{status:405})}async function Ol(r,e,t,n,s,o){let i=new Cr(e.DB);if(r.method==="GET"){let c=await i.getRules(n);return new Response(JSON.stringify(c),{headers:{"Content-Type":"application/json"}})}if(r.method==="POST"){let c=await r.json();if(Array.isArray(c)||c&&Array.isArray(c.rules)){let p=Array.isArray(c)?c:c.rules,f=new Set,m=[];for(let y of p){if(!y||typeof y.pattern!="string")continue;let E=y.pattern.trim().toLowerCase();if(!E||f.has(E))continue;f.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(n),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(n,b),o.waitUntil(ce.clearCache(n,!1,e))),new Response(JSON.stringify({success:!0,count:w}),{status:201,headers:{"Content-Type":"application/json"}})}let l=c,u=l.pattern?l.pattern.trim():"";return u?await i.getRuleByPattern(n,u)?new Response("Rule for this domain already exists",{status:400}):(await i.addRule(n,l),o.waitUntil(ce.clearCache(n,!1,e)),new Response(null,{status:201})):new Response("Domain pattern cannot be empty",{status:400})}if(r.method==="PUT"){let c=await r.json(),a=c.pattern?c.pattern.trim():"";return a?await i.getRuleByPatternExcludeId(n,a,c.id)?new Response("Rule for this domain already exists",{status:400}):(await i.updateRule(c.id,n,c),o.waitUntil(ce.clearCache(n,!1,e)),new Response(null,{status:200})):new Response("Domain pattern cannot be empty",{status:400})}if(r.method==="DELETE"){let{id:c}=await r.json();return await i.deleteRule(c,n),o.waitUntil(ce.clearCache(n,!1,e)),new Response(null,{status:204})}return new Response("Method Not Allowed",{status:405})}var Mt=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 n=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<n.length;o+=100){let i=n.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,n){return(await this.db.prepare("UPDATE lists SET enabled = ? WHERE id = ? AND profile_id = ?").bind(n?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,n,s=null){return n!=null?(await this.db.prepare("UPDATE lists SET last_synced_at = ?, enabled = ?, sync_error = ? WHERE id = ?").bind(t,n,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 Bt=class{constructor(e){this.db=e}db;async upsertListBloom(e,t,n){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,n)),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 n=t.reduce((i,c)=>{let a=c.bloom_filter_chunk.byteLength??c.bloom_filter_chunk.length;return i+a},0),s=new Uint8Array(n),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(`
|
|
416
|
+
`}Zn();async function yl(r,e){let t=new URL(r.url),n=new G(e.DB,e);if(t.pathname==="/api/auth/config"&&r.method==="GET"){let s=new de(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"),n.isEmpty().then(u=>!u).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"&&r.method==="GET"){let s=t.searchParams.get("username")||"";if(!xt.test(s))return new Response(JSON.stringify({error:"Invalid username"}),{status:400,headers:{"Content-Type":"application/json"}});let o=await n.getByUsername(s);return new Response(JSON.stringify({exists:!!o}),{headers:{"Content-Type":"application/json"}})}return new Response("Not Found",{status:404})}pe();$e();Se();var ne=class{constructor(e){this.db=e}db;async record(e,t,n,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,n,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,n){let s=Math.min(t,50);if(n){let{results:i}=await this.db.prepare("SELECT * FROM user_activity_log WHERE user_id = ? AND timestamp < ? ORDER BY timestamp DESC LIMIT ?").bind(e,n,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 na="ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";function wp(r){let e="",t=0,n=0;for(let s of r)for(t=t<<8|s,n+=8;n>=5;)n-=5,e+=na[t>>n&31];return n>0&&(e+=na[t<<5-n&31]),e}function bp(r){let e=r.length;for(;e>0&&r[e-1]==="=";)e--;let t=r.slice(0,e).toUpperCase(),n=[],s=0,o=0;for(let i of t){let c=na.indexOf(i);c!==-1&&(s=s<<5|c,o+=5,o>=8&&(o-=8,n.push(s>>o&255)))}return new Uint8Array(n)}function wl(){let r=new Uint8Array(20);return crypto.getRandomValues(r),wp(r)}async function Ep(r,e){let t=bp(r),n=new Uint8Array(8),s=new DataView(n.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,n),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 qn(r,e,t){if(!r||!e)return{valid:!1};if(!t&&!Ia.test(e))return{valid:!1};try{let n=Math.floor(Date.now()/1e3/30);for(let s of[-1,0,1]){let o=n+s,i=await Ep(r,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(u=>u.toString(16).padStart(2,"0")).join("")===e)return{valid:!0,timeStep:o}}else if(i===e)return{valid:!0,timeStep:o}}}catch(n){return console.error("[TOTP Verification Error]:",n),{valid:!1}}return{valid:!1}}async function es(r,e,t){return(await qn(r,e,t)).valid}function bl(r,e,t){let n=encodeURIComponent(`${t}:${e}`),s=new URLSearchParams({secret:r,issuer:t,algorithm:"SHA1",digits:"6",period:"30"});return`otpauth://totp/${n}?${s.toString()}`}function _p(){for(;;){let r=new Uint32Array(1);crypto.getRandomValues(r);let e=r[0]%1e5,t=e%11;if(t<10){let n=e.toString().padStart(5,"0"),s=t.toString();return`${n}${s}`}}}function lr(){let r=[];for(let e=0;e<5;e++)r.push(_p());return r.join("-")}function vo(){return[lr()]}async function Xe(r){let e=r.replace(/[-\s]/g,"").toUpperCase().trim(),t=new TextEncoder().encode(e),n=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(n)).map(s=>s.toString(16).padStart(2,"0")).join("")}async function zr(r,e){let t=await Xe(r),n=r.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()===n;if(typeof s=="object"){if(s.hash&&s.hash===t)return!0;if(s.key)return String(s.key).replace(/[-\s]/g,"").toUpperCase().trim()===n}return!1})}ge();async function Qr(r,e,t){if(!r||!e)return!1;try{let n=new URLSearchParams;return n.append("secret",e),n.append("response",r),n.append("remoteip",t),!!(await(await fetch("https://challenges.cloudflare.com/turnstile/v0/siteverify",{method:"POST",body:n,headers:{"Content-Type":"application/x-www-form-urlencoded"},signal:AbortSignal.timeout(5e3)})).json()).success}catch{return!1}}async function El(r,e){let t=new G(e.DB,e),n=new ne(e.DB),s=typeof caches<"u"?caches.default:null,o=r.headers.get("CF-Connecting-IP")||"127.0.0.1",i=r.headers.get("User-Agent");if(r.headers.get("X-Password-Leaked")==="true"||r.headers.get("Exposed-Credential-Check")==="true")return new Response("password_leaked",{status:400});if(await v.isRateLimited(s,`signup:${o}`,10,60))return new Response("Too many attempts",{status:429});let{username:c,password:a,turnstileToken:l}=await r.json(),u=new de(e.DB),[d,p,f,m]=await Promise.all([u.get("turnstile_secret_key"),u.get("turnstile_enabled_signup"),u.get("registration_enabled"),t.isEmpty()]);if(!m&&f==="false")return new Response("registration_disabled",{status:403});if(p==="true"&&d&&!await Qr(l,d,o))return new Response("Verification failed",{status:400});if(!xt.test(c))return new Response("Invalid username",{status:400});if(!a||!Rt.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}=Tr(r);if(h===null||g===null)return new Response("geolocation_missing",{status:400});let w=Ar(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 Ie(e.JWT_SECRET)}catch{return new Response("jwt_secret_invalid",{status:400})}let y=await ct(a,2),E=j(15),S=r.cf?.timezone||r.headers.get("CF-Timezone")||null,x=m?"admin":"user",R=!1;try{await t.create({id:E,username:c,passwordHash:y,role:x,timezone:S,passwordVersion:2}),R=!0;let D=new q(e.DB),P=j(6),k=x==="admin"?7:1;await D.create({id:P,owner_id:E,name:"Default",settings:{upstream:["https://security.cloudflare-dns.com/dns-query"],ecs:{enabled:!0,use_client_ip:!0},log_retention_days:k,skip_log_on_pass:!1,default_policy:"ALLOW",best_effort_ech:{enabled:!1,fronting_domain:"cloudflare-ech.com"}}});let N=lr(),V=await Xe(N);await t.updateRecoveryKeys(E,[{hash:V}]);let{session:z,refreshToken:ue}=await Pr(e,E,o,i,h,g,!1),Ae=await ee(z.id,E);await n.record(E,"signup",o,i,void 0,Ae);let K=Et(ue,e,!1),se=j(32),we=lt(se,e,!1),L=Number(e.ACCESS_TOKEN_EXPIRATION_MINUTES)||10,T=await Dr({userId:E,role:x,sessionId:z.id,exp:Math.floor(Date.now()/1e3)+L*60},b),A=new Headers;return A.append("Set-Cookie",K),A.append("Set-Cookie",we),A.append("Content-Type","application/json"),new Response(JSON.stringify({success:!0,accessToken:T,recoveryKey:N}),{headers:A})}catch(D){if(R)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(P){console.error("Failed to clean up incomplete user registration:",P)}return new Response(D.message,{status:400})}}pe();$e();Se();pe();var oe=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 n=await this.db.prepare("SELECT * FROM passkeys WHERE (id = ? OR credential_id = ?) AND user_id = ?").bind(e,e,t).first();if(n)return n;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),n=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)
|
|
417
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).bind(t,e.userId,e.name,e.credentialId,e.publicKey,e.algorithm,e.signCount,s,e.aaguid||null,n,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:n,last_used_at:null}}async updateName(e,t,n){return(await this.db.prepare("UPDATE passkeys SET name = ? WHERE id = ? AND user_id = ?").bind(n,e,t).run()).success}async updateUsage(e,t){let n=Math.floor(Date.now()/1e3);return(await this.db.prepare("UPDATE passkeys SET sign_count = ?, last_used_at = ? WHERE id = ?").bind(t,n,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 gt(r){let e=r instanceof Uint8Array?r:new Uint8Array(r),t="";for(let n=0;n<e.length;n++)t+=String.fromCharCode(e[n]);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function It(r){let e=r.replace(/-/g,"+").replace(/_/g,"/");for(;e.length%4!==0;)e+="=";let t=atob(e),n=new Uint8Array(t.length);for(let s=0;s<t.length;s++)n[s]=t.charCodeAt(s);return n}function ur(){let r=new Uint8Array(32);return crypto.getRandomValues(r),gt(r)}function _l(r){if(r[0]!==48){if(r.length===64)return r;throw new Error("Invalid ECDSA signature: expected ASN.1 SEQUENCE")}let e=2;if(r[1]&128&&(e=2+(r[1]&127)),r[e++]!==2)throw new Error("Expected INTEGER for r in signature");let t=r[e++],n=r.subarray(e,e+t);if(e+=t,r[e++]!==2)throw new Error("Expected INTEGER for s in signature");let s=r[e++],o=r.subarray(e,e+s);for(;n.length>32&&n[0]===0;)n=n.subarray(1);for(;o.length>32&&o[0]===0;)o=o.subarray(1);let i=new Uint8Array(64);return i.set(n,32-n.length),i.set(o,64-o.length),i}function sa(r){let e=0;function t(o){if(o<24)return o;if(o===24)return r[e++];if(o===25){let i=r[e]<<8|r[e+1];return e+=2,i}if(o===26){let i=(r[e]<<24>>>0)+(r[e+1]<<16)+(r[e+2]<<8)+r[e+3];return e+=4,i}if(o===27){let i=BigInt((r[e]<<24>>>0)+(r[e+1]<<16)+(r[e+2]<<8)+r[e+3]),c=BigInt((r[e+4]<<24>>>0)+(r[e+5]<<16)+(r[e+6]<<8)+r[e+7]);return e+=8,i<<32n|c}throw new Error(`Unsupported CBOR uint info: ${o}`)}function n(){if(e>=r.length)throw new Error("Unexpected end of CBOR data");let o=r[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=r.subarray(e,e+a);return e+=a,l}case 3:{let a=Number(t(c)),l=r.subarray(e,e+a);return e+=a,new TextDecoder().decode(l)}case 4:{let a=Number(t(c)),l=[];for(let u=0;u<a;u++)l.push(n());return l}case 5:{let a=Number(t(c)),l={};for(let u=0;u<a;u++){let d=n(),p=n();l[d]=p}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:n(),bytesRead:e}}async function Sp(r){if(r.length<37)throw new Error("Invalid authenticatorData length");let e=r.subarray(0,32),t=r[32],n=(r[33]<<24>>>0)+(r[34]<<16)+(r[35]<<8)+r[36];if(!!!(t&64))throw new Error("Attestation does not contain attested credential data");let o=37,i=r.subarray(o,o+16);o+=16;let c=Array.from(i).map(h=>h.toString(16).padStart(2,"0")).join(""),a=r[o]<<8|r[o+1];o+=2;let l=r.subarray(o,o+a);o+=a;let u=gt(l),d=r.subarray(o),{value:p}=sa(d),f=p[3]??-7,m="";if(f===-7){let h=p[-2],g=p[-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=gt(y)}else if(f===-257){let h=p[-1],g=p[-2];if(!h||!g)throw new Error("Invalid RSA COSE public key components");let w={kty:"RSA",n:gt(h),e:gt(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=gt(y)}else throw new Error(`Unsupported COSE algorithm: ${f}`);return{rpIdHash:e,flags:t,signCount:n,aaguid:c,credentialId:u,publicKeySpki:m,algorithm:f}}async function Sl(r){let{clientDataJSON:e,attestationObject:t,expectedChallenge:n,expectedOrigin:s,expectedRpId:o}=r,i=It(e),c=JSON.parse(new TextDecoder().decode(i));if(c.type!=="webauthn.create")throw new Error(`Invalid clientData type: ${c.type}`);if(c.challenge!==n)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 d=It(t),{value:p}=sa(d);if(!p.authData)throw new Error("Missing authData in attestationObject");let f=await Sp(p.authData),m=new Uint8Array(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(o)));for(let h=0;h<32;h++)if(f.rpIdHash[h]!==m[h])throw new Error("WebAuthn rpIdHash mismatch");if(!(f.flags&1))throw new Error("User Presence (UP) flag not set");return f}async function Ut(r){let{clientDataJSON:e,authenticatorData:t,signature:n,publicKeySpki:s,algorithm:o,expectedChallenge:i,expectedOrigin:c,expectedRpId:a,previousSignCount:l=0}=r,u=It(e),d=JSON.parse(new TextDecoder().decode(u));if(d.type!=="webauthn.get")throw new Error(`Invalid clientData type: ${d.type}`);if(d.challenge!==i)throw new Error("WebAuthn challenge mismatch");let p=new URL(d.origin),f=c.includes("://")?new URL(c):new URL(`https://${c}`);if(p.origin.toLowerCase()!==f.origin.toLowerCase())throw new Error(`WebAuthn origin mismatch: expected ${f.origin}, received ${p.origin}`);if(!(p.hostname==="localhost"||p.hostname==="127.0.0.1")&&p.protocol!=="https:")throw new Error(`WebAuthn requires HTTPS origin, received: ${p.protocol}`);let h=It(t);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 R=0;R<32;R++)if(g[R]!==y[R])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",u)),_=new Uint8Array(h.length+E.length);_.set(h,0),_.set(E,h.length);let S=It(n),x=It(s);if(o===-7){let R=await crypto.subtle.importKey("spki",x,{name:"ECDSA",namedCurve:"P-256"},!1,["verify"]),D=_l(S);if(!await crypto.subtle.verify({name:"ECDSA",hash:"SHA-256"},R,D,_))throw new Error("WebAuthn signature verification failed")}else if(o===-257){let R=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"},R,S,_))throw new Error("WebAuthn signature verification failed")}else throw new Error(`Unsupported public key algorithm: ${o}`);return{signCount:b}}async function Tl(r,e){let t=new URL(r.url),n=new G(e.DB,e),s=new ne(e.DB),o=caches.default,i=r.headers.get("CF-Connecting-IP")||"127.0.0.1",c=r.headers.get("User-Agent");if(t.pathname==="/api/auth/prelogin"&&r.method==="POST"){if(await v.isRateLimited(o,`login_fail:${i}`,10,900))return new Response("Too many attempts",{status:429});let{username:a,turnstileToken:l}=await r.json(),u=new de(e.DB),[d,p]=await Promise.all([u.get("turnstile_secret_key"),u.get("turnstile_enabled_login")]);if(p==="true"&&d&&!await Qr(l,d,i))return new Response("Verification failed",{status:400});let f=await n.getByUsername(a);if(!f)return await n.isEmpty().catch(()=>!1)?new Response("no_users_registered",{status:404}):(await v.isRateLimited(o,`login_fail:${i}`,100,900),new Response("User not found",{status:404}));let m=await ks(e,f.id),h=As(m,e),g=!f.totp_skip_password,w=!!f.totp_enabled,b=f.password_version??1,E=await new oe(e.DB).listByUser(f.id),_=E.length>0,S=null,x=null;_&&(x=ur(),S={challenge:x,rpId:t.hostname,allowCredentials:E.map(k=>({id:k.credential_id,type:"public-key",transports:k.transports?JSON.parse(k.transports):void 0})),timeout:6e4,userVerification:"preferred"});let R=j(32),D=null;b===2&&f.hashed_password&&(D=Rs(f.hashed_password));let P=Number(e.PREAUTH_TTL_SECONDS)||300;return await v.set(o,`preauth_state:${m}`,{nonce:R,failedAttempts:0,passkeyChallenge:x,rpId:t.hostname},P),new Response(JSON.stringify({requires_password:g,requires_totp:w,has_passkey:_,passkey_options:S,password_version:b,nonce:R,serverSalt:D}),{headers:{"Set-Cookie":h,"Content-Type":"application/json"}})}if(t.pathname==="/api/auth/login"&&r.method==="POST"){if(r.headers.get("X-Password-Leaked")==="true"||r.headers.get("Exposed-Credential-Check")==="true")return new Response("password_leaked",{status:400});if(await v.isRateLimited(o,`login_fail:${i}`,10,900))return new Response("Too many login attempts",{status:429});let a=vs(r.headers.get("Cookie"));if(!a)return new Response("Pre-auth session missing or expired",{status:401});let l=await Ls(e,a);if(!l)return new Response("Session expired, please start over",{status:401});let u=await v.get(o,`preauth_state:${a}`);if(!u)return await vn(e,a),new Response("Session expired, please start over",{status:401});let{nonce:d}=u,p=await n.getById(l);if(!p)return new Response("User not found",{status:404});let{password:f,totpTokenHash:m,totpSalt:h,recoveryKey:g,passkeyAssertion:w,keepLoggedIn:b}=await r.json(),y=!1,E=new oe(e.DB),_=await E.listByUser(l),S=_.length>0,x=!!p.totp_enabled,R=!!p.totp_recovery_keys,D=x||S,P=S&&!!w;if(!(!!p.totp_skip_password||P)){if(!f)return new Response("Password is required",{status:400});if((p.password_version??1)===2){let H=await xs(p.hashed_password,d);if(f!==H){await v.isRateLimited(o,`login_fail:${i}`,100,900),await s.record(l,"login_fail",i,c,{reason:"wrong_password"});let U=await tt(o,a,e);return U<=0?new Response("Invalid password",{status:400}):new Response(`Invalid password. ${U} attempt${U>1?"s":""} remaining.`,{status:400})}}else{if(!await Rr(f,p.hashed_password,1)){await v.isRateLimited(o,`login_fail:${i}`,100,900),await s.record(l,"login_fail",i,c,{reason:"wrong_password"});let U=await tt(o,a,e);return U<=0?new Response("Invalid password",{status:400}):new Response(`Invalid password. ${U} attempt${U>1?"s":""} remaining.`,{status:400})}y=!0}}let N=!1,V=!1,z=!1,ue=0,Ae;if(D)if(w&&u.passkeyChallenge){let H=w.id,U=_.find(W=>W.credential_id===H);if(!U){await s.record(l,"passkey_verify_fail",i,c,{reason:"credential_not_found"});let W=await tt(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 Ut({clientDataJSON:w.response.clientDataJSON,authenticatorData:w.response.authenticatorData,signature:w.response.signature,publicKeySpki:U.public_key,algorithm:U.algorithm,expectedChallenge:u.passkeyChallenge,expectedOrigin:`${t.protocol}//${t.host}`,expectedRpId:u.rpId||t.hostname,previousSignCount:U.sign_count});await E.updateUsage(U.id,W),z=!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 tt(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||R)&&g){let H=[];try{let Z=p.totp_recovery_keys;H=typeof Z=="string"?JSON.parse(Z||"[]"):Z||[],Array.isArray(H)||(H=[H])}catch{}if(await zr(g,H)===-1){await s.record(l,"totp_verify_fail",i,c,{method:"recovery_key"});let Z=await tt(o,a,e);return Z<=0?new Response("Invalid recovery key",{status:400}):new Response(`Invalid recovery key. ${Z} attempt${Z>1?"s":""} remaining.`,{status:400})}let W=lr(),J=await Xe(W);await n.updateRecoveryKeys(l,[{hash:J}]),Ae=W,V=!0,ue=1}else if(x&&m){let H=await qn(p.totp_secret||"",m,h);if(!H.valid){await s.record(l,"totp_verify_fail",i,c);let U=await tt(o,a,e);return U<=0?new Response("Invalid TOTP code",{status:400}):new Response(`Invalid TOTP code. ${U} attempt${U>1?"s":""} remaining.`,{status:400})}if(H.timeStep!==void 0){let U=`totp_used:${l}:${H.timeStep}`;if(await v.get(o,U))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 v.set(o,U,1,90)}N=!0}else{let H=await tt(o,a,e);return H<=0?new Response("Missing MFA verification",{status:400}):new Response(`Missing MFA verification (Passkey, TOTP code, or recovery key). ${H} attempt${H>1?"s":""} remaining.`,{status:400})}await vn(e,a),await v.delete(o,`preauth_state:${a}`),await v.delete(o,`ratelimit:login_fail:${i}`);let{latitude:K,longitude:se}=Tr(r);if(K===null||se===null)return new Response("geolocation_missing",{status:400});let{session:we,refreshToken:L}=await Pr(e,l,i,c,K,se,!!b),T=await ee(we.id,l);z?await s.record(l,"passkey_verify_success",i,c,void 0,T):N?await s.record(l,"totp_verify_success",i,c,void 0,T):V&&await s.record(l,"recovery_key_used",i,c,{remaining:ue},T),await s.record(l,"login_success",i,c,void 0,T);let A=j(32),C=lt(A,e,!!b),I=await Ke(e),M=await Ie(I),B=Number(e.ACCESS_TOKEN_EXPIRATION_MINUTES)||10,$=await Dr({userId:l,role:p.role,sessionId:we.id,exp:Math.floor(Date.now()/1e3)+B*60},M),F=new Headers({"Content-Type":"application/json"});return F.append("Set-Cookie",Et(L,e,!!b)),F.append("Set-Cookie",C),F.append("Set-Cookie",Ds()),new Response(JSON.stringify({success:!0,accessToken:$,needsMigration:y,rotatedRecoveryKey:Ae}),{headers:F})}return new Response("Not Found",{status:404})}pe();$e();ge();async function Rl(r,e){let t=caches.default,n=r.headers.get("CF-Connecting-IP")||"127.0.0.1",s=r.headers.get("User-Agent"),o=new ne(e.DB);if(await v.isRateLimited(t,`refresh_fail:${n}`,20,60))return new Response("Too many attempts",{status:429});let i=Oe(r.headers.get("Cookie"));if(!i)return new Response("Refresh token missing",{status:401});let{getRequestCoordinates:c}=await Promise.resolve().then(()=>(pe(),Pn)),{latitude:a,longitude:l}=c(r),{session:u,user:d,newRefreshToken:p,reason:f}=await Cs(e,i,a,l);if(!u||!d||!p){if(d){let E=i?ve(i):null,_=E?await ee(E.sid,d.id):null;await o.record(d.id,"logout",n,s,{reason:f||"unknown"},_)}return await v.isRateLimited(t,`refresh_fail:${n}`,100,60),new Response(JSON.stringify({error:"Invalid refresh token",reason:f||"unknown"}),{status:401,headers:{"Set-Cookie":et(),"Content-Type":"application/json"}})}let m=await Ke(e),h=await Ie(m),g=Number(e.ACCESS_TOKEN_EXPIRATION_MINUTES)||10,w=await Dr({userId:d.id,role:d.role,sessionId:u.id,exp:Math.floor(Date.now()/1e3)+g*60},h),b=new Headers({"Content-Type":"application/json"}),y=u.id.startsWith("k_");return b.append("Set-Cookie",Et(p,e,y)),new Response(JSON.stringify({success:!0,accessToken:w,user:{id:d.id,username:d.username,role:d.role}}),{headers:b})}pe();He();Zn();async function xl(r,e){let t=r.headers.get("CF-Connecting-IP")||"127.0.0.1",n=r.headers.get("User-Agent"),s=new ne(e.DB),o=Oe(r.headers.get("Cookie"));if(o){let c=ve(o);if(c){let l=await new ae(e.DB).getSessionUserId(c.sid);if(await St(e,c.sid),Xr(c.sid),l){let u=await ee(c.sid,l);await s.record(l,"logout",t,n,{reason:"user_active"},u)}}}let i=new Headers({"Content-Type":"application/json"});return i.append("Set-Cookie",et()),i.append("Set-Cookie","csrf_token=; SameSite=Lax; Path=/; Max-Age=0; Secure"),new Response(JSON.stringify({success:!0}),{headers:i})}pe();$e();Se();He();ge();Zn();async function Tp(r,e){try{if(await Rr(r,e))return!0}catch{}try{let t=atob(e),n=new Uint8Array(t.length);for(let s=0;s<t.length;s++)n[s]=t.charCodeAt(s);if(n.length===48){let s=n.slice(0,16),o=n.slice(16),i=Array.from(s).map(u=>u.toString(16).padStart(2,"0")).join(""),c=new TextEncoder().encode(r+i),a=await crypto.subtle.digest("SHA-256",c),l=new Uint8Array(a);if(l.length===o.length){let u=0;for(let d=0;d<l.length;d++)u|=l[d]^o[d];if(u===0)return!0}}}catch{}return!1}async function Al(r,e){let t=new URL(r.url),n=new G(e.DB,e),s=new ne(e.DB),o=caches.default,i=r.headers.get("CF-Connecting-IP")||"127.0.0.1",c=r.headers.get("User-Agent");if(t.pathname==="/api/auth/unlock-session"&&r.method==="GET"){let a=r.headers.get("Authorization")||"",l="";if(a.startsWith("Bearer ")&&(l=a.slice(7)),!l)return new Response("Unauthorized",{status:401});try{let u=await Ke(e),d=await Ie(u),p=await vr(l,d);if(!p)return new Response("Unauthorized",{status:401});let f=await n.getById(p.userId),m=!!(f?.pin_hash&&!/^[a-f0-9]{64}$/.test(f.pin_hash)),h=j(32),g=`unlock_nonce:${p.sessionId}`;return await v.set(o,g,{nonce:h,isLegacy:m},300),new Response(JSON.stringify({nonce:h,legacy:m,userId:p.userId,username:f?.username}),{headers:{"Content-Type":"application/json"}})}catch{return new Response("Unauthorized",{status:401})}}if(t.pathname==="/api/auth/unlock-session"&&r.method==="POST"){let a=r.headers.get("Authorization")||"",l="";if(a.startsWith("Bearer ")&&(l=a.slice(7)),!l)return new Response("Unauthorized",{status:401});try{let u=await Ke(e),d=await Ie(u),p=await vr(l,d);if(!p)return new Response("Unauthorized",{status:401});let{pinHash:f,nonce:m}=await r.json();if(!f)return new Response("Missing pinHash",{status:400});if(!m)return new Response("Missing nonce",{status:400});let h=new ae(e.DB),g=await h.getSession(p.sessionId);if(!g)return new Response("Session not found",{status:401});let w=await n.getById(p.userId);if(!w||!w.pin_hash)return new Response("PIN not configured",{status:400});let b=`unlock_nonce:${p.sessionId}`,y=await v.get(o,b);if(!y?.nonce)return new Response("Challenge expired, please start over",{status:400});let E=y.nonce,_=!!y.isLegacy;if(await v.delete(o,b),m!==E)return new Response("Invalid nonce",{status:400});let S=`unlock_fail:${g.id}`,R=(await v.get(o,S))?.count||0,D=await ee(g.id,p.userId),P=!1;if(_)P=await Tp(f,w.pin_hash),P&&await n.updatePinHash(p.userId,f);else{let N=await Pa(w.pin_hash,E);if(f.length===N.length){let V=0;for(let z=0;z<f.length;z++)V|=f.charCodeAt(z)^N.charCodeAt(z);P=V===0}}if(!P){let N=R+1;return N>=3?(await h.deleteSession(g.id),await v.delete(o,S),await s.record(p.userId,"pin_verify_fail",i,c,{reason:"too_many_attempts"},D),new Response(JSON.stringify({success:!1,error:"too_many_attempts"}),{status:401,headers:{"Content-Type":"application/json"}})):(await v.set(o,S,{count:N},900),await s.record(p.userId,"pin_verify_fail",i,c,{reason:"incorrect_pin",attempt:N},D),new Response(JSON.stringify({success:!1,error:"incorrect_pin",attemptsRemaining:3-N}),{status:400,headers:{"Content-Type":"application/json"}}))}let k=Math.floor(Date.now()/1e3);return await h.resumeSession(g.id,k),Xr(g.id),await v.delete(o,S),await s.record(p.userId,"pin_verify_success",i,c,void 0,D),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}catch(u){return console.error("Unlock session error:",u),new Response("Unauthorized",{status:401})}}if(t.pathname==="/api/auth/lock-session"&&r.method==="POST"){let a=r.headers.get("Authorization")||"",l="";if(a.startsWith("Bearer ")&&(l=a.slice(7)),!l)return new Response("Unauthorized",{status:401});try{let u=await Ke(e),d=await Ie(u),p=await vr(l,d);if(!p)return new Response("Unauthorized",{status:401});let f=new ae(e.DB),m=await f.getSession(p.sessionId);return m?(await f.pauseSession(m.id),Xr(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})}He();ge();Se();async function Dl(r,e){let t=new URL(r.url),n=t.pathname,s=new G(e.DB,e),o=new ne(e.DB),i=caches.default,c=r.headers.get("CF-Connecting-IP")||"127.0.0.1",a=r.headers.get("User-Agent");if(n==="/api/auth/forgot-password/init"&&r.method==="POST"){if(await v.isRateLimited(i,`forgot_pw_ip:${c}`,10,600))return new Response("Too many attempts",{status:429});let{username:l,turnstileToken:u}=await r.json();if(!l)return new Response("Username is required",{status:400});let d=new de(e.DB),[p,f]=await Promise.all([d.get("turnstile_secret_key"),d.get("turnstile_enabled_login")]);if(f==="true"&&p&&!await Qr(u,p,c))return new Response("Verification failed",{status:400});let m=await s.getByUsername(l);if(!m)return await v.isRateLimited(i,`forgot_pw_ip:${c}`,100,600),new Response("User not found",{status:404});let g=await new oe(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 D=typeof E=="string"?JSON.parse(E):E;y=Array.isArray(D)&&D.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&&(_=ur(),S={challenge:_,rpId:t.hostname,allowCredentials:g.map(D=>({id:D.credential_id,type:"public-key",transports:D.transports?JSON.parse(D.transports):void 0})),timeout:6e4,userVerification:"preferred"});let x=j(32),R={userId:m.id,username:m.username,passkeyChallenge:_,rpId:t.hostname,failedAttempts:0};return await v.set(i,`forgot_pw_state:${x}`,R,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(n==="/api/auth/forgot-password/verify"&&r.method==="POST"){let{recoveryToken:l,passkeyAssertion:u,totpTokenHash:d,totpSalt:p,recoveryKey:f}=await r.json();if(!l)return new Response("Recovery token is required",{status:400});let m=`forgot_pw_state:${l}`,h=await v.get(i,m);if(!h)return new Response("Recovery session expired or invalid",{status:400});if(h.failedAttempts>=3)return await v.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 v.delete(i,m),new Response("User not found",{status:404});if(u&&h.passkeyChallenge){let y=new oe(e.DB),_=(await y.listByUser(g.id)).find(S=>S.credential_id===u.id);if(!_)return h.failedAttempts++,await v.set(i,m,h,300),new Response("Passkey not recognized",{status:400});try{let{signCount:S}=await Ut({clientDataJSON:u.response.clientDataJSON,authenticatorData:u.response.authenticatorData,signature:u.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 v.set(i,m,h,300),new Response("Passkey verification failed",{status:400})}}else if(f){let y=[];try{let _=g.totp_recovery_keys;y=typeof _=="string"?JSON.parse(_||"[]"):_||[],Array.isArray(y)||(y=[y])}catch{}let E=await zr(f,y);if(E===-1)return h.failedAttempts++,await v.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(d&&g.totp_secret){let y=await qn(g.totp_secret,d,p);if(!y.valid)return h.failedAttempts++,await v.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 v.get(i,E))return h.failedAttempts++,await v.set(i,m,h,300),new Response("TOTP code already used, please wait for next code",{status:400});await v.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 v.delete(i,m);let w=j(32),b={userId:g.id,username:g.username};return await v.set(i,`forgot_pw_reset:${w}`,b,300),new Response(JSON.stringify({success:!0,resetToken:w}),{headers:{"Content-Type":"application/json"}})}if(n==="/api/auth/forgot-password/reset"&&r.method==="POST"){let{resetToken:l,newPassword:u}=await r.json();if(!l||!u)return new Response("Reset token and new password are required",{status:400});if(!Rt.test(u))return new Response("Password format error",{status:400});let d=`forgot_pw_reset:${l}`,p=await v.get(i,d);if(!p)return new Response("Reset token expired or invalid",{status:400});await v.delete(i,d);let f=await s.getById(p.userId);if(!f)return new Response("User not found",{status:404});let m=await ct(u,2);return await s.updatePassword(f.id,m,2),await new ae(e.DB).deleteAllByUserId(f.id),await o.record(f.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 vl(r,e){try{let n=new URL(r.url).pathname;return n==="/api/auth/config"||n==="/api/auth/check-username"?await yl(r,e):n==="/api/auth/signup"?await El(r,e):n==="/api/auth/prelogin"||n==="/api/auth/login"?await Tl(r,e):n==="/api/auth/refresh"?await Rl(r,e):n==="/api/auth/logout"?await xl(r,e):n.startsWith("/api/auth/forgot-password")?await Dl(r,e):n==="/api/auth/unlock-session"||n==="/api/auth/lock-session"?await Al(r,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 Zr=class{static isAdmin(e){return e.role==="admin"}static canAccessProfile(e,t){return t.owner_id===e.id}};pe();async function Pl(r,e,t,n){let s=new q(e.DB);if(r.method==="GET"){let o=await s.listByOwner(t.id);return new Response(JSON.stringify(o),{headers:{"Content-Type":"application/json"}})}if(r.method==="POST"){let o=await r.json();if(!o.name||!gi.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),u=e.MAX_LOG_RETENTION_DAYS!==void 0&&e.MAX_LOG_RETENTION_DAYS!==""?Number(e.MAX_LOG_RETENTION_DAYS):30,d=e.DEFAULT_LOG_RETENTION_DAYS!==void 0&&e.DEFAULT_LOG_RETENTION_DAYS!==""?Math.min(Number(e.DEFAULT_LOG_RETENTION_DAYS),u):Math.min(7,u),p=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),u):Math.min(7,u),f=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),p):Math.min(1,p),m=t?.role==="admin"?d:f,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 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(t.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 Cl(r,e,t,n,s,o){let i=new q(e.DB),c=new Ue(e.DB),a=n.id;if(s.length===3){if(r.method==="DELETE")return await i.delete(a),new Response(null,{status:204});if(r.method==="PATCH"){let{name:l}=await r.json();return!l||!gi.test(l)?new Response("Invalid Profile Name format",{status:400}):(await i.updateName(a,l),o.waitUntil(ce.clearCache(a,!0,e)),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}}))}return r.method==="GET"?new Response(JSON.stringify(n),{headers:{"Content-Type":"application/json"}}):new Response("Method Not Allowed",{status:405})}if(s[3]==="rotate_key"&&r.method==="POST"){let l=j(12);return await i.rotateKey(a,l),o.waitUntil(ce.clearCache(a,!1,e)),new Response(JSON.stringify({profile_key:l}),{headers:{"Content-Type":"application/json"}})}if(s[3]==="settings"&&r.method==="PATCH"){let l=await r.json(),u=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),u):u,p=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),u):Math.min(7,u),f=t?.role==="admin"?d:p;if(l.log_retention_days!=null&&(l.log_retention_days=Math.min(Number(l.log_retention_days),f)),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://"),R=w.startsWith("sdns://"),D=!w.includes("//")&&!w.startsWith("/");if(!b&&!y&&!E&&!_&&!S&&!x&&!R&&!D)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 P=D?`tcp://${w}`:w;if(!ut(P))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(ce.clearCache(a,!1,e)),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}if(s[3]==="test"&&r.method==="POST"){let{domain:l,type:u}=await r.json(),d=Kt(l,u),p=await ce.process(r,{name:l,type:u,raw:d},{profileId:a,startTime:Date.now(),env:e,ctx:o});return new Response(JSON.stringify({action:p.action,reason:p.reason,answers:p.answer.length>0?Le(p.answer):[],diagnostics:p.diagnostics,latency:p.latency,timings:p.timings,client_ip:r.headers.get("CF-Connecting-IP")||"127.0.0.1",geo_country:await Gt(r,r.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 Po=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 n=Math.floor(Date.now()/1e3),s=j(12),o=5;for(let i=0;i<o;i++){let c=Wt(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,n,n).run(),{id:s,profile_id:e,name:t,token:c,created_at:n,updated_at:n}}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,n){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(n,s,e,t).run()).success}async rotateAccessPointToken(e,t){let n=Math.floor(Date.now()/1e3),s=5;for(let o=0;o<s;o++){let i=Wt(5);try{if(!(await this.db.prepare("UPDATE access_points SET token = ?, updated_at = ? WHERE id = ? AND profile_id = ?").bind(i,n,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 kl(r,e,t,n,s,o){let i=new Po(e.DB);if(r.method==="GET"){let c=await i.getAccessPoints(n);return new Response(JSON.stringify(c),{headers:{"Content-Type":"application/json"}})}if(r.method==="POST"){if(s.length===6&&s[5]==="rotate_token"){let d=s[4],p=await i.rotateAccessPointToken(d,n);return new Response(JSON.stringify({token:p}),{headers:{"Content-Type":"application/json"}})}let c=await r.json();if(!c.name)return new Response("Name is required",{status:400});if(!mi.test(c.name))return new Response("Invalid Access Point name format",{status:400});let a=await i.getAccessPoints(n);if(a.some(d=>d.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 u=await i.addAccessPoint(n,c.name);return new Response(JSON.stringify(u),{status:201,headers:{"Content-Type":"application/json"}})}if(r.method==="PATCH"&&s.length===5){let c=s[4],a=await r.json();return a.name?mi.test(a.name)?(await i.getAccessPoints(n)).some(u=>u.id!==c&&u.name.toLowerCase()===a.name.toLowerCase())?new Response("Access Point name already exists",{status:400}):(await i.updateAccessPointName(c,n,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(r.method==="DELETE"&&s.length===5){let c=s[4];return await i.deleteAccessPoint(c,n),new Response(null,{status:204})}return new Response("Method Not Allowed",{status:405})}async function Ll(r,e,t,n,s,o){let i=new Cr(e.DB);if(r.method==="GET"){let c=await i.getRules(n);return new Response(JSON.stringify(c),{headers:{"Content-Type":"application/json"}})}if(r.method==="POST"){let c=await r.json();if(Array.isArray(c)||c&&Array.isArray(c.rules)){let p=Array.isArray(c)?c:c.rules,f=new Set,m=[];for(let y of p){if(!y||typeof y.pattern!="string")continue;let E=y.pattern.trim().toLowerCase();if(!E||f.has(E))continue;f.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(n),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(n,w),o.waitUntil(ce.clearCache(n,!1,e))),new Response(JSON.stringify({success:!0,count:b}),{status:201,headers:{"Content-Type":"application/json"}})}let l=c,u=l.pattern?l.pattern.trim():"";return u?await i.getRuleByPattern(n,u)?new Response("Rule for this domain already exists",{status:400}):(await i.addRule(n,l),o.waitUntil(ce.clearCache(n,!1,e)),new Response(null,{status:201})):new Response("Domain pattern cannot be empty",{status:400})}if(r.method==="PUT"){let c=await r.json(),a=c.pattern?c.pattern.trim():"";return a?await i.getRuleByPatternExcludeId(n,a,c.id)?new Response("Rule for this domain already exists",{status:400}):(await i.updateRule(c.id,n,c),o.waitUntil(ce.clearCache(n,!1,e)),new Response(null,{status:200})):new Response("Domain pattern cannot be empty",{status:400})}if(r.method==="DELETE"){let{id:c}=await r.json();return await i.deleteRule(c,n),o.waitUntil(ce.clearCache(n,!1,e)),new Response(null,{status:204})}return new Response("Method Not Allowed",{status:405})}var Mt=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 n=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<n.length;o+=100){let i=n.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,n){return(await this.db.prepare("UPDATE lists SET enabled = ? WHERE id = ? AND profile_id = ?").bind(n?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,n,s=null){return n!=null?(await this.db.prepare("UPDATE lists SET last_synced_at = ?, enabled = ?, sync_error = ? WHERE id = ?").bind(t,n,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 Bt=class{constructor(e){this.db=e}db;async upsertListBloom(e,t,n){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,n)),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 n=t.reduce((i,c)=>{let a=c.bloom_filter_chunk.byteLength??c.bloom_filter_chunk.length;return i+a},0),s=new Uint8Array(n),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(`
|
|
418
418
|
SELECT lb.list_id, lb.bloom_filter_chunk
|
|
419
419
|
FROM list_blooms lb
|
|
420
420
|
JOIN lists l ON lb.list_id = l.id
|
|
421
421
|
WHERE l.profile_id = ? AND l.enabled = 1
|
|
422
422
|
ORDER BY lb.list_id ASC, lb.chunk_index ASC
|
|
423
|
-
`).bind(e).all();if(!t||t.length===0)return[];let n=new Map;for(let o of t)n.has(o.list_id)||n.set(o.list_id,[]),n.get(o.list_id).push(o.bloom_filter_chunk);let s=[];for(let[,o]of n.entries()){let i=o.reduce((l,u)=>{let d=u.byteLength??u.length;return l+d},0),c=new Uint8Array(i),a=0;for(let l of o){let u=new Uint8Array(l);c.set(u,a),a+=u.length}s.push(c.buffer)}return s}};async function ts(r,e,t,n,s,o,i,c,a,l){let d=(await e.getLists(r)).filter(p=>!!p.enabled);if(d.length===0)await n.clearProfileBlooms(r);else{let p=Te.create(c,a),f=!1;for(let m of d)try{let h=await t.getListBloom(m.id);if(h){let g=Te.fromUint8Array(new Uint8Array(h));p.merge(g),f=!0}}catch(h){console.error(`[Sync] Failed to load/merge list bloom for list #${m.id}:`,h)}if(f){let m=p.toUint8Array();await n.upsertProfileBloom(r,m.buffer,i)}else await n.clearProfileBlooms(r)}await s.updateListUpdatedAt(r,i),o&&typeof o.waitUntil=="function"&&o.waitUntil(_s.clear(r,!0,l))}function
|
|
424
|
-
`);p=y.pop()||"";for(let E of y){let _=oa(E);if(_){let S=n(_);S instanceof Promise&&await S,f++}}}}if(p){let g=oa(p);if(g){let
|
|
423
|
+
`).bind(e).all();if(!t||t.length===0)return[];let n=new Map;for(let o of t)n.has(o.list_id)||n.set(o.list_id,[]),n.get(o.list_id).push(o.bloom_filter_chunk);let s=[];for(let[,o]of n.entries()){let i=o.reduce((l,u)=>{let d=u.byteLength??u.length;return l+d},0),c=new Uint8Array(i),a=0;for(let l of o){let u=new Uint8Array(l);c.set(u,a),a+=u.length}s.push(c.buffer)}return s}};async function ts(r,e,t,n,s,o,i,c,a,l){let d=(await e.getLists(r)).filter(p=>!!p.enabled);if(d.length===0)await n.clearProfileBlooms(r);else{let p=Te.create(c,a),f=!1;for(let m of d)try{let h=await t.getListBloom(m.id);if(h){let g=Te.fromUint8Array(new Uint8Array(h));p.merge(g),f=!0}}catch(h){console.error(`[Sync] Failed to load/merge list bloom for list #${m.id}:`,h)}if(f){let m=p.toUint8Array();await n.upsertProfileBloom(r,m.buffer,i)}else await n.clearProfileBlooms(r)}await s.updateListUpdatedAt(r,i),o&&typeof o.waitUntil=="function"&&o.waitUntil(_s.clear(r,!0,l))}function Rp(r){if(r.includes(":"))return!0;let e=0,t=r.length;if(t<7||t>15)return!1;for(let n=0;n<t;n++){let s=r.charCodeAt(n);if(s===46)e++;else if(s<48||s>57)return!1}return e===3}function oa(r){let e=0,t=r.length;for(;e<t;){let a=r.charCodeAt(e);if(a===32||a===9||a===13||a===10)e++;else break}let n=t;for(;n>e;){let a=r.charCodeAt(n-1);if(a===32||a===9||a===13||a===10)n--;else break}if(e>=n)return null;let s=r.charCodeAt(e);if(s===33||s===35||s===64&&e+1<n&&r.charCodeAt(e+1)===64)return null;let o=r.substring(e,n);if(o.startsWith("||")){let a=o.substring(2),l=a.indexOf("^");l!==-1&&(a=a.substring(0,l));let u=a.indexOf("$");return u!==-1&&(a=a.substring(0,u)),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 d=o.charCodeAt(l);if(d===32||d===9)l++;else break}let u="";if(l<c){let d=l;for(;d<c;){let p=o.charCodeAt(d);if(p===32||p===9)break;d++}u=o.substring(l,d)}if(u!=="")if(Rp(a)){let d=u.toLowerCase();return d!=="localhost"&&d!=="0.0.0.0"&&d!=="127.0.0.1"?d:null}else return a.toLowerCase();else return a.toLowerCase()}}async function Ol(r,e,t,n){let s=Date.now()+t,o=r,i=0,c=5,a;try{for(;;){if(!await Ua(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 u=a.body?.getReader();if(!u)return{count:0,error:"Failed to get stream reader from response"};let d=new TextDecoder("utf-8",{fatal:!1,ignoreBOM:!0}),p="",f=0,m=0,h=!1;for(;;){let{done:g,value:w}=await u.read();if(g)break;if(w){if(m+=w.length,m>e){await u.cancel(),h=!0;break}let b=d.decode(w,{stream:!0});p+=b;let y=p.split(`
|
|
424
|
+
`);p=y.pop()||"";for(let E of y){let _=oa(E);if(_){let S=n(_);S instanceof Promise&&await S,f++}}}}if(p){let g=oa(p);if(g){let w=n(g);w instanceof Promise&&await w,f++}}return h&&console.warn(`[Fetcher] List truncated at ${(e/1024/1024).toFixed(0)} MB: ${r}`),{count:f,error:null}}catch(l){return{count:0,error:l.message||String(l)}}}var xp=5*1024*1024;async function Co(r,e,t,n,s,o){let i=Number(t.SYNC_TIMEOUT_MS)||9e4,c=Number(t.MAX_LIST_DOMAINS)||5e5,a=Number(t.MAX_SYNC_DOMAINS)||1e6,l=Number(t.BLOOM_FALSE_POSITIVE_RATE)||1e-4,u=Number(t.SYNC_YIELD_BATCH_SIZE)||5e3,d=Number(t.SYNC_YIELD_SLEEP_MS)||10,p=Te.create(a,l),f=0,m=0,{error:h}=await Ol(e.url,xp,i,w=>{if(f<c&&(p.add(w),f++,m++,m>=u))return m=0,new Promise(b=>setTimeout(b,d))}),g=h;return h?console.warn(`[Sync] Profile ${r}: failed to fetch/parse list #${e.id}. Skipping and keeping old bloom. Error: ${h}`):(await s.upsertListBloom(e.id,p.toUint8Array().buffer,o),console.log(`[Sync] Profile ${r}: successfully updated list #${e.id} with ${f} domains.`)),await n.updateListSyncStatus(e.id,o,null,g),g}async function qr(r,e,t){let n=new q(e.DB),s=new Mt(e.DB),o=new Tt(e.DB),i=new Bt(e.DB),c=Math.floor(Date.now()/1e3);try{let a=await n.getById(r);if(!a){console.error(`[Sync] Profile ${r} not found.`);return}let l=a.list_updated_at??0,d=(await s.getLists(r)).filter(b=>!!b.enabled);if(d.length===0){await o.clearProfileBlooms(r),await n.updateListUpdatedAt(r,c);return}!d.some(b=>(b.last_synced_at??0)>l)&&console.log(`[Sync] Profile ${r}: starting a new sync cycle.`);let f=d.filter(b=>(b.last_synced_at??0)<=l).sort((b,y)=>(b.last_synced_at??0)-(y.last_synced_at??0));if(f.length===0){let b=Number(e.MAX_SYNC_DOMAINS)||1e6,y=Number(e.BLOOM_FALSE_POSITIVE_RATE)||1e-4;await n.updateListUpdatedAt(r,c),await ts(r,s,i,o,n,t,c,b,y,e);return}let m=f[0];await Co(r,m,e,s,i,c);let g=(await s.getLists(r)).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 n.updateListUpdatedAt(r,c),await ts(r,s,i,o,n,t,c,b,y,e),console.log(`[Sync] Profile ${r}: 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 ${r}: ${b} active list(s) remaining in this cycle.`)}}catch(a){console.error(`[Sync] Critical failure for Profile ${r}:`,a),await n.updateListUpdatedAt(r,c)}}async function ia(r,e,t){let n=new q(e.DB),s=new Mt(e.DB),o=new Tt(e.DB),i=new Bt(e.DB),c=Math.floor(Date.now()/1e3);try{if(!await n.getById(r)){console.error(`[Sync] Profile ${r} not found.`);return}let u=(await s.getLists(r)).filter(f=>!!f.enabled);if(u.length===0){await o.clearProfileBlooms(r),await n.updateListUpdatedAt(r,c);return}for(let f of u)await Co(r,f,e,s,i,c);await n.updateListUpdatedAt(r,c);let d=Number(e.MAX_SYNC_DOMAINS)||1e6,p=Number(e.BLOOM_FALSE_POSITIVE_RATE)||1e-4;await ts(r,s,i,o,n,t,c,d,p,e),console.log(`[Sync] Profile ${r}: manual sync cycle complete.`)}catch(a){console.error(`[Sync] Critical failure in manual sync for Profile ${r}:`,a),await n.updateListUpdatedAt(r,c)}}async function ko(r,e,t){let n=new Mt(e.DB),s=new Bt(e.DB),o=new Tt(e.DB),i=new q(e.DB),a=(await i.getById(r))?.list_updated_at??0,l=(await n.getLists(r)).filter(p=>!!p.enabled),d=(await Promise.all(l.map(p=>s.hasListBloom(p.id).catch(()=>!0)))).findIndex(p=>!p);if(d!==-1){let p=l[d];try{await Co(r,p,e,n,s,Math.floor(Date.now()/1e3))}catch(f){console.error(`[Sync] fetch of list ${p.id} during rebuild failed:`,f)}}await ts(r,n,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(r,a)}async function Nl(r,e,t,n,s,o){let i=new Mt(e.DB),c=new q(e.DB);if(r.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 d=(new URL(r.url).searchParams.get("domain")||"").trim().toLowerCase().replace(/\.+$/,"");if(!d||d.length>253||!/^[a-z0-9._-]+$/.test(d))return new Response("Invalid or missing domain parameter",{status:400});let p=await i.getListById(l,n);if(!p)return new Response("List Not Found",{status:404});let f=await new Bt(e.DB).getListBloom(l);if(!f)return new Response(JSON.stringify({domain:d,blocked:!1,synced:!1}),{headers:{"Content-Type":"application/json"}});let m;try{m=Te.fromUint8Array(new Uint8Array(f))}catch(w){return console.error(`[Lists] Failed to deserialize bloom filter for list #${l}:`,w),new Response(JSON.stringify({domain:d,blocked:!1,synced:!1,error:"Corrupted filter"}),{status:500,headers:{"Content-Type":"application/json"}})}let h=d,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:d,blocked:g!==null,matchedEntry:g,falsePositiveRate:Number(e.BLOOM_FALSE_POSITIVE_RATE)||1e-4,enabled:!!p.enabled,synced:!0}),{headers:{"Content-Type":"application/json"}})}let a=await i.getLists(n);return new Response(JSON.stringify(a),{headers:{"Content-Type":"application/json"}})}if(r.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 r.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,n)?await i.setEnabled(a,n,l.enabled)?(o.waitUntil(ko(n,e,o).then(()=>ce.clearCache(n,!0,e)).catch(p=>console.error(`[Lists] bloom rebuild failed for ${n}:`,p))),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(r.method==="POST"){if(s[4]==="sync")return o.waitUntil(ia(n,e,o)),new Response(JSON.stringify({message:"Sync started"}),{status:202});let a=await r.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 p=l,f=new Set,m=[];for(let y of p){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(!ut(E))continue;let _=E.toLowerCase();if(f.has(_))continue;f.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(n),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(n,w),o.waitUntil(qr(n,e,o)),o.waitUntil(ce.clearCache(n,!0,e))),new Response(JSON.stringify({success:!0,count:b}),{status:201,headers:{"Content-Type":"application/json"}})}let{url:d}=a;return!d||!d.startsWith("http://")&&!d.startsWith("https://")?new Response("Invalid list URL format",{status:400}):ut(d)?(await i.addList(n,d),o.waitUntil(qr(n,e,o)),o.waitUntil(ce.clearCache(n,!0,e)),new Response(null,{status:201})):new Response("Invalid list URL. Private networks and localhosts are not allowed.",{status:400})}if(r.method==="DELETE"){let{id:a}=await r.json();return await i.deleteList(a,n),o.waitUntil(ko(n,e,o).then(()=>ce.clearCache(n,!0,e)).catch(l=>console.error(`[Lists] Bloom rebuild after delete failed for ${n}:`,l))),new Response(null,{status:204})}return new Response("Method Not Allowed",{status:405})}ge();async function Il(r,e,t,n,s){let o=r.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 u=n.id,d=!1,p=0,f=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(!(d||h||p<=0)){h=!0;try{if(!await e.DB.prepare(`
|
|
425
425
|
SELECT id, timestamp
|
|
426
426
|
FROM logs
|
|
427
427
|
WHERE profile_id = ? AND (timestamp > ? OR (timestamp = ? AND id > ?))
|
|
@@ -438,7 +438,7 @@ echo "Please change your system DNS to 127.0.0.1"
|
|
|
438
438
|
WHERE l.profile_id = ? AND (l.timestamp > ? OR (l.timestamp = ? AND l.id > ?))
|
|
439
439
|
ORDER BY l.timestamp DESC, l.id DESC
|
|
440
440
|
LIMIT 50;
|
|
441
|
-
`).bind(u,p,p,f).all();if(_&&_.length>0){let S=_[0];if(p=S.timestamp,f=Number(S.id),!d){let x={type:"NEW_LOGS",logs:_,latestTimestamp:p,latestId:f};l.send(JSON.stringify(x))}}}catch(E){console.error("[Logs WS] Error probing new logs:",E)}finally{h=!1}}};m=setInterval(()=>{
|
|
441
|
+
`).bind(u,p,p,f).all();if(_&&_.length>0){let S=_[0];if(p=S.timestamp,f=Number(S.id),!d){let x={type:"NEW_LOGS",logs:_,latestTimestamp:p,latestId:f};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":{p=S.sinceTimestamp,f=S.lastId||0,await b();break}case"CHECK_NEW":{S.sinceTimestamp!==void 0&&(p=S.sinceTimestamp),S.lastId!==void 0&&(f=S.lastId),await b();break}case"SYNC_GAP":{let x=Math.max(1,Math.min(Number(S.limit)||100,100)),{results:R}=await e.DB.prepare(`
|
|
442
442
|
SELECT l.id, l.timestamp, l.client_ip, l.domain, l.action, l.record_type,
|
|
443
443
|
l.latency, l.answer, l.geo_country, l.reason, l.access_point_id,
|
|
444
444
|
l.dest_country_code, l.dest_country, l.dest_isp, l.encrypt_version,
|
|
@@ -449,7 +449,7 @@ echo "Please change your system DNS to 127.0.0.1"
|
|
|
449
449
|
WHERE l.profile_id = ? AND l.timestamp >= ? AND l.timestamp <= ?
|
|
450
450
|
ORDER BY l.timestamp DESC, l.id DESC
|
|
451
451
|
LIMIT ?;
|
|
452
|
-
`).bind(u,S.since,S.until,x).all();if(!d){let D={type:"SYNC_DATA",logs:R||[],hasMore:(R?.length||0)>=x};l.send(JSON.stringify(D))}break}case"PING":{if(!d){let x={type:"PONG"};l.send(JSON.stringify(x)),
|
|
452
|
+
`).bind(u,S.since,S.until,x).all();if(!d){let D={type:"SYNC_DATA",logs:R||[],hasMore:(R?.length||0)>=x};l.send(JSON.stringify(D))}break}case"PING":{if(!d){let x={type:"PONG"};l.send(JSON.stringify(x)),b()}break}default:break}}catch(_){console.error("[Logs WS] Message processing error:",_)}});let y=()=>{if(!d){d=!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 Ul(r,e,t,n,s,o){let i=new Ue(e.DB),c=n.id;if(s[3]==="logs"){if(s[4]==="ws"||r.headers.get("Upgrade")?.toLowerCase()==="websocket")return Il(r,e,t,n,o);if(r.method!=="GET")return new Response("Method Not Allowed",{status:405});let a=new URL(r.url).searchParams,l=a.get("range")||"24h",u=a.get("before"),d=a.get("status"),p=a.get("search"),f=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),R=e.MAX_LOG_RETENTION_DAYS!==void 0&&e.MAX_LOG_RETENTION_DAYS!==""?Number(e.MAX_LOG_RETENTION_DAYS):30,D=JSON.parse(n.settings),P=D.log_retention_days!==void 0?Math.min(Number(D.log_retention_days),R):R;if(P===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 k=Math.floor(x-P*24*3600);if(E&&_)S=Math.max(parseInt(E),k),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,k)}if(s.length>4){if(s[4]==="export"){let se=await i.getLogs(c,{since:S,until:x,status:d||void 0,search:p||void 0,access_point_id:f||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 z=parseInt(s[4],10);if(isNaN(z))return new Response("Invalid Log ID",{status:400});let ue=a.get("timestamp"),Ae=ue?parseInt(ue,10):void 0,K=await i.getLog(c,z,Ae);return K?new Response(JSON.stringify(K),{headers:{"Content-Type":"application/json"}}):new Response("Log Not Found",{status:404})}let N=parseInt(a.get("limit")||"50",10);isNaN(N)||N<=0?N=50:N>100&&(N=100);let V=await i.getLogs(c,{since:S,until:x,status:d||void 0,search:p||void 0,before:u?parseInt(u):void 0,limit:N,access_point_id:f||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(r.method!=="GET")return new Response("Method Not Allowed",{status:405});let a=new URL(r.url).searchParams,l=a.get("range"),u=a.get("start"),d=a.get("end"),p=a.get("access_point_id")||void 0,f,m=Math.floor(Date.now()/1e3),h;if(u&&d)f=parseInt(u),m=parseInt(d),h="(timestamp/3600)*3600";else switch(l){case"10m":f=m-600,h="(timestamp/60)*60";break;case"1h":f=m-3600,h="(timestamp/60)*60";break;case"24h":f=m-86400,h="(timestamp/3600)*3600";break;case"7d":f=m-604800,h="(timestamp/86400)*86400";break;case"30d":f=m-2592e3,h="(timestamp/86400)*86400";break;default:f=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 v.get(_,S);if(x)return new Response(JSON.stringify(x),{headers:{"Content-Type":"application/json","X-Cache":"HIT","Cache-Control":"private, no-cache"}});let R=null;if(g==="summary"){let D=a.get("search")||void 0;R=await i.getSummary(c,f,m,D,p)}else if(g==="trend")R=await i.getTrend(c,f,m,h,p);else if(g==="top_allowed")R=await i.getTopAllowed(c,f,m,p);else if(g==="top_blocked")R=await i.getTopBlocked(c,f,m,p);else if(g==="clients")R=await i.getClients(c,f,m,p);else if(g==="destinations"){let D=a.get("limit"),P=D?parseInt(D,10):void 0;R=await i.getDestinations(c,f,m,p,P!==void 0&&!isNaN(P)?P:void 0)}else if(g==="isps"){let D=a.get("country_code")||void 0,P=a.get("limit"),k=P?parseInt(P,10):void 0;R=await i.getISPByCountry(c,D,f,m,p,k!==void 0&&!isNaN(k)?k:void 0)}else return new Response("Not Found",{status:404});return await v.set(_,S,R,300),new Response(JSON.stringify(R),{headers:{"Content-Type":"application/json","X-Cache":"MISS","Cache-Control":"private, no-cache"}})}let w=caches.default,b=`analytics:${c}:${f}:${m}:${h}:${p||"all"}`,y=await v.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,f,m,h,p);return await v.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 Ml(r,e,t,n,s,o){let i=new oe(e.DB),c=s[4];if(c==="status"&&r.method==="GET"){let[a,l,u,d]=await Promise.all([e.DB.prepare("SELECT public_key, created_at, is_active FROM user_log_keys WHERE profile_id = ?").bind(n.id).first(),e.DB.prepare(`
|
|
453
453
|
SELECT upwk.passkey_id
|
|
454
454
|
FROM user_passkey_wrapped_keys upwk
|
|
455
455
|
JOIN passkeys pk ON upwk.passkey_id = pk.id
|
|
@@ -460,7 +460,7 @@ echo "Please change your system DNS to 127.0.0.1"
|
|
|
460
460
|
JOIN passkeys pk ON upwk.passkey_id = pk.id
|
|
461
461
|
WHERE pk.user_id = ?
|
|
462
462
|
LIMIT 1
|
|
463
|
-
`).bind(t.id).first()),u?Response.json({encryptedSk:u.encrypted_sk,iv:u.iv}):new Response("Wrapped key not found for this passkey",{status:404})}if(c==="init"&&r.method==="POST"){let a;try{a=await r.json()}catch{return new Response("Invalid JSON body",{status:400})}let{publicKey:l,passkeyId:u,encryptedSk:d,iv:p,recovery:f}=a;if(!l||!u||!d||!p)return new Response("Missing required fields (publicKey, passkeyId, encryptedSk, iv)",{status:400});let m=await i.getByIdOrCredentialId(u,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(n.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,n.id,d,p,h)];return f&&f.encryptedSk&&f.iv&&f.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(n.id,f.encryptedSk,f.iv,f.salt,h)),await e.DB.batch(b),nr(n.id),Response.json({success:!0})}if(c==="wrap"&&r.method==="POST"){let a;try{a=await r.json()}catch{return new Response("Invalid JSON body",{status:400})}let{passkeyId:l,encryptedSk:u,iv:d}=a;if(!l||!u||!d)return new Response("Missing required fields (passkeyId, encryptedSk, iv)",{status:400});let p=await i.getByIdOrCredentialId(l,t.id);if(!p){let m=await i.listByUser(t.id);m.length>0&&(p=m[0])}if(!p)return new Response("Passkey not found or unauthorized",{status:403});let f=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(p.id,n.id,u,d,f).run(),Response.json({success:!0})}return r.method==="DELETE"&&(!c||c==="keys")?(await e.DB.batch([e.DB.prepare("DELETE FROM user_log_keys WHERE profile_id = ?").bind(n.id),e.DB.prepare("DELETE FROM user_passkey_wrapped_keys WHERE profile_id = ?").bind(n.id),e.DB.prepare("DELETE FROM user_recovery_wrapped_keys WHERE profile_id = ?").bind(n.id)]),nr(n.id),Response.json({success:!0})):new Response("Not Found",{status:404})}async function Fl(r,e,t,n){let o=new URL(r.url).pathname.split("/").filter(Boolean),i=new q(e.DB);if(o.length===2)return t?Cl(r,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(!Zr.canAccessProfile(t,a))return new Response("Profile Not Found",{status:404});let l=o[3];if(!l||["rotate_key","settings","test"].includes(l))return kl(r,e,t,a,o,n);switch(l){case"access_points":return Ll(r,e,t,c,o,n);case"rules":return Ol(r,e,t,c,o,n);case"lists":return Il(r,e,t,c,o,n);case"logs":case"analytics":return Ml(r,e,t,a,o,n);case"e2ee":return Bl(r,e,t,a,o,n);default:return new Response("Not Found",{status:404})}}return new Response("Not Found",{status:404})}pe();async function Hl(r,e,t,n,s){let o=new G(e.DB,e),i=new Ie(e.DB),c=n[2];if(c==="me"){if(r.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,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),l):l,d=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),f=await new oe(e.DB).countByUser(t.id),m=!!a?.totp_enabled||f>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)&&!_t(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:f,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"?u:d,jwt_secret_warning:g}),{headers:{"Content-Type":"application/json"}})}if(r.method==="PATCH"){let a=await r.json();try{if(t.isPaused){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})}return await o.updateLocale(t.id,l||"en-US"),new Response(JSON.stringify({success:!0}))}return new Response("session_paused",{status:403})}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||!xt.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==="logs"&&r.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"&&r.method==="POST"){let{invalidateSession:a}=await Promise.resolve().then(()=>(pe(),Pn)),l=r.headers.get("Cookie")||"",u=Le(l),d=u&&ve(u)?.sid||null;return d&&await a(e,d),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})}Se();Se();ge();async function dr(r,e,t,n){if(e.passkeyAssertion){let o=caches.default,i=await v.get(o,`webauthn_auth_challenge:${r.id}`);if(!i)return{success:!1,error:"Passkey session expired, please try again",reason:"passkey_session_expired"};let c=new oe(t.DB),l=(await c.listByUser(r.id)).find(d=>d.credential_id===e.passkeyAssertion.id);if(!l)return{success:!1,error:"Passkey not found",reason:"passkey_not_found"};let u=new URL(n.url);try{let{signCount:d}=await Ut({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:`${u.protocol}//${u.host}`,expectedRpId:i.rpId,previousSignCount:l.sign_count});return await c.updateUsage(l.id,d),await v.delete(o,`webauthn_auth_challenge:${r.id}`),{success:!0,method:"passkey"}}catch{return{success:!1,error:"Invalid Passkey signature",reason:"invalid_passkey"}}}if(e.totpTokenHash)return!r.totp_enabled||!r.totp_secret?{success:!1,error:"TOTP is not enabled",reason:"totp_not_enabled"}:await es(r.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 bt(s,r.hashed_password,r.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 r.totp_recovery_keys=="string"?JSON.parse(r.totp_recovery_keys):r.totp_recovery_keys||[]}catch{}return await zr(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 $l(r,e,t,n,s){let o=new G(e.DB,e),i=new ne(e.DB),c=r.headers.get("CF-Connecting-IP")||"127.0.0.1",a=r.headers.get("User-Agent"),l=n[2],u=t.sessionId?await ee(t.sessionId,t.id):null;if(l==="password"&&r.method==="POST"){let d=await r.json(),{newPassword:p}=d;if(!p||!Rt.test(p))return new Response("Password format error",{status:400});let f=await o.getById(t.id);if(!f)return new Response("User not found",{status:404});let m=await dr(f,d,e,r);if(!m.success)return await i.record(t.id,"password_change_fail",c,a,{reason:m.reason},u),new Response(m.error||"Authentication failed",{status:400});let h=await at(p,2);return await o.updatePassword(t.id,h,2),await i.record(t.id,"password_change_success",c,a,{method:m.method},u),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}if(l==="migrate-password"&&r.method==="POST"){let d=await r.json(),{clientHash:p}=d;if(!p)return new Response("Missing clientHash",{status:400});let f=await o.getById(t.id);if(!f)return new Response("User not found",{status:404});let m=await dr(f,d,e,r);if(!m.success)return await i.record(t.id,"password_change_fail",c,a,{reason:m.reason,flow:"migration"},u),new Response(m.error||"Authentication failed",{status:400});if((f.password_version??1)===1){let h=await at(p,2);await o.updatePassword(t.id,h,2),await i.record(t.id,"password_change_success",c,a,{method:"migration"},u)}return new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}return new Response("Not Found",{status:404})}Se();async function Kl(r,e,t,n,s){let o=new G(e.DB,e),i=new ne(e.DB),c=r.headers.get("CF-Connecting-IP")||"127.0.0.1",a=r.headers.get("User-Agent"),l=n[2],u=t.sessionId?await ee(t.sessionId,t.id):null;if(l==="totp"){let d=n[3];if(d==="setup"&&r.method==="GET"){let p=await o.getById(t.id);if(p?.totp_enabled)return new Response("TOTP is already enabled",{status:409});let f=bl(),m=new URL(r.url).hostname,h=El(f,p?.username||"user",m);return new Response(JSON.stringify({secret:f,uri:h}),{headers:{"Content-Type":"application/json"}})}if(d==="confirm"&&r.method==="POST"){let{secret:p,totpTokenHash:f,salt:m}=await r.json();if(!p||!f)return new Response("Missing secret or token",{status:400});if(!await es(p,f,m))return new Response("Invalid TOTP code",{status:400});let g=Po(),b=await Promise.all(g.map(async w=>({hash:await Ye(w)})));return await o.updateTOTP(t.id,p,b),await o.updateTOTPSettings(t.id,!0),await i.record(t.id,"totp_setup",c,a,void 0,u),new Response(JSON.stringify({success:!0,recovery_keys:g}),{headers:{"Content-Type":"application/json"}})}if(d==="test"&&r.method==="POST"){let p=await o.getById(t.id);if(!p?.totp_enabled||!p?.totp_secret)return new Response(JSON.stringify({success:!1,message:"TOTP is not enabled"}),{status:400,headers:{"Content-Type":"application/json"}});let{token:f,totpTokenHash:m,salt:h}=await r.json(),g=m||f;return g?await es(p.totp_secret,g,h)?(await i.record(t.id,"totp_verify_success",c,a,{flow:"mfa_test"},u),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})):(await i.record(t.id,"totp_verify_fail",c,a,{flow:"mfa_test"},u),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(d==="settings"&&r.method==="PATCH"){let p=await o.getById(t.id),m=await new oe(e.DB).listByUser(t.id);if(!(!!p?.totp_enabled||m.length>0))return new Response("MFA is not enabled",{status:400});let{skip_password:g}=await r.json();return await o.updateTOTPSettings(t.id,!!g),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}if(!d&&r.method==="DELETE"){let{password:p}=await r.json(),f=await o.getById(t.id);if(!f)return new Response("User not found",{status:404});if(!f.totp_skip_password&&(!p||!await bt(p,f.hashed_password,f.password_version??1)))return new Response("Incorrect password",{status:400});let g=(await new oe(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,u),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}}if(l==="mfa"&&n[3]==="settings"&&r.method==="PATCH"){let d=await o.getById(t.id),f=await new oe(e.DB).listByUser(t.id);if(!(!!d?.totp_enabled||f.length>0))return new Response("MFA is not enabled",{status:400});let{skip_password:h}=await r.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 Wl(r,e,t,n,s){let o=new G(e.DB,e),i=await o.getById(t.id);if(!i)return new Response("User not found",{status:404});let c=await r.json(),a=await dr(i,c,e,r);if(!a.success)return new Response(a.error||"Authentication failed",{status:400});if(r.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 r.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})}Se();ge();async function jl(r,e,t,n,s){let o=new G(e.DB,e),i=new oe(e.DB),c=new ne(e.DB),a=r.headers.get("CF-Connecting-IP")||"127.0.0.1",l=r.headers.get("User-Agent"),u=n[3],d=t.sessionId?await ee(t.sessionId,t.id):null;if(!u&&r.method==="GET"){let p=await i.listByUser(t.id);return new Response(JSON.stringify(p),{headers:{"Content-Type":"application/json"}})}if(u==="auth-options"&&r.method==="POST"){let p=await i.listByUser(t.id);if(p.length===0)return new Response("No passkeys registered",{status:400});let f;try{r.headers.get("content-type")?.includes("application/json")&&(f=(await r.json())?.passkeyId)}catch{}let m=f?p.filter(E=>E.id===f):p;if(m.length===0)return new Response("Target passkey not found",{status:404});let h=ur(),b=new URL(r.url).hostname,w=caches.default;await v.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(u==="test"&&r.method==="POST"){let p=caches.default,f=await v.get(p,`webauthn_auth_challenge:${t.id}`);if(!f)return new Response("Test session expired, please try again",{status:400});let m=await r.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(r.url);try{let{signCount:y}=await Ut({clientDataJSON:h.response.clientDataJSON,authenticatorData:h.response.authenticatorData,signature:h.response.signature,publicKeySpki:b.public_key,algorithm:b.algorithm,expectedChallenge:f.challenge,expectedOrigin:`${w.protocol}//${w.host}`,expectedRpId:f.rpId,previousSignCount:b.sign_count});return await i.updateUsage(b.id,y),await v.delete(p,`webauthn_auth_challenge:${t.id}`),await c.record(t.id,"passkey_verify_success",a,l,{flow:"mfa_test",name:b.name,id:b.id},d),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"},d),console.warn("[Passkey Test] Verification failed:",y.message||y),new Response(y.message||"Passkey verification failed",{status:400})}}if(u==="register"&&n[4]==="options"&&r.method==="POST"){let p=await i.listByUser(t.id),f=ur(),h=new URL(r.url).hostname,g=caches.default;await v.set(g,`webauthn_reg_challenge:${t.id}`,{challenge:f,rpId:h},300);let w=(await o.getById(t.id))?.username||t.username||"",y=w?`${w} (${h})`:h,E={challenge:f,rp:{name:h,id:h},user:{id:ht(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:p.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(u==="register"&&n[4]==="verify"&&r.method==="POST"){let p=caches.default,f=await v.get(p,`webauthn_reg_challenge:${t.id}`);if(!f)return new Response("Registration session expired, please try again",{status:400});await v.delete(p,`webauthn_reg_challenge:${t.id}`);let m=await r.json(),{name:h,credential:g}=m;if(!g||!g.response)return new Response("Invalid credential data",{status:400});let b=new URL(r.url),w=`${b.protocol}//${b.host}`;try{let y=await Tl({clientDataJSON:g.response.clientDataJSON,attestationObject:g.response.attestationObject,expectedChallenge:f.challenge,expectedOrigin:w,expectedRpId:f.rpId});if(await i.getByCredentialId(y.credentialId))return new Response("This passkey is already registered",{status:409});let _=(h||"").trim();if(!gi.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 R=await o.getById(t.id),D=[];if(R){let P=!1;if(R.totp_recovery_keys)try{let k=typeof R.totp_recovery_keys=="string"?JSON.parse(R.totp_recovery_keys):R.totp_recovery_keys;Array.isArray(k)&&k.length>0&&(P=!0)}catch{R.totp_recovery_keys.length>0&&(P=!0)}else R.totp_recovery_keys_encrypted&&(P=!0);if(!P){let k=Po(),N=await Promise.all(k.map(async V=>({hash:await Ye(V)})));await o.updateRecoveryKeys(t.id,N),D=k}}return await c.record(t.id,"passkey_registered",a,l,{name:_},d),new Response(JSON.stringify({...x,recovery_keys:D.length>0?D: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(u&&r.method==="PATCH"){let p=u,{name:f}=await r.json(),m=(f||"").trim();if(!m||!gi.test(m))return new Response("Invalid Passkey name format",{status:400});if(!await i.getById(p,t.id))return new Response("Passkey not found",{status:404});let g=await i.updateName(p,t.id,m);return new Response(JSON.stringify({success:g}),{headers:{"Content-Type":"application/json"}})}if(u&&r.method==="DELETE"){let p=u,f=await i.getById(p,t.id);if(!f)return new Response("Passkey not found",{status:404});await i.delete(p,t.id),await c.record(t.id,"passkey_deleted",a,l,{name:f.name},d);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})}Se();async function Vl(r,e,t,n,s){let o=new G(e.DB,e),i=new ne(e.DB),c=r.headers.get("CF-Connecting-IP")||"127.0.0.1",a=r.headers.get("User-Agent"),l=n[3],u=t.sessionId?await ee(t.sessionId,t.id):null;if(l==="rotate"&&r.method==="POST"){let d=await r.json(),p=await o.getById(t.id);if(!p)return new Response("User not found",{status:404});let f=await dr(p,d,e,r);if(!f.success)return new Response(f.error||"Authentication failed",{status:400});if(f.method!=="passkey"&&f.method!=="recovery_key")return new Response("Recovery Key rotation only permits authentication via existing Passkey or original Recovery Key",{status:403});let m=lr(),g=[{hash:await Ye(m)}];return await o.updateRecoveryKeys(t.id,g),await i.record(t.id,"recovery_key_rotated",c,a,{method:f.method},u),new Response(JSON.stringify({success:!0,recovery_key:m}),{headers:{"Content-Type":"application/json"}})}return new Response("Not Found",{status:404})}async function Jl(r,e,t,n,s){switch(n[2]){case"password":case"migrate-password":return $l(r,e,t,n,s);case"totp":case"mfa":return Kl(r,e,t,n,s);case"pin":return Wl(r,e,t,n,s);case"passkeys":return jl(r,e,t,n,s);case"recovery-keys":return Vl(r,e,t,n,s);default:return new Response("Not Found",{status:404})}}pe();async function Gl(r,e,t,n,s){let o=new ne(e.DB),i=r.headers.get("CF-Connecting-IP")||"127.0.0.1",c=r.headers.get("User-Agent"),a=n[2];if(a==="activity"&&r.method==="GET"){let l=new URL(r.url).searchParams,u=Math.min(parseInt(l.get("limit")||"20",10),50),d=l.get("before")?parseInt(l.get("before"),10):void 0,p=await o.listByUser(t.id,u,d);return new Response(JSON.stringify(p),{headers:{"Content-Type":"application/json"}})}if(a==="sessions"){if(!n[3]&&r.method==="GET"){let{SessionModel:l}=await Promise.resolve().then(()=>(Fe(),Rn)),d=await new l(e.DB).getSessionsByUser(t.id),p=r.headers.get("Cookie")||"",f=Le(p),m=f&&ve(f)?.sid||null,h=await Promise.all(d.map(async g=>({...g,id:await ee(g.id,t.id),is_current:g.id===m})));return new Response(JSON.stringify(h),{headers:{"Content-Type":"application/json"}})}if(n[3]==="others"&&r.method==="DELETE"){let{SessionModel:l}=await Promise.resolve().then(()=>(Fe(),Rn)),u=new l(e.DB),d=Le(r.headers.get("Cookie")||""),p=d&&ve(d)?.sid||null;if(!p)return new Response("Current session not found",{status:400});let m=(await u.getSessionsByUser(t.id)).filter(w=>w.id!==p),{invalidateSession:h}=await Promise.resolve().then(()=>(pe(),Pn)),{invalidateAuthUserCache:g}=await Promise.resolve().then(()=>(Zn(),yl));for(let w of m)await h(e,w.id),g(w.id);let b=await ee(p,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(n[3]&&r.method==="DELETE"){let l=n[3],{SessionModel:u}=await Promise.resolve().then(()=>(Fe(),Rn)),p=await new u(e.DB).getSessionsByUser(t.id),f=null;for(let w of p)if(await ee(w.id,t.id)===l){f=w.id;break}if(!f)return new Response("Not Found",{status:404});let{invalidateSession:m}=await Promise.resolve().then(()=>(pe(),Pn));await m(e,f);let h=Le(r.headers.get("Cookie")||""),g=h&&ve(h)?.sid||null,b=g?await ee(g,t.id):null;return await o.record(t.id,"session_revoked",i,c,{reason:"user_revoke",target_session:l},l),f===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 Yl(r,e,t,n,s){let o=new oe(e.DB),i=new q(e.DB),c=n[3];if(c==="status"&&r.method==="GET"){let[a,l]=await Promise.all([i.listByOwner(t.id),o.listByUser(t.id)]),u=null,d=[],p=null;if(a.length>0){let[f,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(`
|
|
463
|
+
`).bind(t.id).first()),u?Response.json({encryptedSk:u.encrypted_sk,iv:u.iv}):new Response("Wrapped key not found for this passkey",{status:404})}if(c==="init"&&r.method==="POST"){let a;try{a=await r.json()}catch{return new Response("Invalid JSON body",{status:400})}let{publicKey:l,passkeyId:u,encryptedSk:d,iv:p,recovery:f}=a;if(!l||!u||!d||!p)return new Response("Missing required fields (publicKey, passkeyId, encryptedSk, iv)",{status:400});let m=await i.getByIdOrCredentialId(u,t.id);if(!m){let b=await i.listByUser(t.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(n.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,n.id,d,p,h)];return f&&f.encryptedSk&&f.iv&&f.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(n.id,f.encryptedSk,f.iv,f.salt,h)),await e.DB.batch(w),nr(n.id),Response.json({success:!0})}if(c==="wrap"&&r.method==="POST"){let a;try{a=await r.json()}catch{return new Response("Invalid JSON body",{status:400})}let{passkeyId:l,encryptedSk:u,iv:d}=a;if(!l||!u||!d)return new Response("Missing required fields (passkeyId, encryptedSk, iv)",{status:400});let p=await i.getByIdOrCredentialId(l,t.id);if(!p){let m=await i.listByUser(t.id);m.length>0&&(p=m[0])}if(!p)return new Response("Passkey not found or unauthorized",{status:403});let f=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(p.id,n.id,u,d,f).run(),Response.json({success:!0})}return r.method==="DELETE"&&(!c||c==="keys")?(await e.DB.batch([e.DB.prepare("DELETE FROM user_log_keys WHERE profile_id = ?").bind(n.id),e.DB.prepare("DELETE FROM user_passkey_wrapped_keys WHERE profile_id = ?").bind(n.id),e.DB.prepare("DELETE FROM user_recovery_wrapped_keys WHERE profile_id = ?").bind(n.id)]),nr(n.id),Response.json({success:!0})):new Response("Not Found",{status:404})}async function Bl(r,e,t,n){let o=new URL(r.url).pathname.split("/").filter(Boolean),i=new q(e.DB);if(o.length===2)return t?Pl(r,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(!Zr.canAccessProfile(t,a))return new Response("Profile Not Found",{status:404});let l=o[3];if(!l||["rotate_key","settings","test"].includes(l))return Cl(r,e,t,a,o,n);switch(l){case"access_points":return kl(r,e,t,c,o,n);case"rules":return Ll(r,e,t,c,o,n);case"lists":return Nl(r,e,t,c,o,n);case"logs":case"analytics":return Ul(r,e,t,a,o,n);case"e2ee":return Ml(r,e,t,a,o,n);default:return new Response("Not Found",{status:404})}}return new Response("Not Found",{status:404})}pe();Se();ge();async function Ce(r,e,t,n){if(e.passkeyAssertion){let o=caches.default,i=await v.get(o,`webauthn_auth_challenge:${r.id}`);if(!i)return{success:!1,error:"Passkey session expired, please try again",reason:"passkey_session_expired"};let c=new oe(t.DB),l=(await c.listByUser(r.id)).find(d=>d.credential_id===e.passkeyAssertion.id);if(!l)return{success:!1,error:"Passkey not found",reason:"passkey_not_found"};let u=new URL(n.url);try{let{signCount:d}=await Ut({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:`${u.protocol}//${u.host}`,expectedRpId:i.rpId,previousSignCount:l.sign_count});return await c.updateUsage(l.id,d),await v.delete(o,`webauthn_auth_challenge:${r.id}`),{success:!0,method:"passkey"}}catch{return{success:!1,error:"Invalid Passkey signature",reason:"invalid_passkey"}}}if(e.totpTokenHash)return!r.totp_enabled||!r.totp_secret?{success:!1,error:"TOTP is not enabled",reason:"totp_not_enabled"}:await es(r.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 Rr(s,r.hashed_password,r.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 r.totp_recovery_keys=="string"?JSON.parse(r.totp_recovery_keys):r.totp_recovery_keys||[]}catch{}return await zr(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 Fl(r,e,t,n,s){let o=new G(e.DB,e),i=new Ue(e.DB),c=n[2];if(c==="me"){if(r.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,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),l):l,d=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),f=await new oe(e.DB).countByUser(t.id),m=!!a?.totp_enabled||f>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=t.role==="admin"?Ne(e.JWT_SECRET)&&!_t(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:f,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"?u:d,jwt_secret_warning:g}),{headers:{"Content-Type":"application/json"}})}if(r.method==="PATCH"){let a=await r.json();try{if(t.isPaused){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})}return await o.updateLocale(t.id,l||"en-US"),new Response(JSON.stringify({success:!0}))}return new Response("session_paused",{status:403})}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||!xt.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==="logs"&&r.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"&&r.method==="POST"||c==="me"&&r.method==="DELETE"){let a=await o.getById(t.id);if(!a)return new Response("User not found",{status:404});let l={};try{r.headers.get("content-type")?.includes("application/json")&&(l=await r.json())}catch{}let u=await Ce(a,l,e,r);if(!u.success)return new Response(u.error||"Authentication failed",{status:400});let{invalidateSession:d}=await Promise.resolve().then(()=>(pe(),Pn)),p=r.headers.get("Cookie")||"",f=Oe(p),m=f&&ve(f)?.sid||null;return m&&await d(e,m),await o.delete(t.id),new Response(JSON.stringify({success:!0}),{headers:{"Set-Cookie":et(),"Content-Type":"application/json"}})}return new Response("Not Found",{status:404})}Se();async function Hl(r,e,t,n,s){let o=new G(e.DB,e),i=new ne(e.DB),c=r.headers.get("CF-Connecting-IP")||"127.0.0.1",a=r.headers.get("User-Agent"),l=n[2],u=t.sessionId?await ee(t.sessionId,t.id):null;if(l==="password"&&r.method==="POST"){let d=await r.json(),{newPassword:p}=d;if(!p||!Rt.test(p))return new Response("Password format error",{status:400});let f=await o.getById(t.id);if(!f)return new Response("User not found",{status:404});let m=await Ce(f,d,e,r);if(!m.success)return await i.record(t.id,"password_change_fail",c,a,{reason:m.reason},u),new Response(m.error||"Authentication failed",{status:400});let h=await ct(p,2);return await o.updatePassword(t.id,h,2),await i.record(t.id,"password_change_success",c,a,{method:m.method},u),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}if(l==="migrate-password"&&r.method==="POST"){let d=await r.json(),{clientHash:p}=d;if(!p)return new Response("Missing clientHash",{status:400});let f=await o.getById(t.id);if(!f)return new Response("User not found",{status:404});let m=await Ce(f,d,e,r);if(!m.success)return await i.record(t.id,"password_change_fail",c,a,{reason:m.reason,flow:"migration"},u),new Response(m.error||"Authentication failed",{status:400});if((f.password_version??1)===1){let h=await ct(p,2);await o.updatePassword(t.id,h,2),await i.record(t.id,"password_change_success",c,a,{method:"migration"},u)}return new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}return new Response("Not Found",{status:404})}Se();async function $l(r,e,t,n,s){let o=new G(e.DB,e),i=new ne(e.DB),c=r.headers.get("CF-Connecting-IP")||"127.0.0.1",a=r.headers.get("User-Agent"),l=n[2],u=t.sessionId?await ee(t.sessionId,t.id):null;if(l==="totp"){let d=n[3];if(d==="setup"&&r.method==="GET"){let p=await o.getById(t.id);if(p?.totp_enabled)return new Response("TOTP is already enabled",{status:409});let f=wl(),m=new URL(r.url).hostname,h=bl(f,p?.username||"user",m);return new Response(JSON.stringify({secret:f,uri:h}),{headers:{"Content-Type":"application/json"}})}if(d==="confirm"&&r.method==="POST"){let{secret:p,totpTokenHash:f,salt:m}=await r.json();if(!p||!f)return new Response("Missing secret or token",{status:400});if(!await es(p,f,m))return new Response("Invalid TOTP code",{status:400});let g=vo(),w=await Promise.all(g.map(async b=>({hash:await Xe(b)})));return await o.updateTOTP(t.id,p,w),await o.updateTOTPSettings(t.id,!0),await i.record(t.id,"totp_setup",c,a,void 0,u),new Response(JSON.stringify({success:!0,recovery_keys:g}),{headers:{"Content-Type":"application/json"}})}if(d==="test"&&r.method==="POST"){let p=await o.getById(t.id);if(!p?.totp_enabled||!p?.totp_secret)return new Response(JSON.stringify({success:!1,message:"TOTP is not enabled"}),{status:400,headers:{"Content-Type":"application/json"}});let{token:f,totpTokenHash:m,salt:h}=await r.json(),g=m||f;return g?await es(p.totp_secret,g,h)?(await i.record(t.id,"totp_verify_success",c,a,{flow:"mfa_test"},u),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})):(await i.record(t.id,"totp_verify_fail",c,a,{flow:"mfa_test"},u),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(d==="settings"&&r.method==="PATCH"){let p=await o.getById(t.id),m=await new oe(e.DB).listByUser(t.id);if(!(!!p?.totp_enabled||m.length>0))return new Response("MFA is not enabled",{status:400});let{skip_password:g}=await r.json();return await o.updateTOTPSettings(t.id,!!g),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}if(!d&&r.method==="DELETE"){let p=await r.json().catch(()=>({})),f=await o.getById(t.id);if(!f)return new Response("User not found",{status:404});let m=await Ce(f,p,e,r);if(!m.success)return await i.record(t.id,"totp_verify_fail",c,a,{reason:m.reason},u),new Response(m.error||"Authentication failed",{status:400});let w=(await new oe(e.DB).listByUser(t.id)).length>0;return await o.removeTOTP(t.id,w),await i.record(t.id,"totp_removed",c,a,{method:m.method},u),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}}if(l==="mfa"&&n[3]==="settings"&&r.method==="PATCH"){let d=await o.getById(t.id),f=await new oe(e.DB).listByUser(t.id);if(!(!!d?.totp_enabled||f.length>0))return new Response("MFA is not enabled",{status:400});let{skip_password:h}=await r.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 Kl(r,e,t,n,s){let o=new G(e.DB,e),i=await o.getById(t.id);if(!i)return new Response("User not found",{status:404});let c=await r.json(),a=await Ce(i,c,e,r);if(!a.success)return new Response(a.error||"Authentication failed",{status:400});if(r.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 r.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})}Se();ge();async function Wl(r,e,t,n,s){let o=new G(e.DB,e),i=new oe(e.DB),c=new ne(e.DB),a=r.headers.get("CF-Connecting-IP")||"127.0.0.1",l=r.headers.get("User-Agent"),u=n[3],d=t.sessionId?await ee(t.sessionId,t.id):null;if(!u&&r.method==="GET"){let p=await i.listByUser(t.id);return new Response(JSON.stringify(p),{headers:{"Content-Type":"application/json"}})}if(u==="auth-options"&&r.method==="POST"){let p=await i.listByUser(t.id);if(p.length===0)return new Response("No passkeys registered",{status:400});let f;try{r.headers.get("content-type")?.includes("application/json")&&(f=(await r.json())?.passkeyId)}catch{}let m=f?p.filter(E=>E.id===f):p;if(m.length===0)return new Response("Target passkey not found",{status:404});let h=ur(),w=new URL(r.url).hostname,b=caches.default;await v.set(b,`webauthn_auth_challenge:${t.id}`,{challenge:h,rpId:w},300);let y={challenge:h,rpId:w,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(u==="test"&&r.method==="POST"){let p=caches.default,f=await v.get(p,`webauthn_auth_challenge:${t.id}`);if(!f)return new Response("Test session expired, please try again",{status:400});let m=await r.json(),h=m.credential||m.passkeyAssertion||m;if(!h||!h.response||!h.id)return new Response("Invalid credential data",{status:400});let w=(await i.listByUser(t.id)).find(y=>y.credential_id===h.id);if(!w)return new Response("Passkey not recognized for this account",{status:404});let b=new URL(r.url);try{let{signCount:y}=await Ut({clientDataJSON:h.response.clientDataJSON,authenticatorData:h.response.authenticatorData,signature:h.response.signature,publicKeySpki:w.public_key,algorithm:w.algorithm,expectedChallenge:f.challenge,expectedOrigin:`${b.protocol}//${b.host}`,expectedRpId:f.rpId,previousSignCount:w.sign_count});return await i.updateUsage(w.id,y),await v.delete(p,`webauthn_auth_challenge:${t.id}`),await c.record(t.id,"passkey_verify_success",a,l,{flow:"mfa_test",name:w.name,id:w.id},d),new Response(JSON.stringify({success:!0,passkey:{id:w.id,name:w.name}}),{headers:{"Content-Type":"application/json"}})}catch(y){return await c.record(t.id,"passkey_verify_fail",a,l,{flow:"mfa_test",name:w.name,id:w.id,error:y.message||"failed"},d),console.warn("[Passkey Test] Verification failed:",y.message||y),new Response(y.message||"Passkey verification failed",{status:400})}}if(u==="register"&&n[4]==="options"&&r.method==="POST"){let p=await i.listByUser(t.id),f=ur(),h=new URL(r.url).hostname,g=caches.default;await v.set(g,`webauthn_reg_challenge:${t.id}`,{challenge:f,rpId:h},300);let b=(await o.getById(t.id))?.username||t.username||"",y=b?`${b} (${h})`:h,E={challenge:f,rp:{name:h,id:h},user:{id:gt(new TextEncoder().encode(t.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:p.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(u==="register"&&n[4]==="verify"&&r.method==="POST"){let p=caches.default,f=await v.get(p,`webauthn_reg_challenge:${t.id}`);if(!f)return new Response("Registration session expired, please try again",{status:400});await v.delete(p,`webauthn_reg_challenge:${t.id}`);let m=await r.json(),{name:h,credential:g}=m;if(!g||!g.response)return new Response("Invalid credential data",{status:400});let w=new URL(r.url),b=`${w.protocol}//${w.host}`;try{let y=await Sl({clientDataJSON:g.response.clientDataJSON,attestationObject:g.response.attestationObject,expectedChallenge:f.challenge,expectedOrigin:b,expectedRpId:f.rpId});if(await i.getByCredentialId(y.credentialId))return new Response("This passkey is already registered",{status:409});let _=(h||"").trim();if(!hi.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 R=await o.getById(t.id),D=[];if(R){let P=!1;if(R.totp_recovery_keys)try{let k=typeof R.totp_recovery_keys=="string"?JSON.parse(R.totp_recovery_keys):R.totp_recovery_keys;Array.isArray(k)&&k.length>0&&(P=!0)}catch{R.totp_recovery_keys.length>0&&(P=!0)}else R.totp_recovery_keys_encrypted&&(P=!0);if(!P){let k=vo(),N=await Promise.all(k.map(async V=>({hash:await Xe(V)})));await o.updateRecoveryKeys(t.id,N),D=k}}return await c.record(t.id,"passkey_registered",a,l,{name:_},d),new Response(JSON.stringify({...x,recovery_keys:D.length>0?D: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(u&&r.method==="PATCH"){let p=u,{name:f}=await r.json(),m=(f||"").trim();if(!m||!hi.test(m))return new Response("Invalid Passkey name format",{status:400});if(!await i.getById(p,t.id))return new Response("Passkey not found",{status:404});let g=await i.updateName(p,t.id,m);return new Response(JSON.stringify({success:g}),{headers:{"Content-Type":"application/json"}})}if(u&&r.method==="DELETE"){let p=u,f=await i.getById(p,t.id);if(!f)return new Response("Passkey not found",{status:404});let m=await o.getById(t.id);if(!m)return new Response("User not found",{status:404});let h={};try{r.headers.get("content-type")?.includes("application/json")&&(h=await r.json())}catch{}let g=await Ce(m,h,e,r);return g.success?(await i.delete(p,t.id),await c.record(t.id,"passkey_deleted",a,l,{name:f.name,method:g.method},d),await i.countByUser(t.id)===0&&!m?.totp_enabled&&await o.updateTOTPSettings(t.id,!1),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})):(await c.record(t.id,"passkey_verify_fail",a,l,{reason:g.reason},d),new Response(g.error||"Authentication failed",{status:400}))}return new Response("Not Found",{status:404})}Se();async function jl(r,e,t,n,s){let o=new G(e.DB,e),i=new ne(e.DB),c=r.headers.get("CF-Connecting-IP")||"127.0.0.1",a=r.headers.get("User-Agent"),l=n[3],u=t.sessionId?await ee(t.sessionId,t.id):null;if(l==="rotate"&&r.method==="POST"){let d=await r.json(),p=await o.getById(t.id);if(!p)return new Response("User not found",{status:404});let f=await Ce(p,d,e,r);if(!f.success)return new Response(f.error||"Authentication failed",{status:400});if(f.method!=="passkey"&&f.method!=="recovery_key")return new Response("Recovery Key rotation only permits authentication via existing Passkey or original Recovery Key",{status:403});let m=lr(),g=[{hash:await Xe(m)}];return await o.updateRecoveryKeys(t.id,g),await i.record(t.id,"recovery_key_rotated",c,a,{method:f.method},u),new Response(JSON.stringify({success:!0,recovery_key:m}),{headers:{"Content-Type":"application/json"}})}return new Response("Not Found",{status:404})}async function Vl(r,e,t,n,s){switch(n[2]){case"password":case"migrate-password":return Hl(r,e,t,n,s);case"totp":case"mfa":return $l(r,e,t,n,s);case"pin":return Kl(r,e,t,n,s);case"passkeys":return Wl(r,e,t,n,s);case"recovery-keys":return jl(r,e,t,n,s);default:return new Response("Not Found",{status:404})}}pe();async function Jl(r,e,t,n,s){let o=new ne(e.DB),i=r.headers.get("CF-Connecting-IP")||"127.0.0.1",c=r.headers.get("User-Agent"),a=n[2];if(a==="activity"&&r.method==="GET"){let l=new URL(r.url).searchParams,u=Math.min(parseInt(l.get("limit")||"20",10),50),d=l.get("before")?parseInt(l.get("before"),10):void 0,p=await o.listByUser(t.id,u,d);return new Response(JSON.stringify(p),{headers:{"Content-Type":"application/json"}})}if(a==="sessions"){if(!n[3]&&r.method==="GET"){let{SessionModel:l}=await Promise.resolve().then(()=>(He(),Rn)),d=await new l(e.DB).getSessionsByUser(t.id),p=r.headers.get("Cookie")||"",f=Oe(p),m=f&&ve(f)?.sid||null,h=await Promise.all(d.map(async g=>({...g,id:await ee(g.id,t.id),is_current:g.id===m})));return new Response(JSON.stringify(h),{headers:{"Content-Type":"application/json"}})}if(n[3]==="others"&&r.method==="DELETE"){let{SessionModel:l}=await Promise.resolve().then(()=>(He(),Rn)),u=new l(e.DB),d=Oe(r.headers.get("Cookie")||""),p=d&&ve(d)?.sid||null;if(!p)return new Response("Current session not found",{status:400});let m=(await u.getSessionsByUser(t.id)).filter(b=>b.id!==p),{invalidateSession:h}=await Promise.resolve().then(()=>(pe(),Pn)),{invalidateAuthUserCache:g}=await Promise.resolve().then(()=>(Zn(),gl));for(let b of m)await h(e,b.id),g(b.id);let w=await ee(p,t.id);return await o.record(t.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(n[3]&&r.method==="DELETE"){let l=n[3],{SessionModel:u}=await Promise.resolve().then(()=>(He(),Rn)),p=await new u(e.DB).getSessionsByUser(t.id),f=null;for(let b of p)if(await ee(b.id,t.id)===l){f=b.id;break}if(!f)return new Response("Not Found",{status:404});let{invalidateSession:m}=await Promise.resolve().then(()=>(pe(),Pn));await m(e,f);let h=Oe(r.headers.get("Cookie")||""),g=h&&ve(h)?.sid||null,w=g?await ee(g,t.id):null;return await o.record(t.id,"session_revoked",i,c,{reason:"user_revoke",target_session:l},l),f===g?new Response(JSON.stringify({success:!0,is_current:!0}),{headers:{"Set-Cookie":et(),"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 Gl(r,e,t,n,s){let o=new oe(e.DB),i=new q(e.DB),c=n[3];if(c==="status"&&r.method==="GET"){let[a,l]=await Promise.all([i.listByOwner(t.id),o.listByUser(t.id)]),u=null,d=[],p=null;if(a.length>0){let[f,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(`
|
|
464
464
|
SELECT upwk.passkey_id
|
|
465
465
|
FROM user_passkey_wrapped_keys upwk
|
|
466
466
|
JOIN passkeys pk ON upwk.passkey_id = pk.id
|
|
@@ -471,11 +471,11 @@ echo "Please change your system DNS to 127.0.0.1"
|
|
|
471
471
|
JOIN passkeys pk ON upwk.passkey_id = pk.id
|
|
472
472
|
WHERE pk.user_id = ?
|
|
473
473
|
LIMIT 1
|
|
474
|
-
`).bind(t.id).first()),u?Response.json({encryptedSk:u.encrypted_sk,iv:u.iv}):new Response("Wrapped key not found for this passkey",{status:404})}if(c==="recovery-wrapped-key"&&r.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"&&r.method==="POST"){let a;try{a=await r.json()}catch{return new Response("Invalid JSON body",{status:400})}let{publicKey:l,passkeyId:u,encryptedSk:d,iv:p,recovery:f}=a;if(!l||!u&&!f)return new Response("Missing required fields (publicKey and either passkey or recovery)",{status:400});let m=null;if(u&&(m=await o.getByIdOrCredentialId(u,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&&d&&p&&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,d,p,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)),f&&f.encryptedSk&&f.iv&&f.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,f.encryptedSk,f.iv,f.salt,g))}w.length>0&&await e.DB.batch(w);for(let E of h)nr(E.id);return Response.json({success:!0})}if(c==="wrap"&&r.method==="POST"){let a;try{a=await r.json()}catch{return new Response("Invalid JSON body",{status:400})}let{passkeyId:l,encryptedSk:u,iv:d}=a;if(!l||!u||!d)return new Response("Missing required fields (passkeyId, encryptedSk, iv)",{status:400});let p=await o.getByIdOrCredentialId(l,t.id);if(!p){let g=await o.listByUser(t.id);g.length>0&&(p=g[0])}if(!p)return new Response("Passkey not found or unauthorized",{status:403});let f=await i.listByOwner(t.id),m=f.length>0?f[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(p.id,m,u,d,h).run(),Response.json({success:!0})}if(c==="wrap-recovery"&&r.method==="POST"){let a;try{a=await r.json()}catch{return new Response("Invalid JSON body",{status:400})}let{encryptedSk:l,iv:u,salt:d}=a;if(!l||!u||!d)return new Response("Missing required fields (encryptedSk, iv, salt)",{status:400});let p=await i.listByOwner(t.id),f=Math.floor(Date.now()/1e3),m=[];for(let h of p)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,u,d,f));return m.length>0&&await e.DB.batch(m),Response.json({success:!0})}if(c==="enable"&&r.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)nr(l.id);return Response.json({success:!0,enabled:!0})}if(r.method==="DELETE"&&(!c||c==="keys")){let l=new URL(r.url).searchParams.get("purge")==="true",u=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 d of u)nr(d.id);return Response.json({success:!0,purged:l,enabled:!1})}return new Response("Not Found",{status:404})}async function Xl(r,e,t,n,s){let o=n[2];return o==="me"||o==="delete"||o==="logs"?Hl(r,e,t,n,s):o==="password"||o==="totp"||o==="passkeys"||o==="mfa"||o==="migrate-password"||o==="pin"||o==="recovery-keys"?Jl(r,e,t,n,s):o==="activity"||o==="sessions"?Gl(r,e,t,n,s):o==="e2ee"?Yl(r,e,t,n,s):new Response("Not Found",{status:404})}pe();Se();async function zl(r,e,t,n,s){let o=new G(e.DB,e),i=new q(e.DB);if(n[2]==="users"){if(r.method==="GET"){let c=await o.listAll();return new Response(JSON.stringify(c),{headers:{"Content-Type":"application/json"}})}if(r.method==="POST"){let{username:c,password:a,role:l}=await r.json();if(!c||!xt.test(c))return new Response("Invalid username format",{status:400});if(!a||!Rt.test(a))return new Response("Password format error",{status:400});let u=await at(a,2),d=j(15);try{return await o.create({id:d,username:c,passwordHash:u,role:l||"user",passwordVersion:2}),new Response(JSON.stringify({id:d}),{status:201})}catch(p){return new Response(p.message,{status:400})}}if(r.method==="DELETE"&&n[3]){let c=n[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(n[2]==="settings"){let c=new de(e.DB);if(r.method==="GET"){let a=await c.getAll();return delete a.jwt_secret,new Response(JSON.stringify(a),{headers:{"Content-Type":"application/json"}})}if(r.method==="PATCH"){let a=await r.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 Ql(r,e,t,n){let o=new URL(r.url).pathname.split("/").filter(Boolean);return o[1]==="account"?Xl(r,e,t,o,n):o[1]==="admin"?Zr.isAdmin(t)?zl(r,e,t,o,n):new Response("Forbidden",{status:403}):new Response("Not Found",{status:404})}ge();async function Zl(r,e){let t=new URL(r.url),n=typeof caches<"u"?caches.default:null;if(t.pathname==="/api/clientinfo"){let s=r.headers.get("CF-Connecting-IP")||"127.0.0.1",o=await v.get(n,`active_dns:${s}`),i=r.cf,c=i?.country||r.headers.get("CF-IPCountry")||"",a=c,l=i?.region||r.headers.get("CF-Region")||"",u=i?.city||r.headers.get("CF-IPCity")||"",d=i?.timezone||r.headers.get("CF-Timezone")||"",p=i?.asn?Number(i.asn):r.headers.get("CF-ASN")?Number(r.headers.get("CF-ASN")):0,f=i?.asOrganization||r.headers.get("CF-AS-Org")||"";if(!c||c==="UNKNOWN"||c==="UN"||c==="XX")if(!tt(s))c="Private Network",a="LAN",l="LAN",u="Local",d="UNKNOWN",f="Private Network";else try{let h=await Ln(s);if(h&&(c=h.country||h.country_code||"UNKNOWN",a=h.country_code||"UNKNOWN",l=h.region||"UNKNOWN",u=h.city||"UNKNOWN",d=h.timezone||"UNKNOWN",f=h.org||h.isp||"UNKNOWN",!p&&h.as)){let g=h.as.match(/^AS(\d+)/i);g&&(p=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:u||"UNKNOWN",timezone:d||"UNKNOWN",asn:p||0,asOrganization:f||"UNKNOWN",connectedProfileId:o||null,substituteDomain:e.SUBSTITUTE_DOMAIN||on,dotDomain:e.SERVERFULL_DOT_DOMAIN||e.DOT_DOMAIN||null,isServerfull:m,mode:m?"serverfull":"cloudflare"}),{headers:{"Content-Type":"application/json"}})}if(t.pathname==="/api/substitute"){let s=e.SUBSTITUTE_DOMAIN||on,o=null,i=null,c=async a=>{let l=["https://cloudflare-dns.com/dns-query","https://1.1.1.1/dns-query"];for(let u of l)try{let d=await fetch(`${u}?name=${s}&type=${a}`,{headers:{Accept:"application/dns-json"},signal:AbortSignal.timeout(3e3)});if(d.ok){let p=await d.json();if(p?.Answer?.length>0){let f=p.Answer.find(m=>m.type===(a==="A"?1:28));if(f?.data)return f.data}}}catch(d){console.error(`[Substitute Resolve] Failed resolving ${a} via ${u}:`,d)}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=is;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=as;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=Ta(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=r.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{1F6DC}"}}),{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 u=await l.json();if(Array.isArray(u?.Answer)&&u.Answer.length>0){let d=i==="A"?1:28;return u.Answer.filter(p=>p.type===d&&typeof p.data=="string").map(p=>p.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,u]=await Promise.allSettled([a.resolve4(s),a.resolve6(s)]);l.status==="fulfilled"&&Array.isArray(l.value)&&(i=l.value),u.status==="fulfilled"&&Array.isArray(u.value)&&(c=u.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();var rs=0;async function ql(r,e,t){try{let n=typeof caches<"u"?caches.default:null,s=Math.floor(Date.now()/1e3),o=!0;rs&&s-rs<3600&&(o=!1);let i="cron:last_cleanup_timestamp",c=new de(e.DB);if(o){let a=await v.get(n,i);a&&s-a<3600&&(rs=a,o=!1)}if(o)try{let a=await c.get("cron_last_cleanup_timestamp");if(a){let l=parseInt(a,10)||0;s-l<3600&&(rs=l,o=!1)}}catch(a){console.warn("[Cron] Failed to read persistent cleanup timestamp:",a)}if(o){rs=s;try{let a=new G(e.DB,e),{clearedProfiles:l,deletedUsers:u}=await a.applyInactivityPolicy(s);(l>0||u>0)&&console.log(`[Cron] Inactivity cleanup: cleared ${l} profile(s), deleted ${u} user(s).`)}catch(a){console.error("[Cron] Inactivity policy execution failed:",a)}try{let a=new Ie(e.DB),l=e.MAX_LOG_RETENTION_DAYS!==void 0&&e.MAX_LOG_RETENTION_DAYS!==""?Number(e.MAX_LOG_RETENTION_DAYS):30,u=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 a.cleanupGlobal(l,u,d)}catch(a){console.error("[Cron] Global log cleanup failed:",a)}try{let{SessionModel:a}=await Promise.resolve().then(()=>(Fe(),Rn)),l=new a(e.DB),{deletedSessions:u,deletedPending:d}=await l.deleteExpiredSessions(s);(u>0||d>0)&&console.log(`[Cron] Purged ${u} expired session(s) and ${d} pending token(s).`)}catch(a){console.error("[Cron] Session cleanup failed:",a)}await v.set(n,i,s,3600);try{await c.set("cron_last_cleanup_timestamp",String(s))}catch(a){console.warn("[Cron] Failed to persist cleanup timestamp:",a)}console.log("[Cron] Cleanup phase completed at",new Date().toISOString())}try{await ni(e.DB)}catch(a){console.error("[Cron] Cloudflare IP range sync failed:",a)}try{let a="cron:last_idle_sync_check",l=Number(e.SYNC_IDLE_INTERVAL_SEC)||1800,u=await v.get(n,a);if(!!!(u&&s-u<l)){let p=Number(e.SYNC_PROFILE_INTERVAL_SEC)||86400,f=s-p,m=new q(e.DB),h=Number(e.SYNC_BATCH_SIZE)||1,g=await m.getSyncTargets(f,h);if(g.length>0){await v.delete(n,a);for(let b of g)try{await qr(b.id,e,t)}catch(w){let y=w instanceof Error?w.message:String(w);console.error(`[Cron] Sync failed for profile ${b.id}:`,y)}console.log(`[Cron] Sync: processed ${g.length} profile(s).`)}else await v.set(n,a,s,l)}}catch(a){let l=a instanceof Error?a.message:String(a);console.error("[Cron] Sync phase failed:",l)}}catch(n){let s=n instanceof Error?n.message:String(n);console.error("[Cron] Critical Failure:",s)}}async function eu(r,e,t){let n=new Request(new URL("https://obex.local/world-110m-v2.json"),r),s=caches.default,o=await s.match(n);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(n,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}He();ge();var Oo={async fetch(r,e,t){v.setOrigin(new URL(r.url).origin);let n=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||e.SERVERFULL_DB_PATH!==void 0,s=cn(e,n);s==="Turso"&&hr(e)&&(e.DB=Jo(e));let o=new Uint8Array(16);crypto.getRandomValues(o);let i=Array.from(o).map(d=>d.toString(16).padStart(2,"0")).join(""),c=null,l=await(async()=>{let d=new URL(r.url);if(d.pathname==="/world-110m.json")return eu(r,e,t);if(d.pathname.startsWith("/api/")){let h=!1,g="";if(s==="Turso")(!hr(e)||!e.DB)&&(h=!0,g="DATABASE_SERVICE is set to Turso, but TURSO_DATABASE_URL or TURSO_AUTH_TOKEN is not configured.");else if(s==="File")n?e.DB||(h=!0,g="Database file is missing. Please restart the service or verify file permissions."):(h=!0,g="DATABASE_SERVICE='File' is not supported in Cloudflare Workers. Please configure D1 database binding or use DATABASE_SERVICE='Turso'.");else if(n)h=!0,g="DATABASE_SERVICE='D1' is designed for Cloudflare Workers. In Serverfull mode, please set DATABASE_SERVICE='File' or 'Turso'.";else try{h=!e.DB}catch{h=!0}let b=!Oe(e.JWT_SECRET);if(h||b)return new Response(JSON.stringify({error:"configuration_error",isDbMissing:h,isJwtSecretMissing:b,databaseService:s,message:g||"DNS Worker is not fully configured. Please configure the database and JWT_SECRET secret variable."}),{status:503,headers:{"Content-Type":"application/json","Access-Control-Allow-Origin":"*"}});c=await ta(r,e,t);let w=["/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/substitute","/api/resolve","/api/geoip"].includes(d.pathname)||d.pathname.startsWith("/api/icon/")||d.pathname.startsWith("/api/presets/")||d.pathname.startsWith("/api/auth/forgot-password");return!c&&!w?new Response("Unauthorized",{status:401}):c&&c.isPaused&&!(["/api/auth/unlock-session","/api/auth/logout","/api/auth/refresh"].includes(d.pathname)||d.pathname==="/api/account/me"&&r.method==="PATCH")?new Response("session_paused",{status:403}):c&&["POST","PUT","PATCH","DELETE"].includes(r.method)&&!w&&!ra(r)?new Response("CSRF validation failed",{status:403}):d.pathname.startsWith("/api/auth/")?Pl(r,e):d.pathname==="/api/clientinfo"||d.pathname==="/api/substitute"||d.pathname==="/api/resolve"||d.pathname==="/api/geoip"||d.pathname.startsWith("/api/presets/")||d.pathname.startsWith("/api/icon/")?Zl(r,e):d.pathname.startsWith("/api/profiles")?Fl(r,e,c,t):d.pathname.startsWith("/api/account")||d.pathname.startsWith("/api/admin")?Ql(r,e,c,t):new Response("API Not Found",{status:404})}if(d.pathname==="/setup.sh"){let h=d.searchParams.get("key");if(!h||!Vt.test(h))return new Response("Missing or invalid key parameter",{status:400});let g=gl(d.origin,h);return new Response(g,{headers:{"Content-Type":"text/plain; charset=utf-8","Cache-Control":"no-cache"}})}let p=d.pathname.slice(1),f=Vt.test(p),m=r.method==="POST"||d.searchParams.has("dns")||r.headers.get("accept")?.includes("dns-message");if(f&&(m||r.method==="OPTIONS"))return r.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"}}):fl(r,e,t,p);try{let h=await e.ASSETS.fetch(r);if(h.status===404&&!d.pathname.startsWith("/assets/")&&(r.method==="GET"||r.method==="HEAD")&&(h=await e.ASSETS.fetch(new Request(d.origin+"/",{method:r.method,headers:r.headers}))),d.pathname.endsWith(".wasm")){let b=new Headers(h.headers);return b.set("Content-Type","application/wasm"),b.set("Cross-Origin-Resource-Policy","same-origin"),new Response(h.body,{status:h.status,statusText:h.statusText,headers:b})}if((h.headers.get("Content-Type")||"").includes("text/html")){let b=!1;s==="Turso"?b=!hr(e)||!e.DB:s==="File"?b=!n||!e.DB:b=n||!e.DB;let w=!Oe(e.JWT_SECRET),y="{}";try{y=JSON.stringify({nonce:i,isDbMissing:b,isJwtSecretMissing:w,isServerfull:n,databaseService:s,isTurso:s==="Turso",mode:n?"serverfull":"cloudflare"})}catch{}return new HTMLRewriter().on("head",{element(E){E.prepend(`<script nonce="${i}">window.DNS_WORKER_CONFIG = ${y};</script>`,{html:!0})}}).transform(h)}return h}catch{return new Response("Asset Fetch Error",{status:500})}})(),u=c;if(u&&!xr(r.headers.get("Cookie"))){let d=u.sessionId?.startsWith("k_");try{let p=j(32);l.headers.append("Set-Cookie",ct(p,e,d))}catch{let f=new Headers(l.headers),m=j(32);f.append("Set-Cookie",ct(m,e,d)),l=new Response(l.body,{status:l.status,statusText:l.statusText,headers:f})}}if(l.headers.get("Content-Type")?.includes("application/dns-message")){let d=new Headers(l.headers);return d.set("Access-Control-Allow-Origin","*"),d.set("Access-Control-Allow-Methods","GET, POST, OPTIONS"),d.set("Access-Control-Allow-Headers","Content-Type, Accept"),new Response(l.body,{status:l.status,statusText:l.statusText,headers:d})}return ea(l,i)},async scheduled(r,e,t){e.SUBSTITUTE_DOMAIN&&v.setOrigin(`https://${e.SUBSTITUTE_DOMAIN}`),cn(e,!1)==="Turso"&&hr(e)&&(e.DB=Jo(e)),await ql(r,e,t)}};function No(r){if(!r||typeof r!="string")return null;let e=r.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,n]=e.split(":");n&&/^\d+$/.test(n)&&it(t)&&(e=t)}return e.startsWith("::ffff:")&&(e=e.substring(7)),it(e)||$t(e)?e:null}function Dp(r,e){return e?(Array.isArray(e)?e:e.split(",").map(n=>n.trim()).filter(Boolean)).includes(r):!1}function tu(r,e,t){let n=No(e);if(n&&tt(n)&&!Dp(n,t))return n;let s=No(r.get("CF-Connecting-IP"));if(s)return s;let o=No(r.get("X-Real-IP"));if(o)return o;let i=r.get("X-Forwarded-For");if(i){let c=i.split(",");for(let a of c){let l=No(a);if(l)return l}}return n||"127.0.0.1"}function aa(r,e,t,n,s){return async(o,i)=>{try{let c=o.headers["x-forwarded-proto"]?.toLowerCase(),a=c||e;if(e==="http"&&s?.enabled&&c!=="https"){let _=(o.headers.host||`${t}:${n}`).trim().replace(/:\d+$/,""),S=s.httpsPort===443||s.httpsPort===0?"":`:${s.httpsPort}`,x=`https://${_}${S}${o.url||"/"}`;i.statusCode=o.method==="GET"||o.method==="HEAD"?301:307,i.setHeader("Location",x),i.setHeader("Connection","close"),i.setHeader("Content-Type","text/plain; charset=utf-8"),i.end(`Redirecting to ${x}`);return}let l=o.headers.host||`${t}:${n}`,u=new URL(o.url||"/",`${a}://${l}`),d=new Headers;for(let[E,_]of Object.entries(o.headers))_&&(Array.isArray(_)?_.forEach(S=>d.append(E,S)):d.set(E,String(_)));let p=tu(d,o.socket.remoteAddress,r.TRUSTED_PROXIES);d.set("CF-Connecting-IP",p);let f=d.get("CF-IPLatitude");(!f||f.trim()==="")&&d.set("CF-IPLatitude","0.0");let m=d.get("CF-IPLongitude");(!m||m.trim()==="")&&d.set("CF-IPLongitude","0.0");let h=null;if(o.method!=="GET"&&o.method!=="HEAD"){let E=[];for await(let _ of o)E.push(typeof _=="string"?ru.from(_):_);h=ru.concat(E)}let g=new Request(u.toString(),{method:o.method,headers:d,body:h,duplex:"half"}),b={waitUntil(E){E.catch(_=>console.error(`[${e.toUpperCase()} Background Task Error]:`,_))},passThroughOnException(){}},w=await Oo.fetch(g,r,b);i.statusCode=w.status,i.statusMessage=w.statusText;let y=typeof w.headers.getSetCookie=="function"?w.headers.getSetCookie():[];if(y.length===0&&w.headers.has("set-cookie")){let E=w.headers.get("set-cookie");E&&(y=[E])}if(w.headers.forEach((E,_)=>{let S=_.toLowerCase();S!=="set-cookie"&&(e==="https"&&S==="alt-svc"?i.setHeader("Alt-Svc",`h3=":${n}"; ma=86400, h3-29=":${n}"; ma=86400`):i.setHeader(_,E))}),y.length>0){let _=a==="http"?y.map(S=>S.replace(/;\s*Secure\b/gi,"")):y;i.setHeader("Set-Cookie",_)}if(e==="https"&&!i.hasHeader("Alt-Svc")&&i.setHeader("Alt-Svc",`h3=":${n}"; ma=86400, h3-29=":${n}"; ma=86400`),w.body){let E=w.body.getReader();for(;;){let{done:_,value:S}=await E.read();if(_)break;i.write(S)}}i.end()}catch(c){console.error(`[${e.toUpperCase()} Server] Request processing failed:`,c),i.headersSent||(i.statusCode=500,i.setHeader("Content-Type","application/json"),i.end(JSON.stringify({error:"Internal Server Error"})))}}}var Io=class{constructor(e){this.options=e;qi(this.options.env,this.options.staticDir)}options;server=null;isRunning=!1;start(){return new Promise((e,t)=>{let{port:n,host:s,env:o,httpsRedirect:i}=this.options,c=aa(o,"http",s,n,i);this.server=vp.createServer(c),this.server.keepAliveTimeout=65e3,this.server.headersTimeout=66e3,this.server.on("connection",l=>{l.setNoDelay(!0)});let a=l=>{this.server=null,console.error(ar({serviceName:"Web Dashboard & DoH (HTTP)",protocol:"HTTP",port:n,err:l,alternateOption:`--http-port <port> (e.g. --http-port ${n+1})`})),t(l)};this.server.once("error",a),this.server.listen(n,s,()=>{this.server?.removeListener("error",a),this.server?.on("error",u=>{console.error("[HTTP Server] Runtime error:",u)}),this.isRunning=!0;let l=i?.enabled?` (Auto-redirecting to HTTPS on port ${i.httpsPort})`:"";console.log(`[HTTP Server] Web Dashboard & DoH listening on http://${s}:${n}${l}`),e()})})}stop(){return new Promise(e=>{this.server&&this.isRunning?this.server.close(()=>{this.isRunning=!1,console.log("[HTTP Server] Service stopped."),e()}):e()})}},Uo=class{constructor(e){this.options=e;qi(this.options.env,this.options.staticDir)}options;server=null;isRunning=!1;start(){return new Promise((e,t)=>{let{port:n,host:s,certPath:o,keyPath:i,env:c}=this.options;try{let a=nu.readFileSync(o),l=nu.readFileSync(i),u=aa(c,"https",s,n);this.server=Pp.createServer({cert:a,key:l},u),this.server.keepAliveTimeout=65e3,this.server.headersTimeout=66e3,this.server.on("connection",p=>{p.setNoDelay(!0)});let d=p=>{this.server=null,console.error(ar({serviceName:"Web Dashboard & DoH (HTTPS)",protocol:"HTTPS",port:n,err:p,alternateOption:`--https-port <port> (e.g. --https-port ${n+1})`})),t(p)};this.server.once("error",d),this.server.listen(n,s,()=>{this.server?.removeListener("error",d),this.server?.on("error",p=>{console.error("[HTTPS Server] Runtime error:",p)}),this.isRunning=!0,console.log(`[HTTPS Server] Web Dashboard & DoH listening on https://${s}:${n}`),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()})}};He();import Kp from"node:path";import{parseArgs as Wp}from"node:util";He();import Cp from"node:net";import kp from"node:dgram";function Mo(r,e,t=300){return new Promise(n=>{let s=new Cp.Socket,o=!1,i=a=>{if(!o){o=!0;try{s.destroy()}catch{}n(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(r,c)}catch{i("free")}})}function su(r,e){return new Promise(t=>{let n=kp.createSocket("udp4"),s=!1,o=i=>{if(!s){s=!0;try{n.close()}catch{}t(i)}};n.once("error",i=>{let c=i?.code;o(c==="EADDRINUSE"?"active":"free")});try{n.bind(r,e,()=>{o("free")})}catch{o("active")}})}import ou from"node:fs";import{DatabaseSync as Lp}from"node:sqlite";function iu(r){if(!ou.existsSync(r))return{exists:!1,statusText:"Not Initialized (File does not exist yet; created on first start)"};try{let e=ou.statSync(r),t=e.size>1024*1024?`${(e.size/(1024*1024)).toFixed(2)} MB`:`${(e.size/1024).toFixed(1)} KB`,n=0,s=0,o=0;try{let c=new Lp(r,{readOnly:!0}),a=c.prepare("SELECT count(*) as cnt FROM sqlite_master WHERE type='table' AND name='d1_migrations'").get();a&&a.cnt>0&&(n=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 u=c.prepare("SELECT count(*) as cnt FROM sqlite_master WHERE type='table' AND name='profiles'").get();u&&u.cnt>0&&(o=c.prepare("SELECT count(*) as count FROM profiles").get()?.count||0),c.close()}catch{}let i=[t,n>0?`${n} migrations`:null,s>0?`${s} user(s)`:null,o>0?`${o} profile(s)`:null].filter(Boolean).join(", ");return{exists:!0,sizeFormatted:t,migrationsCount:n,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 au(r,e){try{let t=ln(r,e),n=await ga(t),s=0,o=0;try{s=(await t.prepare("SELECT count(*) as count FROM users").first())?.count||0,o=(await t.prepare("SELECT count(*) as count FROM profiles").first())?.count||0}catch{}let i=[n.count>0?`${n.count} migrations`:null,s>0?`${s} user(s)`:null,o>0?`${o} profile(s)`:null].filter(Boolean).join(", ");return{exists:!0,migrationsCount:n.count,usersCount:s,profilesCount:o,statusText:`Ready (Connected${i?`: ${i}`:""})`}}catch(t){return{exists:!1,statusText:`Connection Failed (${t instanceof Error?t.message:String(t)})`}}}async function cu(r,e){let t=Yr(r.tlsCertPath,r.tlsKeyPath),n=!r.disableHttps&&t.configured&&t.filesExist,s=r.databaseService==="Turso",o=s?r.tursoDatabaseUrl&&r.tursoAuthToken?au(r.tursoDatabaseUrl,r.tursoAuthToken):Promise.resolve({exists:!1,statusText:"Configuration Error (TURSO_DATABASE_URL or TURSO_AUTH_TOKEN missing)"}):Promise.resolve(iu(r.dbPath)),[i,c,a,l,u]=await Promise.all([Mo(r.httpPort,r.host),n?Mo(r.httpsPort,r.host):Promise.resolve("disabled"),r.disableUdp?Promise.resolve("disabled"):su(r.udpPort,r.host),r.disableDot?Promise.resolve("disabled"):Mo(r.dotPort,r.host),o]),d="Default (Insecure fallback, please configure JWT_SECRET)";Oe(e)&&(d=_t(e)?"Configured (Strong, >= 32 characters)":"Configured (Warning: Shorter than 32 characters)");let p=i==="active"?or(r.httpPort,"TCP"):null,f=p?`: ${ir(p)}`:"",m=i==="active"?`http://${r.host}:${r.httpPort} [Active / Listening${f}]`:`http://${r.host}:${r.httpPort} [Stopped / Port Available]`,h="";if(r.disableHttps)h="Disabled (--disable-https)";else if(!t.configured)h=`https://${r.host}:${r.httpsPort} [Disabled - TLS Certificates Not Configured]`;else if(!t.filesExist)h=`https://${r.host}:${r.httpsPort} [Warning - TLS Certificate Files Missing]`;else if(c==="active"){let A=or(r.httpsPort,"TCP"),C=A?`: ${ir(A)}`:"";h=`https://${r.host}:${r.httpsPort} [Active / Listening${C}]`}else h=`https://${r.host}:${r.httpsPort} [Stopped / Port Available]`;let g=!r.disableUdp&&a==="active"?or(r.udpPort,"UDP"):null,b=g?`: ${ir(g)}`:"",w=r.disableUdp?"Disabled (--disable-udp)":a==="active"?`udp://${r.host}:${r.udpPort} [Active / In Use${b}]`:`udp://${r.host}:${r.udpPort} [Stopped / Port Available]`,y="",E=r.dotDomain?` (${r.dotDomain})`:"";if(r.disableDot)y="Disabled (--disable-dot)";else if(!t.configured)y=`tls://${r.host}:${r.dotPort}${E} [Disabled - TLS Certificates Not Configured]`;else if(!t.filesExist)y=`tls://${r.host}:${r.dotPort}${E} [Warning - TLS Certificate Files Missing]`;else if(!t.isWildcard)y=`tls://${r.host}:${r.dotPort}${E} [Paused - Requires Wildcard Certificate (*.domain)]`;else if(l==="active"){let A=or(r.dotPort,"TCP"),C=A?`: ${ir(A)}`:"";y=`tls://${r.host}:${r.dotPort}${E} [Active / Listening${C}]`}else y=`tls://${r.host}:${r.dotPort}${E} [Stopped / Port Available]`;let _=r.defaultProfileKey?`Explicit (${r.defaultProfileKey})`:"Auto (Database default profile)",S=xe({title:"DNS Worker Runtime Status (Serverfull Mode)",borderChar:"=",bullet:"\u2022 "}),x=Ge({title:`
|
|
475
|
-
Service Transports:`,items:[{label:"Web Dashboard (HTTP)",value:m},{label:"Web Dashboard (HTTPS)",value:h},{label:"Classic UDP DNS",value:
|
|
476
|
-
Database & Storage:`,items:P}),N="Not Configured (HTTP only, HTTPS & DoT disabled)";if(t.configured)if(!t.filesExist)N="Configured [Files Missing]";else if(t.error)N=`Configured [Invalid Certificate: ${t.error}]`;else{let A=t.isWildcard?"Wildcard (*.domain)":"Single Domain",C=t.expiresAt?t.expiresAt.toISOString().split("T")[0]:"Unknown";N=`Valid (${A}, Expires: ${C})`}let V=r.dotDomain?`${r.dotDomain} (Wildcard / Single-domain compatible)`:"Not Configured (Auto SNI prefix matching)",z=!r.disableHttps&&t.configured&&t.filesExist?`Enabled via Alt-Svc (UDP :${r.httpsPort}, RFC 9114)`:"Disabled (Requires active HTTPS with TLS certificate)",ue=t.configured&&t.filesExist?`Compatible (RFC 9250 / RFC 9460 DDR, UDP :${r.dotPort})`:"Disabled (Requires TLS certificate)",Ae=r.echEnabled?`Enabled (RFC 9460, Outer SNI: ${r.echFrontingDomain||"cloudflare-ech.com"})`:"Disabled",K=
|
|
477
|
-
Environment & Security:`,items:[{label:"Node.js Runtime",value:`v${process.versions.node} (${process.platform} ${process.arch})`},{label:"Config Directory",value:
|
|
478
|
-
`);console.log(T)}import
|
|
474
|
+
`).bind(t.id).first()),u?Response.json({encryptedSk:u.encrypted_sk,iv:u.iv}):new Response("Wrapped key not found for this passkey",{status:404})}if(c==="recovery-wrapped-key"&&r.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"&&r.method==="POST"){let a;try{a=await r.json()}catch{return new Response("Invalid JSON body",{status:400})}let{publicKey:l,passkeyId:u,encryptedSk:d,iv:p,recovery:f}=a;if(!l||!u&&!f)return new Response("Missing required fields (publicKey and either passkey or recovery)",{status:400});let m=null;if(u&&(m=await o.getByIdOrCredentialId(u,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),w=typeof l=="string"?l:JSON.stringify(l),b=[],y=h.length>0?h[0].id:null;if(y){m&&d&&p&&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,d,p,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)),f&&f.encryptedSk&&f.iv&&f.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,f.encryptedSk,f.iv,f.salt,g))}b.length>0&&await e.DB.batch(b);for(let E of h)nr(E.id);return Response.json({success:!0})}if(c==="wrap"&&r.method==="POST"){let a;try{a=await r.json()}catch{return new Response("Invalid JSON body",{status:400})}let{passkeyId:l,encryptedSk:u,iv:d}=a;if(!l||!u||!d)return new Response("Missing required fields (passkeyId, encryptedSk, iv)",{status:400});let p=await o.getByIdOrCredentialId(l,t.id);if(!p){let g=await o.listByUser(t.id);g.length>0&&(p=g[0])}if(!p)return new Response("Passkey not found or unauthorized",{status:403});let f=await i.listByOwner(t.id),m=f.length>0?f[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(p.id,m,u,d,h).run(),Response.json({success:!0})}if(c==="wrap-recovery"&&r.method==="POST"){let a;try{a=await r.json()}catch{return new Response("Invalid JSON body",{status:400})}let{encryptedSk:l,iv:u,salt:d}=a;if(!l||!u||!d)return new Response("Missing required fields (encryptedSk, iv, salt)",{status:400});let p=await i.listByOwner(t.id),f=Math.floor(Date.now()/1e3),m=[];for(let h of p)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,u,d,f));return m.length>0&&await e.DB.batch(m),Response.json({success:!0})}if(c==="enable"&&r.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)nr(l.id);return Response.json({success:!0,enabled:!0})}if(r.method==="DELETE"&&(!c||c==="keys")){let l=new URL(r.url).searchParams.get("purge")==="true",u=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 d of u)nr(d.id);return Response.json({success:!0,purged:l,enabled:!1})}return new Response("Not Found",{status:404})}async function Yl(r,e,t,n,s){let o=n[2];return o==="me"||o==="delete"||o==="logs"?Fl(r,e,t,n,s):o==="password"||o==="totp"||o==="passkeys"||o==="mfa"||o==="migrate-password"||o==="pin"||o==="recovery-keys"?Vl(r,e,t,n,s):o==="activity"||o==="sessions"?Jl(r,e,t,n,s):o==="e2ee"?Gl(r,e,t,n,s):new Response("Not Found",{status:404})}pe();Se();async function Xl(r,e,t,n,s){let o=new G(e.DB,e),i=new q(e.DB);if(n[2]==="users"){if(r.method==="GET"){let c=await o.listAll();return new Response(JSON.stringify(c),{headers:{"Content-Type":"application/json"}})}if(r.method==="POST"){let{username:c,password:a,role:l}=await r.json();if(!c||!xt.test(c))return new Response("Invalid username format",{status:400});if(!a||!Rt.test(a))return new Response("Password format error",{status:400});let u=await ct(a,2),d=j(15);try{return await o.create({id:d,username:c,passwordHash:u,role:l||"user",passwordVersion:2}),new Response(JSON.stringify({id:d}),{status:201})}catch(p){return new Response(p.message,{status:400})}}if(r.method==="DELETE"&&n[3]){let c=n[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(n[2]==="settings"){let c=new de(e.DB);if(r.method==="GET"){let a=await c.getAll();return delete a.jwt_secret,new Response(JSON.stringify(a),{headers:{"Content-Type":"application/json"}})}if(r.method==="PATCH"){let a=await r.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 zl(r,e,t,n){let o=new URL(r.url).pathname.split("/").filter(Boolean);return o[1]==="account"?Yl(r,e,t,o,n):o[1]==="admin"?Zr.isAdmin(t)?Xl(r,e,t,o,n):new Response("Forbidden",{status:403}):new Response("Not Found",{status:404})}ge();async function Ql(r,e){let t=new URL(r.url),n=typeof caches<"u"?caches.default:null;if(t.pathname==="/api/clientinfo"){let s=r.headers.get("CF-Connecting-IP")||"127.0.0.1",o=await v.get(n,`active_dns:${s}`),i=r.cf,c=i?.country||r.headers.get("CF-IPCountry")||"",a=c,l=i?.region||r.headers.get("CF-Region")||"",u=i?.city||r.headers.get("CF-IPCity")||"",d=i?.timezone||r.headers.get("CF-Timezone")||"",p=i?.asn?Number(i.asn):r.headers.get("CF-ASN")?Number(r.headers.get("CF-ASN")):0,f=i?.asOrganization||r.headers.get("CF-AS-Org")||"";if(!c||c==="UNKNOWN"||c==="UN"||c==="XX")if(!rt(s))c="Private Network",a="LAN",l="LAN",u="Local",d="UNKNOWN",f="Private Network";else try{let h=await Ln(s);if(h&&(c=h.country||h.country_code||"UNKNOWN",a=h.country_code||"UNKNOWN",l=h.region||"UNKNOWN",u=h.city||"UNKNOWN",d=h.timezone||"UNKNOWN",f=h.org||h.isp||"UNKNOWN",!p&&h.as)){let g=h.as.match(/^AS(\d+)/i);g&&(p=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:u||"UNKNOWN",timezone:d||"UNKNOWN",asn:p||0,asOrganization:f||"UNKNOWN",connectedProfileId:o||null,substituteDomain:e.SUBSTITUTE_DOMAIN||on,dotDomain:e.SERVERFULL_DOT_DOMAIN||e.DOT_DOMAIN||null,isServerfull:m,mode:m?"serverfull":"cloudflare"}),{headers:{"Content-Type":"application/json"}})}if(t.pathname==="/api/substitute"){let s=e.SUBSTITUTE_DOMAIN||on,o=null,i=null,c=async a=>{let l=["https://cloudflare-dns.com/dns-query","https://1.1.1.1/dns-query"];for(let u of l)try{let d=await fetch(`${u}?name=${s}&type=${a}`,{headers:{Accept:"application/dns-json"},signal:AbortSignal.timeout(3e3)});if(d.ok){let p=await d.json();if(p?.Answer?.length>0){let f=p.Answer.find(m=>m.type===(a==="A"?1:28));if(f?.data)return f.data}}}catch(d){console.error(`[Substitute Resolve] Failed resolving ${a} via ${u}:`,d)}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=is;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=as;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=Ta(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=r.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{1F6DC}"}}),{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 u=await l.json();if(Array.isArray(u?.Answer)&&u.Answer.length>0){let d=i==="A"?1:28;return u.Answer.filter(p=>p.type===d&&typeof p.data=="string").map(p=>p.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,u]=await Promise.allSettled([a.resolve4(s),a.resolve6(s)]);l.status==="fulfilled"&&Array.isArray(l.value)&&(i=l.value),u.status==="fulfilled"&&Array.isArray(u.value)&&(c=u.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();var rs=0;async function Zl(r,e,t){try{let n=typeof caches<"u"?caches.default:null,s=Math.floor(Date.now()/1e3),o=!0;rs&&s-rs<3600&&(o=!1);let i="cron:last_cleanup_timestamp",c=new de(e.DB);if(o){let a=await v.get(n,i);a&&s-a<3600&&(rs=a,o=!1)}if(o)try{let a=await c.get("cron_last_cleanup_timestamp");if(a){let l=parseInt(a,10)||0;s-l<3600&&(rs=l,o=!1)}}catch(a){console.warn("[Cron] Failed to read persistent cleanup timestamp:",a)}if(o){rs=s;try{let a=new G(e.DB,e),{clearedProfiles:l,deletedUsers:u}=await a.applyInactivityPolicy(s);(l>0||u>0)&&console.log(`[Cron] Inactivity cleanup: cleared ${l} profile(s), deleted ${u} user(s).`)}catch(a){console.error("[Cron] Inactivity policy execution failed:",a)}try{let a=new Ue(e.DB),l=e.MAX_LOG_RETENTION_DAYS!==void 0&&e.MAX_LOG_RETENTION_DAYS!==""?Number(e.MAX_LOG_RETENTION_DAYS):30,u=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 a.cleanupGlobal(l,u,d)}catch(a){console.error("[Cron] Global log cleanup failed:",a)}try{let{SessionModel:a}=await Promise.resolve().then(()=>(He(),Rn)),l=new a(e.DB),{deletedSessions:u,deletedPending:d}=await l.deleteExpiredSessions(s);(u>0||d>0)&&console.log(`[Cron] Purged ${u} expired session(s) and ${d} pending token(s).`)}catch(a){console.error("[Cron] Session cleanup failed:",a)}await v.set(n,i,s,3600);try{await c.set("cron_last_cleanup_timestamp",String(s))}catch(a){console.warn("[Cron] Failed to persist cleanup timestamp:",a)}console.log("[Cron] Cleanup phase completed at",new Date().toISOString())}try{await ri(e.DB)}catch(a){console.error("[Cron] Cloudflare IP range sync failed:",a)}try{let a="cron:last_idle_sync_check",l=Number(e.SYNC_IDLE_INTERVAL_SEC)||1800,u=await v.get(n,a);if(!!!(u&&s-u<l)){let p=Number(e.SYNC_PROFILE_INTERVAL_SEC)||86400,f=s-p,m=new q(e.DB),h=Number(e.SYNC_BATCH_SIZE)||1,g=await m.getSyncTargets(f,h);if(g.length>0){await v.delete(n,a);for(let w of g)try{await qr(w.id,e,t)}catch(b){let y=b instanceof Error?b.message:String(b);console.error(`[Cron] Sync failed for profile ${w.id}:`,y)}console.log(`[Cron] Sync: processed ${g.length} profile(s).`)}else await v.set(n,a,s,l)}}catch(a){let l=a instanceof Error?a.message:String(a);console.error("[Cron] Sync phase failed:",l)}}catch(n){let s=n instanceof Error?n.message:String(n);console.error("[Cron] Critical Failure:",s)}}async function ql(r,e,t){let n=new Request(new URL("https://obex.local/world-110m-v2.json"),r),s=caches.default,o=await s.match(n);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(n,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}$e();ge();var Lo={async fetch(r,e,t){v.setOrigin(new URL(r.url).origin);let n=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||e.SERVERFULL_DB_PATH!==void 0,s=cn(e,n);s==="Turso"&&mr(e)&&(e.DB=Vo(e));let o=new Uint8Array(16);crypto.getRandomValues(o);let i=Array.from(o).map(d=>d.toString(16).padStart(2,"0")).join(""),c=null,l=await(async()=>{let d=new URL(r.url);if(d.pathname==="/world-110m.json")return ql(r,e,t);if(d.pathname.startsWith("/api/")){let h=!1,g="";if(s==="Turso")(!mr(e)||!e.DB)&&(h=!0,g="DATABASE_SERVICE is set to Turso, but TURSO_DATABASE_URL or TURSO_AUTH_TOKEN is not configured.");else if(s==="File")n?e.DB||(h=!0,g="Database file is missing. Please restart the service or verify file permissions."):(h=!0,g="DATABASE_SERVICE='File' is not supported in Cloudflare Workers. Please configure D1 database binding or use DATABASE_SERVICE='Turso'.");else if(n)h=!0,g="DATABASE_SERVICE='D1' is designed for Cloudflare Workers. In Serverfull mode, please set DATABASE_SERVICE='File' or 'Turso'.";else try{h=!e.DB}catch{h=!0}let w=!Ne(e.JWT_SECRET);if(h||w)return new Response(JSON.stringify({error:"configuration_error",isDbMissing:h,isJwtSecretMissing:w,databaseService:s,message:g||"DNS Worker is not fully configured. Please configure the database and JWT_SECRET secret variable."}),{status:503,headers:{"Content-Type":"application/json","Access-Control-Allow-Origin":"*"}});c=await ta(r,e,t);let b=["/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/substitute","/api/resolve","/api/geoip"].includes(d.pathname)||d.pathname.startsWith("/api/icon/")||d.pathname.startsWith("/api/presets/")||d.pathname.startsWith("/api/auth/forgot-password");return!c&&!b?new Response("Unauthorized",{status:401}):c&&c.isPaused&&!(["/api/auth/unlock-session","/api/auth/logout","/api/auth/refresh"].includes(d.pathname)||d.pathname==="/api/account/me"&&r.method==="PATCH")?new Response("session_paused",{status:403}):c&&["POST","PUT","PATCH","DELETE"].includes(r.method)&&!b&&!ra(r)?new Response("CSRF validation failed",{status:403}):d.pathname.startsWith("/api/auth/")?vl(r,e):d.pathname==="/api/clientinfo"||d.pathname==="/api/substitute"||d.pathname==="/api/resolve"||d.pathname==="/api/geoip"||d.pathname.startsWith("/api/presets/")||d.pathname.startsWith("/api/icon/")?Ql(r,e):d.pathname.startsWith("/api/profiles")?Bl(r,e,c,t):d.pathname.startsWith("/api/account")||d.pathname.startsWith("/api/admin")?zl(r,e,c,t):new Response("API Not Found",{status:404})}if(d.pathname==="/setup.sh"){let h=d.searchParams.get("key");if(!h||!Vt.test(h))return new Response("Missing or invalid key parameter",{status:400});let g=hl(d.origin,h);return new Response(g,{headers:{"Content-Type":"text/plain; charset=utf-8","Cache-Control":"no-cache"}})}let p=d.pathname.slice(1),f=Vt.test(p),m=r.method==="POST"||d.searchParams.has("dns")||r.headers.get("accept")?.includes("dns-message");if(f&&(m||r.method==="OPTIONS"))return r.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"}}):pl(r,e,t,p);try{let h=await e.ASSETS.fetch(r);if(h.status===404&&!d.pathname.startsWith("/assets/")&&(r.method==="GET"||r.method==="HEAD")&&(h=await e.ASSETS.fetch(new Request(d.origin+"/",{method:r.method,headers:r.headers}))),d.pathname.endsWith(".wasm")){let w=new Headers(h.headers);return w.set("Content-Type","application/wasm"),w.set("Cross-Origin-Resource-Policy","same-origin"),new Response(h.body,{status:h.status,statusText:h.statusText,headers:w})}if((h.headers.get("Content-Type")||"").includes("text/html")){let w=!1;s==="Turso"?w=!mr(e)||!e.DB:s==="File"?w=!n||!e.DB:w=n||!e.DB;let b=!Ne(e.JWT_SECRET),y="{}";try{y=JSON.stringify({nonce:i,isDbMissing:w,isJwtSecretMissing:b,isServerfull:n,databaseService:s,isTurso:s==="Turso",mode:n?"serverfull":"cloudflare"})}catch{}return new HTMLRewriter().on("head",{element(E){E.prepend(`<script nonce="${i}">window.DNS_WORKER_CONFIG = ${y};</script>`,{html:!0})}}).transform(h)}return h}catch{return new Response("Asset Fetch Error",{status:500})}})(),u=c;if(u&&!xr(r.headers.get("Cookie"))){let d=u.sessionId?.startsWith("k_");try{let p=j(32);l.headers.append("Set-Cookie",lt(p,e,d))}catch{let f=new Headers(l.headers),m=j(32);f.append("Set-Cookie",lt(m,e,d)),l=new Response(l.body,{status:l.status,statusText:l.statusText,headers:f})}}if(l.headers.get("Content-Type")?.includes("application/dns-message")){let d=new Headers(l.headers);return d.set("Access-Control-Allow-Origin","*"),d.set("Access-Control-Allow-Methods","GET, POST, OPTIONS"),d.set("Access-Control-Allow-Headers","Content-Type, Accept"),new Response(l.body,{status:l.status,statusText:l.statusText,headers:d})}return ea(l,i)},async scheduled(r,e,t){e.SUBSTITUTE_DOMAIN&&v.setOrigin(`https://${e.SUBSTITUTE_DOMAIN}`),cn(e,!1)==="Turso"&&mr(e)&&(e.DB=Vo(e)),await Zl(r,e,t)}};function Oo(r){if(!r||typeof r!="string")return null;let e=r.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,n]=e.split(":");n&&/^\d+$/.test(n)&&at(t)&&(e=t)}return e.startsWith("::ffff:")&&(e=e.substring(7)),at(e)||$t(e)?e:null}function Ap(r,e){return e?(Array.isArray(e)?e:e.split(",").map(n=>n.trim()).filter(Boolean)).includes(r):!1}function eu(r,e,t){let n=Oo(e);if(n&&rt(n)&&!Ap(n,t))return n;let s=Oo(r.get("CF-Connecting-IP"));if(s)return s;let o=Oo(r.get("X-Real-IP"));if(o)return o;let i=r.get("X-Forwarded-For");if(i){let c=i.split(",");for(let a of c){let l=Oo(a);if(l)return l}}return n||"127.0.0.1"}function aa(r,e,t,n,s){return async(o,i)=>{try{let c=o.headers["x-forwarded-proto"]?.toLowerCase(),a=c||e;if(e==="http"&&s?.enabled&&c!=="https"){let _=(o.headers.host||`${t}:${n}`).trim().replace(/:\d+$/,""),S=s.httpsPort===443||s.httpsPort===0?"":`:${s.httpsPort}`,x=`https://${_}${S}${o.url||"/"}`;i.statusCode=o.method==="GET"||o.method==="HEAD"?301:307,i.setHeader("Location",x),i.setHeader("Connection","close"),i.setHeader("Content-Type","text/plain; charset=utf-8"),i.end(`Redirecting to ${x}`);return}let l=o.headers.host||`${t}:${n}`,u=new URL(o.url||"/",`${a}://${l}`),d=new Headers;for(let[E,_]of Object.entries(o.headers))_&&(Array.isArray(_)?_.forEach(S=>d.append(E,S)):d.set(E,String(_)));let p=eu(d,o.socket.remoteAddress,r.TRUSTED_PROXIES);d.set("CF-Connecting-IP",p);let f=d.get("CF-IPLatitude");(!f||f.trim()==="")&&d.set("CF-IPLatitude","0.0");let m=d.get("CF-IPLongitude");(!m||m.trim()==="")&&d.set("CF-IPLongitude","0.0");let h=null;if(o.method!=="GET"&&o.method!=="HEAD"){let E=[];for await(let _ of o)E.push(typeof _=="string"?tu.from(_):_);h=tu.concat(E)}let g=new Request(u.toString(),{method:o.method,headers:d,body:h,duplex:"half"}),w={waitUntil(E){E.catch(_=>console.error(`[${e.toUpperCase()} Background Task Error]:`,_))},passThroughOnException(){}},b=await Lo.fetch(g,r,w);i.statusCode=b.status,i.statusMessage=b.statusText;let y=typeof b.headers.getSetCookie=="function"?b.headers.getSetCookie():[];if(y.length===0&&b.headers.has("set-cookie")){let E=b.headers.get("set-cookie");E&&(y=[E])}if(b.headers.forEach((E,_)=>{let S=_.toLowerCase();S!=="set-cookie"&&(e==="https"&&S==="alt-svc"?i.setHeader("Alt-Svc",`h3=":${n}"; ma=86400, h3-29=":${n}"; ma=86400`):i.setHeader(_,E))}),y.length>0){let _=a==="http"?y.map(S=>S.replace(/;\s*Secure\b/gi,"")):y;i.setHeader("Set-Cookie",_)}if(e==="https"&&!i.hasHeader("Alt-Svc")&&i.setHeader("Alt-Svc",`h3=":${n}"; ma=86400, h3-29=":${n}"; ma=86400`),b.body){let E=b.body.getReader();for(;;){let{done:_,value:S}=await E.read();if(_)break;i.write(S)}}i.end()}catch(c){console.error(`[${e.toUpperCase()} Server] Request processing failed:`,c),i.headersSent||(i.statusCode=500,i.setHeader("Content-Type","application/json"),i.end(JSON.stringify({error:"Internal Server Error"})))}}}var No=class{constructor(e){this.options=e;qi(this.options.env,this.options.staticDir)}options;server=null;isRunning=!1;start(){return new Promise((e,t)=>{let{port:n,host:s,env:o,httpsRedirect:i}=this.options,c=aa(o,"http",s,n,i);this.server=Dp.createServer(c),this.server.keepAliveTimeout=65e3,this.server.headersTimeout=66e3,this.server.on("connection",l=>{l.setNoDelay(!0)});let a=l=>{this.server=null,console.error(ar({serviceName:"Web Dashboard & DoH (HTTP)",protocol:"HTTP",port:n,err:l,alternateOption:`--http-port <port> (e.g. --http-port ${n+1})`})),t(l)};this.server.once("error",a),this.server.listen(n,s,()=>{this.server?.removeListener("error",a),this.server?.on("error",u=>{console.error("[HTTP Server] Runtime error:",u)}),this.isRunning=!0;let l=i?.enabled?` (Auto-redirecting to HTTPS on port ${i.httpsPort})`:"";console.log(`[HTTP Server] Web Dashboard & DoH listening on http://${s}:${n}${l}`),e()})})}stop(){return new Promise(e=>{this.server&&this.isRunning?this.server.close(()=>{this.isRunning=!1,console.log("[HTTP Server] Service stopped."),e()}):e()})}},Io=class{constructor(e){this.options=e;qi(this.options.env,this.options.staticDir)}options;server=null;isRunning=!1;start(){return new Promise((e,t)=>{let{port:n,host:s,certPath:o,keyPath:i,env:c}=this.options;try{let a=ru.readFileSync(o),l=ru.readFileSync(i),u=aa(c,"https",s,n);this.server=vp.createServer({cert:a,key:l},u),this.server.keepAliveTimeout=65e3,this.server.headersTimeout=66e3,this.server.on("connection",p=>{p.setNoDelay(!0)});let d=p=>{this.server=null,console.error(ar({serviceName:"Web Dashboard & DoH (HTTPS)",protocol:"HTTPS",port:n,err:p,alternateOption:`--https-port <port> (e.g. --https-port ${n+1})`})),t(p)};this.server.once("error",d),this.server.listen(n,s,()=>{this.server?.removeListener("error",d),this.server?.on("error",p=>{console.error("[HTTPS Server] Runtime error:",p)}),this.isRunning=!0,console.log(`[HTTPS Server] Web Dashboard & DoH listening on https://${s}:${n}`),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()})}};$e();import $p from"node:path";import{parseArgs as Kp}from"node:util";$e();import Pp from"node:net";import Cp from"node:dgram";function Uo(r,e,t=300){return new Promise(n=>{let s=new Pp.Socket,o=!1,i=a=>{if(!o){o=!0;try{s.destroy()}catch{}n(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(r,c)}catch{i("free")}})}function nu(r,e){return new Promise(t=>{let n=Cp.createSocket("udp4"),s=!1,o=i=>{if(!s){s=!0;try{n.close()}catch{}t(i)}};n.once("error",i=>{let c=i?.code;o(c==="EADDRINUSE"?"active":"free")});try{n.bind(r,e,()=>{o("free")})}catch{o("active")}})}import su from"node:fs";import{DatabaseSync as kp}from"node:sqlite";function ou(r){if(!su.existsSync(r))return{exists:!1,statusText:"Not Initialized (File does not exist yet; created on first start)"};try{let e=su.statSync(r),t=e.size>1024*1024?`${(e.size/(1024*1024)).toFixed(2)} MB`:`${(e.size/1024).toFixed(1)} KB`,n=0,s=0,o=0;try{let c=new kp(r,{readOnly:!0}),a=c.prepare("SELECT count(*) as cnt FROM sqlite_master WHERE type='table' AND name='d1_migrations'").get();a&&a.cnt>0&&(n=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 u=c.prepare("SELECT count(*) as cnt FROM sqlite_master WHERE type='table' AND name='profiles'").get();u&&u.cnt>0&&(o=c.prepare("SELECT count(*) as count FROM profiles").get()?.count||0),c.close()}catch{}let i=[t,n>0?`${n} migrations`:null,s>0?`${s} user(s)`:null,o>0?`${o} profile(s)`:null].filter(Boolean).join(", ");return{exists:!0,sizeFormatted:t,migrationsCount:n,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 iu(r,e){try{let t=ln(r,e),n=await ga(t),s=0,o=0;try{s=(await t.prepare("SELECT count(*) as count FROM users").first())?.count||0,o=(await t.prepare("SELECT count(*) as count FROM profiles").first())?.count||0}catch{}let i=[n.count>0?`${n.count} migrations`:null,s>0?`${s} user(s)`:null,o>0?`${o} profile(s)`:null].filter(Boolean).join(", ");return{exists:!0,migrationsCount:n.count,usersCount:s,profilesCount:o,statusText:`Ready (Connected${i?`: ${i}`:""})`}}catch(t){return{exists:!1,statusText:`Connection Failed (${t instanceof Error?t.message:String(t)})`}}}async function au(r,e){let t=Yr(r.tlsCertPath,r.tlsKeyPath),n=!r.disableHttps&&t.configured&&t.filesExist,s=r.databaseService==="Turso",o=s?r.tursoDatabaseUrl&&r.tursoAuthToken?iu(r.tursoDatabaseUrl,r.tursoAuthToken):Promise.resolve({exists:!1,statusText:"Configuration Error (TURSO_DATABASE_URL or TURSO_AUTH_TOKEN missing)"}):Promise.resolve(ou(r.dbPath)),[i,c,a,l,u]=await Promise.all([Uo(r.httpPort,r.host),n?Uo(r.httpsPort,r.host):Promise.resolve("disabled"),r.disableUdp?Promise.resolve("disabled"):nu(r.udpPort,r.host),r.disableDot?Promise.resolve("disabled"):Uo(r.dotPort,r.host),o]),d="Default (Insecure fallback, please configure JWT_SECRET)";Ne(e)&&(d=_t(e)?"Configured (Strong, >= 32 characters)":"Configured (Warning: Shorter than 32 characters)");let p=i==="active"?or(r.httpPort,"TCP"):null,f=p?`: ${ir(p)}`:"",m=i==="active"?`http://${r.host}:${r.httpPort} [Active / Listening${f}]`:`http://${r.host}:${r.httpPort} [Stopped / Port Available]`,h="";if(r.disableHttps)h="Disabled (--disable-https)";else if(!t.configured)h=`https://${r.host}:${r.httpsPort} [Disabled - TLS Certificates Not Configured]`;else if(!t.filesExist)h=`https://${r.host}:${r.httpsPort} [Warning - TLS Certificate Files Missing]`;else if(c==="active"){let A=or(r.httpsPort,"TCP"),C=A?`: ${ir(A)}`:"";h=`https://${r.host}:${r.httpsPort} [Active / Listening${C}]`}else h=`https://${r.host}:${r.httpsPort} [Stopped / Port Available]`;let g=!r.disableUdp&&a==="active"?or(r.udpPort,"UDP"):null,w=g?`: ${ir(g)}`:"",b=r.disableUdp?"Disabled (--disable-udp)":a==="active"?`udp://${r.host}:${r.udpPort} [Active / In Use${w}]`:`udp://${r.host}:${r.udpPort} [Stopped / Port Available]`,y="",E=r.dotDomain?` (${r.dotDomain})`:"";if(r.disableDot)y="Disabled (--disable-dot)";else if(!t.configured)y=`tls://${r.host}:${r.dotPort}${E} [Disabled - TLS Certificates Not Configured]`;else if(!t.filesExist)y=`tls://${r.host}:${r.dotPort}${E} [Warning - TLS Certificate Files Missing]`;else if(!t.isWildcard)y=`tls://${r.host}:${r.dotPort}${E} [Paused - Requires Wildcard Certificate (*.domain)]`;else if(l==="active"){let A=or(r.dotPort,"TCP"),C=A?`: ${ir(A)}`:"";y=`tls://${r.host}:${r.dotPort}${E} [Active / Listening${C}]`}else y=`tls://${r.host}:${r.dotPort}${E} [Stopped / Port Available]`;let _=r.defaultProfileKey?`Explicit (${r.defaultProfileKey})`:"Auto (Database default profile)",S=xe({title:"DNS Worker Runtime Status (Serverfull Mode)",borderChar:"=",bullet:"\u2022 "}),x=Ye({title:`
|
|
475
|
+
Service Transports:`,items:[{label:"Web Dashboard (HTTP)",value:m},{label:"Web Dashboard (HTTPS)",value:h},{label:"Classic UDP DNS",value:b},{label:"DNS over TLS (DoT)",value:y}]}),R=ps(),D=R.length>0?`${R.join(", ")} [Loaded]`:`None found (Using built-in presets & defaults; default path: ${Fe()})`,P=s?[{label:"Database Service",value:`${r.databaseService} (Turso libSQL over HTTP)`},{label:"Turso URL",value:an(r.tursoDatabaseUrl)},{label:"Database Status",value:u.statusText}]:[{label:"Database Service",value:`${r.databaseService} (Local SQLite via node:sqlite)`},{label:"SQLite Path",value:r.dbPath},{label:"Database Status",value:u.statusText},{label:"Persistent Data Dir",value:qe()}],k=Ye({title:`
|
|
476
|
+
Database & Storage:`,items:P}),N="Not Configured (HTTP only, HTTPS & DoT disabled)";if(t.configured)if(!t.filesExist)N="Configured [Files Missing]";else if(t.error)N=`Configured [Invalid Certificate: ${t.error}]`;else{let A=t.isWildcard?"Wildcard (*.domain)":"Single Domain",C=t.expiresAt?t.expiresAt.toISOString().split("T")[0]:"Unknown";N=`Valid (${A}, Expires: ${C})`}let V=r.dotDomain?`${r.dotDomain} (Wildcard / Single-domain compatible)`:"Not Configured (Auto SNI prefix matching)",z=!r.disableHttps&&t.configured&&t.filesExist?`Enabled via Alt-Svc (UDP :${r.httpsPort}, RFC 9114)`:"Disabled (Requires active HTTPS with TLS certificate)",ue=t.configured&&t.filesExist?`Compatible (RFC 9250 / RFC 9460 DDR, UDP :${r.dotPort})`:"Disabled (Requires TLS certificate)",Ae=r.echEnabled?`Enabled (RFC 9460, Outer SNI: ${r.echFrontingDomain||"cloudflare-ech.com"})`:"Disabled",K=Ye({title:`
|
|
477
|
+
Environment & Security:`,items:[{label:"Node.js Runtime",value:`v${process.versions.node} (${process.platform} ${process.arch})`},{label:"Config Directory",value:hr()},{label:"Config Source",value:D},{label:"TLS Certificate",value:N},{label:"JWT Secret",value:d},{label:"DoT Base Domain",value:V},{label:"HTTP/3 (h3)",value:z},{label:"DNS over QUIC (DoQ)",value:ue},{label:"ECH (Encrypted Client Hello)",value:Ae},{label:"Default Profile Key",value:_}]}),se=[];if(i==="free"&&(a==="free"||r.disableUdp)){let A=process.platform==="win32"?"dns-worker service install (in Administrator terminal)":"sudo dns-worker service install";se.push("Services are currently stopped."),se.push(`To run continuously as a persistent background daemon: ${A}`)}let we=Qn(r.dotDomain);!t.configured||!t.filesExist?(se.push(`To enable secure HTTPS (port ${r.httpsPort}) and DoT (port ${r.dotPort}):`),se.push(` ${we}`)):t.isWildcard||(se.push("Current certificate is single-domain. To support per-profile DoT (<profile>.domain):"),se.push(` ${we}`)),se.push("Run 'dns-worker ech' to view active ECH configuration, outer SNI, and RFC 9460 DNS records.");let L=se.length>0?Gr(se):"",T=[S,x,k,K,L].filter(Boolean).join(`
|
|
478
|
+
`);console.log(T)}import Lp from"node:fs";import Op from"node:path";import{execSync as Np}from"node:child_process";function cu(){try{return Np("net session",{stdio:"ignore"}),!0}catch{return!1}}function lu(){return typeof process.getuid=="function"&&process.getuid()===0}function en(r){let e=process.execPath,t=process.argv[1]?Op.resolve(process.argv[1]):"",n=r||process.env.SERVERFULL_SERVICE_USER||process.env.SUDO_USER||process.env.USER||"root",s=n==="root"?"/root":process.env.SUDO_USER&&n===process.env.SUDO_USER?`/home/${process.env.SUDO_USER}`:process.env.HOME||process.cwd(),o="";return t&&Lp.existsSync(t)?o=`"${e}" "${t}"`:o="dns-worker",{execCmd:o,nodePath:e,scriptPath:t,workDir:process.platform==="win32"?process.cwd():s,user:n}}import dr from"node:fs";import Ip from"node:path";import{execSync as ze}from"node:child_process";var yt="dns-worker",Up=`${yt}.service`,tn=`/etc/systemd/system/${Up}`;function ca(r){let{execCmd:e,workDir:t,user:n}=r;return`[Unit]
|
|
479
479
|
Description=DNS Worker Serverfull Service (UDP DNS, DoT & Web Dashboard)
|
|
480
480
|
After=network.target
|
|
481
481
|
|
|
@@ -508,25 +508,25 @@ SyslogIdentifier=dns-worker
|
|
|
508
508
|
|
|
509
509
|
[Install]
|
|
510
510
|
WantedBy=multi-user.target
|
|
511
|
-
`}async function
|
|
511
|
+
`}async function uu(r,e){let t=lu();switch(r){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 n=en(e),s=ca(n);try{let o="/var/lib/dns-worker",i="/etc/dns-worker",c=Ip.join(i,".env");try{if(dr.existsSync(o)||dr.mkdirSync(o,{recursive:!0,mode:493}),dr.existsSync(i)||dr.mkdirSync(i,{recursive:!0,mode:493}),Be(c,!1),n.user&&n.user!=="root"){try{ze(`chown -R ${n.user} ${o}`)}catch{}try{ze(`chown -R ${n.user} ${i}`)}catch{}}}catch{}dr.writeFileSync(tn,s,"utf-8"),ze("systemctl daemon-reload",{stdio:"inherit"}),ze(`systemctl enable ${yt}`,{stdio:"inherit"}),ze(`systemctl restart ${yt}`,{stdio:"inherit"});let a=xe({title:"DNS Worker Linux Service Installed & Started",borderChar:"=",bullet:"\u2022 ",items:[{label:"Service File",value:tn},{label:"Running As User",value:`${n.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=_o({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(`
|
|
512
512
|
`+a+`
|
|
513
513
|
|
|
514
|
-
`+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 ${tn}.`]})),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{
|
|
514
|
+
`+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 ${tn}.`]})),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{ze(`systemctl stop ${yt}`,{stdio:"ignore"})}catch{}try{ze(`systemctl disable ${yt}`,{stdio:"ignore"})}catch{}dr.existsSync(tn)&&dr.unlinkSync(tn),ze("systemctl daemon-reload",{stdio:"inherit"}),console.log(O({level:"success",title:"Service Removed",message:`DNS Worker systemd service removed from ${tn}.`}))}catch(n){let s=n instanceof Error?n.message:String(n);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 (${r}) requires elevated privileges.`,solutions:[`Run with sudo: sudo dns-worker service ${r}`]})),process.exit(1));try{ze(`systemctl ${r} ${yt}`,{stdio:"inherit"}),console.log(O({level:"success",title:"Service Action Executed",message:`systemctl ${r} ${yt}`}))}catch(n){let s=n instanceof Error?n.message:String(n);console.error(O({level:"error",title:`Service ${r} Failed`,message:s})),process.exit(1)}break}case"status":{try{ze(`systemctl status ${yt}`,{stdio:"inherit"})}catch{}break}case"logs":{try{ze(`journalctl -u ${yt} -f -n 50`,{stdio:"inherit"})}catch(n){let s=n instanceof Error?n.message:String(n);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 "${r}".`,solutions:["Supported actions: install, start, stop, restart, enable, disable, status, logs, uninstall","Example: sudo dns-worker service install"]})),process.exit(1)}}import pr from"node:fs";import Mo from"node:path";import{execSync as Qe}from"node:child_process";var me="DNS-Worker",ss=Mo.join(process.env.ProgramData||"C:\\ProgramData","DNS-Worker"),fr=Mo.join(ss,"service.log"),ns=Mo.join(ss,"run-service.bat");function Mp(r){return`@echo off\r
|
|
515
515
|
setlocal\r
|
|
516
516
|
cd /d "${r.workDir}"\r
|
|
517
|
-
"${r.nodePath}" "${r.scriptPath}" >> "${
|
|
518
|
-
`}async function
|
|
517
|
+
"${r.nodePath}" "${r.scriptPath}" >> "${fr}" 2>&1\r
|
|
518
|
+
`}async function du(r){let e=cu();switch(r){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=en();try{pr.existsSync(ss)||pr.mkdirSync(ss,{recursive:!0});let n=Mo.join(ss,".env");Be(n,!1);let s=Mp(t);pr.writeFileSync(ns,s,"utf-8");let o=`schtasks /create /tn "${me}" /tr "\\"${ns}\\"" /sc onstart /ru "SYSTEM" /rl HIGHEST /f`;Qe(o,{stdio:"inherit"});try{Qe(`schtasks /run /tn "${me}"`,{stdio:"inherit"})}catch{}let i=xe({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:n},{label:"Launcher Script",value:ns},{label:"Log Output",value:fr}]}),c=_o({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(`
|
|
519
519
|
`+i+`
|
|
520
520
|
|
|
521
|
-
`+c)}catch(n){let s=n instanceof Error?n.message:String(n);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{
|
|
522
|
-
`);console.log(
|
|
521
|
+
`+c)}catch(n){let s=n instanceof Error?n.message:String(n);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{Qe(`schtasks /end /tn "${me}"`,{stdio:"ignore"})}catch{}Qe(`schtasks /delete /tn "${me}" /f`,{stdio:"inherit"}),pr.existsSync(ns)&&pr.unlinkSync(ns),console.log(O({level:"success",title:"Service Removed",message:`Windows background task "${me}" removed successfully.`}))}catch(t){let n=t instanceof Error?t.message:String(t);console.error(O({level:"error",title:"Windows Service Removal Failed",message:n})),process.exit(1)}break}case"start":{try{Qe(`schtasks /run /tn "${me}"`,{stdio:"inherit"}),console.log(O({level:"success",title:"Service Started",message:`Started Windows background task: ${me}`}))}catch(t){let n=t instanceof Error?t.message:String(t);console.error(O({level:"error",title:"Task Start Failed",message:n,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{Qe(`schtasks /end /tn "${me}"`,{stdio:"inherit"}),console.log(O({level:"success",title:"Service Stopped",message:`Stopped Windows background task: ${me}`}))}catch(t){let n=t instanceof Error?t.message:String(t);console.error(O({level:"error",title:"Task Stop Failed",message:n})),process.exit(1)}break}case"restart":{try{try{Qe(`schtasks /end /tn "${me}"`,{stdio:"ignore"})}catch{}Qe(`schtasks /run /tn "${me}"`,{stdio:"inherit"}),console.log(O({level:"success",title:"Service Restarted",message:`Restarted Windows background task: ${me}`}))}catch(t){let n=t instanceof Error?t.message:String(t);console.error(O({level:"error",title:"Task Restart Failed",message:n})),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{Qe(`schtasks /change /tn "${me}" /enable`,{stdio:"inherit"}),console.log(O({level:"success",title:"Service Enabled",message:`Windows background task "${me}" enabled.`}))}catch(t){let n=t instanceof Error?t.message:String(t);console.error(O({level:"error",title:"Task Enable Failed",message:n,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{Qe(`schtasks /change /tn "${me}" /disable`,{stdio:"inherit"}),console.log(O({level:"success",title:"Service Disabled",message:`Windows background task "${me}" disabled.`}))}catch(t){let n=t instanceof Error?t.message:String(t);console.error(O({level:"error",title:"Task Disable Failed",message:n})),process.exit(1)}break}case"status":{try{Qe(`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(!pr.existsSync(fr)){console.log(O({level:"info",title:"Service Logs Notice",message:`No log file found at ${fr} yet.`,details:["The background service has not produced any log output or has not been started yet."]}));return}try{let s=pr.readFileSync(fr,"utf-8").trim().split(/\r?\n/).slice(-50).join(`
|
|
522
|
+
`);console.log(So({title:`Recent 50 Service Log Lines: ${fr}`,content:s,borderChar:"-",tip:`In PowerShell, run: Get-Content "${fr}" -Tail 50 -Wait`}))}catch(t){let n=t instanceof Error?t.message:String(t);console.error(O({level:"error",title:"Service Logs Error",message:`Error reading log file: ${n}`}))}break}default:console.error(O({level:"error",title:"Service Command Error",message:`Unknown service action "${r}".`,solutions:["Supported actions: install, start, stop, restart, enable, disable, status, logs, uninstall","Example: dns-worker service install"]})),process.exit(1)}}async function pu(r,e){if(process.platform==="win32")await du(r);else if(process.platform==="linux")await uu(r,e);else{let t=en(),n=ca(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(So({title:"systemd service unit template",content:n.trim(),borderChar:"-"}))}}import rn from"node:fs";import nn from"node:path";import Bp from"node:readline/promises";import{stdin as fu,stdout as Fp}from"node:process";import{DatabaseSync as Hp}from"node:sqlite";async function mu(r={}){let e=Fe(),t=Ft(),n=nn.join(process.cwd(),".env");if(!r.force){fu.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=xe({title:"\u26A0\uFE0F CAUTION: FACTORY RESET (DATA DESTRUCTION)",borderChar:"!",bullet:"\u2022 "}),c=[{label:"Configuration File",value:e},{label:"SQLite Database",value:t}];rn.existsSync(n)&&c.push({label:"Local .env File",value:n});let a=Ye({title:`
|
|
523
523
|
Target Resources to be Reset:`,items:c});console.log([i,a,`
|
|
524
524
|
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.
|
|
525
525
|
`].join(`
|
|
526
|
-
`));let l=
|
|
527
|
-
`):"None (Using built-in presets & defaults)",s=xe({title:"DNS Worker Configuration Summary",borderChar:"=",bullet:"\u2022 "}),o=
|
|
528
|
-
Active Configuration Paths:`,items:[{label:"Persistent Data Dir",value:
|
|
529
|
-
`))}function Vp(r){let{config:e}=fn(r),t=e.echFrontingDomain||"cloudflare-ech.com",n=e.echConfig||hn(t),s=e.dotDomain||"dns.example.com",o=xe({title:"Encrypted Client Hello (ECH) & DNS Service Records",borderChar:"=",bullet:"\u2022 "}),i=
|
|
526
|
+
`));let l=Bp.createInterface({input:fu,output:Fp});try{let d=(await l.question("Are you sure you want to proceed with factory reset? (yes/no): ")).trim().toLowerCase();if(d!=="yes"&&d!=="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(rn.existsSync(i))try{let a=new Hp(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:u}of l)a.exec(`DROP TABLE IF EXISTS "${u}";`);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(rn.existsSync(a))try{rn.unlinkSync(a)}catch{}};s(t);let o=nn.join(process.cwd(),"data","dns_worker.sqlite");rn.existsSync(o)&&nn.resolve(o)!==nn.resolve(t)&&s(o),console.log("[Reset] Rebuilding fresh database schema..."),ms(t),Be(e,!0),rn.existsSync(n)&&nn.resolve(n)!==nn.resolve(e)&&Be(n,!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 hu(){let r=process.versions.bun;if(r){let[n,s]=r.split(".").map(Number);(n<1||n===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${r}).`,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 Wp(r){return/^[a-zA-Z0-9._\-\/\\ :]+$/.test(r)}function jp(r,e){if(r==="path"){console.log(Fe());return}if(r==="template"){process.stdout.write(Go);return}if(r==="init"){let c=process.argv.includes("--force")||e==="--force";e&&e!=="--force"&&!Wp(e)&&(console.error(O({level:"error",title:"Invalid Configuration Path",message:"The provided config path contains unsupported characters.",solutions:['Use a normal filesystem path containing letters, numbers, spaces, ".", "_", "-", "/", "\\", or ":" only.',"Avoid shell metacharacters and control characters in path arguments."]})),process.exit(1));let a=e&&e!=="--force"?$p.resolve(e):Fe(),l=Be(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}fs();let t=ps(),n=t.length>0?t.join(`
|
|
527
|
+
`):"None (Using built-in presets & defaults)",s=xe({title:"DNS Worker Configuration Summary",borderChar:"=",bullet:"\u2022 "}),o=Ye({title:`
|
|
528
|
+
Active Configuration Paths:`,items:[{label:"Persistent Data Dir",value:qe()},{label:"Config Directory",value:hr()},{label:"Default Config Path",value:Fe()},{label:"Default SQLite Path",value:Ft()},{label:"Loaded Config Files",value:n}]}),i=Gr(["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(`
|
|
529
|
+
`))}function Vp(r){let{config:e}=fn(r),t=e.echFrontingDomain||"cloudflare-ech.com",n=e.echConfig||hn(t),s=e.dotDomain||"dns.example.com",o=xe({title:"Encrypted Client Hello (ECH) & DNS Service Records",borderChar:"=",bullet:"\u2022 "}),i=Ye({title:`
|
|
530
530
|
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:n},{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="${n}"`,a=`${s}. 300 IN HTTPS 1 . alpn="h3,h2" port=${e.httpsPort} ech="${n}"`,l=`
|
|
531
531
|
Standard DNS Service Binding Records (RFC 9460 & RFC 9460 Section 8 DDR):
|
|
532
532
|
\u2022 DDR SVCB Record (DoQ/DoT auto-discovery):
|
|
@@ -534,6 +534,6 @@ Standard DNS Service Binding Records (RFC 9460 & RFC 9460 Section 8 DDR):
|
|
|
534
534
|
|
|
535
535
|
\u2022 HTTPS Service Record (HTTP/3 & ECH):
|
|
536
536
|
${a}`,u=Gr(["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,u].join(`
|
|
537
|
-
`))}function la(){let r=un(),e=hl({name:`DNS Worker v${r} (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:"--database-service <D1|Turso|File>",desc:"Database engine (default: File in Serverfull, D1 in Serverless)"},{label:"--db <path>",desc:`SQLite database file path (default: ${Ft()})`},{label:"--turso-url <url>",desc:"Turso / libSQL database URL (e.g. libsql://your-db.turso.io)"},{label:"--turso-token <token>",desc:"Turso database authorization token"},{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:"DATABASE_SERVICE",desc:"Database engine (D1, Turso, File. Default: File)"},{label:"DB_PATH / SERVERFULL_DB_PATH",desc:"SQLite database file path"},{label:"TURSO_DATABASE_URL / TURSO_URL",desc:"Turso / libSQL database URL (e.g. libsql://your-db.turso.io)"},{label:"TURSO_AUTH_TOKEN",desc:"Turso database authorization token"},{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 yu(){try{let{values:r,positionals:e}=Wp({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"},"database-service":{type:"string"},"db-service":{type:"string"},db:{type:"string"},"turso-url":{type:"string"},"turso-token":{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((r.help||e[0]?.toLowerCase()==="help")&&(la(),process.exit(0)),r.version&&(console.log(`dns-worker v${un()}`),process.exit(0)),r.status||e[0]?.toLowerCase()==="status"){let{config:n,env:s}=fn(r);await cu(n,s.JWT_SECRET),process.exit(0)}if(e[0]?.toLowerCase()==="reset"){let n=!!(r.force||r.yes||process.argv.includes("--force")||process.argv.includes("-f")||process.argv.includes("-y")||process.argv.includes("--yes"));await hu({force:n}),process.exit(0)}if(e[0]?.toLowerCase()==="ech"&&(Vp(r),process.exit(0)),e[0]?.toLowerCase()==="config"){let n=e[1]?.toLowerCase()||"show",s=e[2];jp(n,s),process.exit(0)}if(e[0]?.toLowerCase()==="service"){let n=e[1]?.toLowerCase()||"status",s=r.user;await fu(n,s),process.exit(0)}if(e[0]?.toLowerCase()==="postinstall"){try{let{dataDir:n,configFile:s}=yr(!0);console.log(`[dns-worker] Initialized data directory: ${n}`),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."]})),la(),process.exit(1)),r}catch(r){let e=r instanceof Error?r.message:String(r),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."]})),la(),process.exit(1)}}async function Gp(){gu();let r=await yu();console.log(xe({title:`Initializing DNS Worker v${un()} (Serverfull)`,borderChar:"-"})),da();let{config:e,env:t}=fn(r),n=Yr(e.tlsCertPath,e.tlsKeyPath),s=n.configured&&n.filesExist&&!e.disableHttps,o=!e.disableDot&&n.configured&&n.filesExist&&n.isWildcard;n.configured?n.filesExist?n.isWildcard||console.log(O(Qi("non_wildcard",e.dotDomain))):console.log(O({level:"warning",title:"TLS Certificate Files Inaccessible",message:n.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(Qi("missing",e.dotDomain)));let i=e.disableHttps?"Disabled (--disable-https)":s?`https://${e.host}:${e.httpsPort}`:n.configured?`Disabled (Files Inaccessible: ${n.error||"Check Permissions"})`:"Disabled (TLS Certificates Not Configured)",c=e.disableDot?"Disabled (--disable-dot)":n.configured?n.filesExist?n.isWildcard?`tls://${e.host}:${e.dotPort}`:"Paused (Requires Wildcard Certificate *.domain)":`Disabled (Files Inaccessible: ${n.error||"Check Permissions"})`:"Disabled (TLS Certificates Not Configured)";console.log(Ge({title:"[Services] Configured Ports & Transports:",items:[{label:"Web Dashboard & DoH (HTTP)",value:s?`http://${e.host}:${e.httpPort} (Redirects to HTTPS)`:`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)&&!_t(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=null;if(e.databaseService==="Turso"){(!e.tursoDatabaseUrl||!e.tursoAuthToken)&&(console.error(O({level:"error",title:"Database Configuration Error",message:"DATABASE_SERVICE is set to 'Turso', but TURSO_DATABASE_URL or TURSO_AUTH_TOKEN is missing.",solutions:["Set TURSO_DATABASE_URL and TURSO_AUTH_TOKEN in .env or via CLI arguments (--turso-url, --turso-token).","Alternatively, set DATABASE_SERVICE='File' to use local SQLite."]})),process.exit(1)),console.log(`[Database] Using Turso Database: ${an(e.tursoDatabaseUrl)}`);let g=ln(e.tursoDatabaseUrl,e.tursoAuthToken),b=Jp.join(e.packageRoot,"migrations");await ya(g,b),t.DB=g}else if(e.databaseService==="D1")console.error(O({level:"error",title:"Database Configuration Error",message:"DATABASE_SERVICE='D1' is designed for Cloudflare Workers environments with D1 bindings.",solutions:["In Serverfull mode, please set DATABASE_SERVICE='File' (default local SQLite) or DATABASE_SERVICE='Turso'."]})),process.exit(1);else{let g=ms(e.dbPath);a=g,t.DB=g}let l=e.disableUdp?null:new Ro({port:e.udpPort,host:e.host,defaultProfileKey:e.defaultProfileKey,env:t}),u=o?new Do({port:e.dotPort,host:e.host,tlsKeyPath:e.tlsKeyPath,tlsCertPath:e.tlsCertPath,dotDomain:e.dotDomain,defaultProfileKey:e.defaultProfileKey,env:t}):null,d=new Io({port:e.httpPort,host:e.host,env:t,httpsRedirect:s?{enabled:!0,httpsPort:e.httpsPort}:void 0}),p=s?new Uo({port:e.httpsPort,host:e.host,certPath:e.tlsCertPath,keyPath:e.tlsKeyPath,env:t}):null;l&&await l.start(),u&&await u.start(),await d.start(),p&&await p.start();let f=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 Oo.scheduled(g,t,b)}catch(g){console.error("[Cron Scheduler Error]:",g)}},6e4),m=!!(n.configured&&n.filesExist);console.log(xe({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:u&&m?`tls://${e.dotDomain||e.host}:${e.dotPort}`:n.configured?n.filesExist?n.isWildcard?"Disabled":"Paused (Requires Wildcard Certificate *.domain)":`Disabled (Files Inaccessible: ${n.error||"Check Permissions"})`:"Disabled / Not Configured"},{label:"Web UI & DoH (HTTP)",value:`http://${e.host}:${e.httpPort}`},{label:"Web UI & DoH (HTTPS)",value:p?`https://${e.dotDomain||e.host}:${e.httpsPort}`:n.configured?n.filesExist?"Disabled":`Disabled (Files Inaccessible: ${n.error||"Check Permissions"})`:"Disabled / Not Configured"},{label:"Database Engine",value:e.databaseService==="Turso"?`Turso (${an(e.tursoDatabaseUrl)})`:`SQLite (${e.dbPath})`}]}));let h=async g=>{console.log(`
|
|
538
|
-
[Serverfull] Received ${g}. Shutting down gracefully...`),clearInterval(f),await Promise.all([l?.stop(),u?.stop(),d.stop(),p?.stop()]);try{await
|
|
537
|
+
`))}function la(){let r=un(),e=ml({name:`DNS Worker v${r} (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:"--database-service <D1|Turso|File>",desc:"Database engine (default: File in Serverfull, D1 in Serverless)"},{label:"--db <path>",desc:`SQLite database file path (default: ${Ft()})`},{label:"--turso-url <url>",desc:"Turso / libSQL database URL (e.g. libsql://your-db.turso.io)"},{label:"--turso-token <token>",desc:"Turso database authorization token"},{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:"DATABASE_SERVICE",desc:"Database engine (D1, Turso, File. Default: File)"},{label:"DB_PATH / SERVERFULL_DB_PATH",desc:"SQLite database file path"},{label:"TURSO_DATABASE_URL / TURSO_URL",desc:"Turso / libSQL database URL (e.g. libsql://your-db.turso.io)"},{label:"TURSO_AUTH_TOKEN",desc:"Turso database authorization token"},{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 gu(){try{let{values:r,positionals:e}=Kp({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"},"database-service":{type:"string"},"db-service":{type:"string"},db:{type:"string"},"turso-url":{type:"string"},"turso-token":{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((r.help||e[0]?.toLowerCase()==="help")&&(la(),process.exit(0)),r.version&&(console.log(`dns-worker v${un()}`),process.exit(0)),r.status||e[0]?.toLowerCase()==="status"){let{config:n,env:s}=fn(r);await au(n,s.JWT_SECRET),process.exit(0)}if(e[0]?.toLowerCase()==="reset"){let n=!!(r.force||r.yes||process.argv.includes("--force")||process.argv.includes("-f")||process.argv.includes("-y")||process.argv.includes("--yes"));await mu({force:n}),process.exit(0)}if(e[0]?.toLowerCase()==="ech"&&(Vp(r),process.exit(0)),e[0]?.toLowerCase()==="config"){let n=e[1]?.toLowerCase()||"show",s=e[2];jp(n,s),process.exit(0)}if(e[0]?.toLowerCase()==="service"){let n=e[1]?.toLowerCase()||"status",s=r.user;await pu(n,s),process.exit(0)}if(e[0]?.toLowerCase()==="postinstall"){try{let{dataDir:n,configFile:s}=gr(!0);console.log(`[dns-worker] Initialized data directory: ${n}`),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."]})),la(),process.exit(1)),r}catch(r){let e=r instanceof Error?r.message:String(r),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."]})),la(),process.exit(1)}}async function Gp(){hu();let r=await gu();console.log(xe({title:`Initializing DNS Worker v${un()} (Serverfull)`,borderChar:"-"})),da();let{config:e,env:t}=fn(r),n=Yr(e.tlsCertPath,e.tlsKeyPath),s=n.configured&&n.filesExist&&!e.disableHttps,o=!e.disableDot&&n.configured&&n.filesExist&&n.isWildcard;n.configured?n.filesExist?n.isWildcard||console.log(O(Qi("non_wildcard",e.dotDomain))):console.log(O({level:"warning",title:"TLS Certificate Files Inaccessible",message:n.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(Qi("missing",e.dotDomain)));let i=e.disableHttps?"Disabled (--disable-https)":s?`https://${e.host}:${e.httpsPort}`:n.configured?`Disabled (Files Inaccessible: ${n.error||"Check Permissions"})`:"Disabled (TLS Certificates Not Configured)",c=e.disableDot?"Disabled (--disable-dot)":n.configured?n.filesExist?n.isWildcard?`tls://${e.host}:${e.dotPort}`:"Paused (Requires Wildcard Certificate *.domain)":`Disabled (Files Inaccessible: ${n.error||"Check Permissions"})`:"Disabled (TLS Certificates Not Configured)";console.log(Ye({title:"[Services] Configured Ports & Transports:",items:[{label:"Web Dashboard & DoH (HTTP)",value:s?`http://${e.host}:${e.httpPort} (Redirects to HTTPS)`:`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}]})),Ne(t.JWT_SECRET)&&!_t(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=null;if(e.databaseService==="Turso"){(!e.tursoDatabaseUrl||!e.tursoAuthToken)&&(console.error(O({level:"error",title:"Database Configuration Error",message:"DATABASE_SERVICE is set to 'Turso', but TURSO_DATABASE_URL or TURSO_AUTH_TOKEN is missing.",solutions:["Set TURSO_DATABASE_URL and TURSO_AUTH_TOKEN in .env or via CLI arguments (--turso-url, --turso-token).","Alternatively, set DATABASE_SERVICE='File' to use local SQLite."]})),process.exit(1)),console.log(`[Database] Using Turso Database: ${an(e.tursoDatabaseUrl)}`);let g=ln(e.tursoDatabaseUrl,e.tursoAuthToken),w=Jp.join(e.packageRoot,"migrations");await ya(g,w),t.DB=g}else if(e.databaseService==="D1")console.error(O({level:"error",title:"Database Configuration Error",message:"DATABASE_SERVICE='D1' is designed for Cloudflare Workers environments with D1 bindings.",solutions:["In Serverfull mode, please set DATABASE_SERVICE='File' (default local SQLite) or DATABASE_SERVICE='Turso'."]})),process.exit(1);else{let g=ms(e.dbPath);a=g,t.DB=g}let l=e.disableUdp?null:new To({port:e.udpPort,host:e.host,defaultProfileKey:e.defaultProfileKey,env:t}),u=o?new Ao({port:e.dotPort,host:e.host,tlsKeyPath:e.tlsKeyPath,tlsCertPath:e.tlsCertPath,dotDomain:e.dotDomain,defaultProfileKey:e.defaultProfileKey,env:t}):null,d=new No({port:e.httpPort,host:e.host,env:t,httpsRedirect:s?{enabled:!0,httpsPort:e.httpsPort}:void 0}),p=s?new Io({port:e.httpsPort,host:e.host,certPath:e.tlsCertPath,keyPath:e.tlsKeyPath,env:t}):null;l&&await l.start(),u&&await u.start(),await d.start(),p&&await p.start();let f=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 Lo.scheduled(g,t,w)}catch(g){console.error("[Cron Scheduler Error]:",g)}},6e4),m=!!(n.configured&&n.filesExist);console.log(xe({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:u&&m?`tls://${e.dotDomain||e.host}:${e.dotPort}`:n.configured?n.filesExist?n.isWildcard?"Disabled":"Paused (Requires Wildcard Certificate *.domain)":`Disabled (Files Inaccessible: ${n.error||"Check Permissions"})`:"Disabled / Not Configured"},{label:"Web UI & DoH (HTTP)",value:`http://${e.host}:${e.httpPort}`},{label:"Web UI & DoH (HTTPS)",value:p?`https://${e.dotDomain||e.host}:${e.httpsPort}`:n.configured?n.filesExist?"Disabled":`Disabled (Files Inaccessible: ${n.error||"Check Permissions"})`:"Disabled / Not Configured"},{label:"Database Engine",value:e.databaseService==="Turso"?`Turso (${an(e.tursoDatabaseUrl)})`:`SQLite (${e.dbPath})`}]}));let h=async g=>{console.log(`
|
|
538
|
+
[Serverfull] Received ${g}. Shutting down gracefully...`),clearInterval(f),await Promise.all([l?.stop(),u?.stop(),d.stop(),p?.stop()]);try{await fo(t)}catch{}if(a)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"))}Gp().catch(r=>{let e=r?.code;if(e!=="EACCES"&&e!=="EADDRINUSE"){let t=r instanceof Error?r.message:String(r);console.error(O({level:"error",title:"Serverfull - Fatal Startup Error",message:t}))}process.exit(1)});export{hu as checkNodeVersion,jp as handleConfigCommand,Vp as handleEchCommand,gu as parseCli,la as printHelp};
|
|
539
539
|
//# sourceMappingURL=serverfull.mjs.map
|