dns-worker 1.1.4-canary.9ff8559 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/serverfull.mjs +17 -17
- package/dist/serverfull.mjs.map +3 -3
- package/package.json +3 -2
- package/static/assets/{AccountView-CVqM49FF.js → AccountView-C8B4Bc-T.js} +3 -3
- package/static/assets/{AnalyticsView-CdMxSJPm.js → AnalyticsView-D7BTnKlw.js} +2 -2
- package/static/assets/{DestinationMap-DYPQPrpn.js → DestinationMap-ILIFQ8kh.js} +1 -1
- package/static/assets/{FilteringView-DnSDokeJ.js → FilteringView-omSHWCn-.js} +1 -1
- package/static/assets/{LogsView-Dy2CgweL.js → LogsView-BJCXSnJt.js} +3 -3
- package/static/assets/{RulesView-DYUN5LiV.js → RulesView-DdCGroNG.js} +1 -1
- package/static/assets/{SettingsView-D-u2Wgxt.js → SettingsView-Ts3_vNFF.js} +1 -1
- package/static/assets/{SetupView-D659Vgyp.js → SetupView-BZB2zVie.js} +1 -1
- package/static/assets/{TrendChart-DmAYAuwW.js → TrendChart-fLn-W0HW.js} +1 -1
- package/static/assets/date-BWIs3jEk.js +1 -0
- package/static/assets/{index-CXPqlmSb.js → index-BQkd-FVt.js} +5 -5
- package/static/assets/index-BcgJ7kqG.css +2 -0
- package/static/assets/{services-Cc0Uqlqe.js → services-BZ8vUefB.js} +1 -1
- package/static/index.html +2 -2
- package/static/sw.js +1 -1
- package/static/assets/date-Bh9cxBZp.js +0 -1
- package/static/assets/index-CbbrI5Ms.css +0 -2
package/dist/serverfull.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var Eu=Object.defineProperty;var Qe=(r,e,t)=>()=>{if(t)throw t[0];try{return r&&(e=r(r=0)),e}catch(n){throw t=[n],n}};var Ho=(r,e)=>{for(var t in e)Eu(r,t,{get:e[t],enumerable:!0})};var
|
|
2
|
+
var Eu=Object.defineProperty;var Qe=(r,e,t)=>()=>{if(t)throw t[0];try{return r&&(e=r(r=0)),e}catch(n){throw t=[n],n}};var Ho=(r,e)=>{for(var t in e)Eu(r,t,{get:e[t],enumerable:!0})};var Pa,P,ge=Qe(()=>{"use strict";Pa="https://obex-dns.internal",P={setOrigin(r){r&&(r.startsWith("http://")||r.startsWith("https://"))&&(Pa=r.replace(/\/+$/,""))},generateCacheUrl(r){return`${Pa}/__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 Rr(r){let e=r.cf;if(e&&e.latitude&&e.longitude){let s=parseFloat(e.latitude),o=parseFloat(e.longitude);if(!isNaN(s)&&!isNaN(o))return{latitude:s,longitude:o}}let t=r.headers.get("CF-IPLatitude"),n=r.headers.get("CF-IPLongitude");if(t&&n){let s=parseFloat(t),o=parseFloat(n);if(!isNaN(s)&&!isNaN(o))return{latitude:s,longitude:o}}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 ci=Qe(()=>{"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 at(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 bt(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+=li[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 va(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 li,Se=Qe(()=>{"use strict";li="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 qe(){return`${Sn}=; HttpOnly; SameSite=Lax; Path=/; Max-Age=0; Secure`}function Le(r){if(!r)return null;let e=r.match(new RegExp(`(?:^|;\\s*)${Sn}=([^;]*)`));return e?e[1]:null}function ct(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 Ps(r){if(!r)return null;let e=r.match(new RegExp(`(?:^|;\\s*)${Tn}=([^;]*)`));return e?e[1]:null}var Sn,Tn,Ca=Qe(()=>{"use strict";Sn="auth_refresh",Tn="preauth_session"});var Rn={};Ho(Rn,{SessionModel:()=>ae});var ae,Fe=Qe(()=>{"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,7 +10,7 @@ var Eu=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:Fu.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}:${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 ui,Fu,Hu,He=Qe(()=>{"use strict";ui=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,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 gl={};Ho(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 $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,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,Qn=Qe(()=>{"use strict";pe();He();Fe();cr=new Map,Nt=new Map});import Vp from"node:path";var ss=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 ss;globalThis.caches={default:r,open:async()=>new ss}}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 os=[{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"}],is=[{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"}],as=[{ip:"198.41.222.102",area:"SG"},{ip:"173.245.59.246",area:"SG"},{ip:"104.18.47.174",area:"HK"},{ip:"104.19.50.3",area:"HK"}],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===`
|
|
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 vs(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:Fu.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}:${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 Pr(r,e){let t=r.split(".");if(t.length!==3)return null;let[n,s,o]=t,i=`${n}.${s}`,c=vs(o);if(!await crypto.subtle.verify("HMAC",e,c,ka(i)))return null;try{let l=vs(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,Fu,Hu,He=Qe(()=>{"use strict";ui=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 Pe(r){try{let e=new TextDecoder().decode(vs(r));return JSON.parse(e)}catch{return null}}async function vr(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=Pe(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,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 Pn(r,e){await new ae(r.DB).deletePendingTotpSession(e)}async function et(r,e,t){let n=`preauth_state:${e}`,s=await P.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 P.delete(r,n),0;let i=Number(t.PREAUTH_TTL_SECONDS)||300;return await P.set(r,n,{...s,failedAttempts:o},i),3-o}var La=Qe(()=>{"use strict";Fe();Se();fi();ge()});var vn={};Ho(vn,{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:()=>vr,extractSaltHex:()=>Rs,generateId:()=>j,generateSessionHash:()=>ee,generateZBase32Token:()=>Wt,getJwtSecretStatus:()=>Ar,getOrCreateJwtSecret:()=>$e,getRequestCoordinates:()=>Rr,hmacSha256:()=>xs,invalidatePreauthSession:()=>Pn,invalidateSession:()=>St,isMissingJwtSecret:()=>di,isPresetJwtSecret:()=>pi,isStrongJwtSecret:()=>_t,isUsableJwtSecret:()=>Oe,parseRefreshTokenString:()=>Pe,readCsrfCookie:()=>xr,readPreauthCookie:()=>Ps,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 gl={};Ho(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 $e(e),i=await Ne(o),c=await Pr(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,Qn=Qe(()=>{"use strict";pe();He();Fe();cr=new Map,Nt=new Map});import Vp from"node:path";var ss=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 ss;globalThis.caches={default:r,open:async()=>new ss}}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 os=[{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"}],is=[{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"}],as=[{ip:"198.41.222.102",area:"SG"},{ip:"173.245.59.246",area:"SG"},{ip:"104.18.47.174",area:"HK"},{ip:"104.19.50.3",area:"HK"}],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
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 jo=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}
|
|
@@ -232,19 +232,19 @@ PRESET_ECH_FRONTING_DOMAINS='["cloudflare-ech.com","crypto.cloudflare.com","one.
|
|
|
232
232
|
# Substitute Region IPs mapping (JSON string) / \u8F85\u52A9\u57DF\u540D\u5404\u533A\u57DF\u89E3\u6790 IP \u6620\u5C04 (JSON \u5B57\u7B26\u4E32)
|
|
233
233
|
IP_REGION_CN='[{"ip":"198.41.222.102","area":"SG"},{"ip":"173.245.59.246","area":"SG"},{"ip":"104.18.47.174","area":"HK"},{"ip":"104.19.50.3","area":"HK"}]'
|
|
234
234
|
`;function Me(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,Yo,{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 st(){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(st(),"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 Ze(){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(Ze(),"dns_worker.sqlite")}function gr(){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 Be(){return re.join(gr(),".env")}function yr(r=!0){let e=Ze(),t=gr(),n=Be();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{Me(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(`
|
|
235
|
-
`);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()){yr(!0),ds.length=0;let e=[dn.join(r,".dev.vars"),dn.join(r,".env"),dn.join(r,".env.serverfull"),Be(),process.platform==="linux"?"/etc/dns-worker/.env":null,process.platform==="linux"?"/etc/default/dns-worker":null,process.platform==="linux"?dn.join(Ze(),".env"):null,dn.join(st(),".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=Ze()){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){yr(),fs();let e=st(),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},
|
|
235
|
+
`);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()){yr(!0),ds.length=0;let e=[dn.join(r,".dev.vars"),dn.join(r,".env"),dn.join(r,".env.serverfull"),Be(),process.platform==="linux"?"/etc/dns-worker/.env":null,process.platform==="linux"?"/etc/default/dns-worker":null,process.platform==="linux"?dn.join(Ze(),".env"):null,dn.join(st(),".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=Ze()){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){yr(),fs();let e=st(),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},v={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(os),PRESET_EXTERNAL_FILTERS:process.env.PRESET_EXTERNAL_FILTERS||JSON.stringify(is),IP_REGION_CN:process.env.IP_REGION_CN||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:v}}import yt from"node:fs";import wr from"node:path";import{DatabaseSync as Pu}from"node:sqlite";var Xo=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}
|
|
236
236
|
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}
|
|
237
237
|
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}
|
|
238
238
|
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}
|
|
239
|
-
SQL: ${this.sql}`),t}}},zo=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 Xo(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
|
|
239
|
+
SQL: ${this.sql}`),t}}},zo=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 Xo(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 vu(r,e){if(r.exec(`
|
|
240
240
|
CREATE TABLE IF NOT EXISTS _cf_d1_migrations (
|
|
241
241
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
242
242
|
name TEXT UNIQUE NOT NULL,
|
|
243
243
|
applied_at INTEGER NOT NULL
|
|
244
244
|
);
|
|
245
|
-
`),!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 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=wr.join(e,"migrations");return Pu(n,s),new zo(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 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 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=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,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 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(`
|
|
245
|
+
`),!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 vu(n,s),new zo(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 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 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=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,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 v=0;v<R;v++)D+=String.fromCharCode(r[_+1+v]);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 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(`
|
|
246
246
|
`),...a.split(`
|
|
247
|
-
`)].map(p=>p.trim()).filter(p=>p.length>0&&!p.startsWith("#")).filter(p=>qo(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),ri(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 Er(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 si(r,e,t=0){try{if(!r||r.length<12)return Er(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}=ot(r,s);if(p===0||(s+=p+4,s>r.length))return Er(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 Er(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}=ot(r,i);if(h===0||(i+=h+4,i>r.length))return Er(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 ii(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=oi(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=oi(r,u),l=u;break}u=oi(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 oi(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 _r=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 _r(3),En=new _r(200),Sr=new _r(500),_n=new _r(500),Tr=null;function ai(r){Tr=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(),Tr=null;for(let o of Sr.keys())o.startsWith(`${r}:`)&&Sr.delete(o);try{if(typeof caches<"u"&&caches&&caches.default){let o=caches.default,i=[
|
|
247
|
+
`)].map(p=>p.trim()).filter(p=>p.length>0&&!p.startsWith("#")).filter(p=>qo(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),ri(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 Er(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 si(r,e,t=0){try{if(!r||r.length<12)return Er(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}=ot(r,s);if(p===0||(s+=p+4,s>r.length))return Er(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 Er(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}=ot(r,i);if(h===0||(i+=h+4,i>r.length))return Er(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 ii(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=oi(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=oi(r,u),l=u;break}u=oi(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 oi(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 _r=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 _r(3),En=new _r(200),Sr=new _r(500),_n=new _r(500),Tr=null;function ai(r){Tr=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(),Tr=null;for(let o of Sr.keys())o.startsWith(`${r}:`)&&Sr.delete(o);try{if(typeof caches<"u"&&caches&&caches.default){let o=caches.default,i=[P.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(`
|
|
248
248
|
SELECT * FROM (
|
|
249
249
|
SELECT p.*, ap.id as access_point_id, ap.name as access_point_name, 1 as priority
|
|
250
250
|
FROM access_points ap
|
|
@@ -257,7 +257,7 @@ SQL: ${this.sql}`),t}}},zo=class{constructor(e,t){this.rawDb=e;this.dbPath=t}raw
|
|
|
257
257
|
)
|
|
258
258
|
ORDER BY priority ASC
|
|
259
259
|
LIMIT 1
|
|
260
|
-
`).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}$/,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"],$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"],mi=ys(Wu);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 $u)if(n.endsWith(o)||n===o.slice(1))return!1;if(n.includes("metadata.google"))return!1;let s=Ku(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 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=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=${b}`;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 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=ke(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=ke(u),p="ECH Rewritten"}}}return{answer:u,parsedAnswers:d,effectiveReason:p}}ge();var Gt=new Map,Ha=336*60*60*1e3;async function Ln(r){if(!tt(r))return null;let e=`geoip:${r}`,t=Date.now(),n=Gt.get(e);if(n){if(t<n.expiresAt)return n.data;Gt.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 Gt.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(Gt.size>=1e5){let c=Gt.keys().next().value;c!==void 0&&Gt.delete(c)}if(Gt.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 Jt(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 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=`
|
|
260
|
+
`).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=P.generateCacheUrl(`bloom-bin:${t}`),f=await P.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(P.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}$/,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"],$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"],mi=ys(Wu);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 $u)if(n.endsWith(o)||n===o.slice(1))return!1;if(n.includes("metadata.google"))return!1;let s=Ku(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 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=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=${b}`;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 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=ke(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=ke(u),p="ECH Rewritten"}}}return{answer:u,parsedAnswers:d,effectiveReason:p}}ge();var Gt=new Map,Ha=336*60*60*1e3;async function Ln(r){if(!tt(r))return null;let e=`geoip:${r}`,t=Date.now(),n=Gt.get(e);if(n){if(t<n.expiresAt)return n.data;Gt.delete(e)}let s=null;if(typeof caches<"u"&&caches.default&&(s=caches.default),s)try{let i=await P.get(s,e);if(i)return Gt.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(Gt.size>=1e5){let c=Gt.keys().next().value;c!==void 0&&Gt.delete(c)}if(Gt.set(e,{data:i,expiresAt:t+Ha}),s)try{await P.set(s,e,i,86400*14)}catch(c){console.warn("Cloudflare Cache API write error:",c)}};try{let i=await fetch(`http://ip-api.com/json/${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 Jt(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 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=`
|
|
261
261
|
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
|
|
262
262
|
FROM logs l
|
|
263
263
|
LEFT JOIN kem_keys k ON l.kem_key_id = k.id
|
|
@@ -324,7 +324,7 @@ SQL: ${this.sql}`),t}}},zo=class{constructor(e,t){this.rawDb=e;this.dbPath=t}raw
|
|
|
324
324
|
AND (dest_country_code IS NOT NULL OR dest_geoip IS NOT NULL)
|
|
325
325
|
AND COALESCE(dest_isp, json_extract(dest_geoip, '$.isp')) IS NOT NULL
|
|
326
326
|
AND COALESCE(dest_isp, json_extract(dest_geoip, '$.isp')) != ''
|
|
327
|
-
`,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 $a(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 ja(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)},Ka=(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 Nn(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 Va=new Uint8Array(new Uint32Array([287454020]).buffer)[0]===68;function Ju(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]=Ju(r[e]);return r}var Ir=Va?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 In(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 Wa(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=Wa(r.charCodeAt(o)),c=Wa(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 Ka(r,"defaults"),e!==void 0&&Ka(e,t),Object.assign(Object.create(null),r,e)}function Un(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 Mn(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 Ya(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=In,We=(...r)=>Ei(...r),Gs=r=>bi(r),Ur=Xt,Js=r=>js(r),Vs=BigInt(0),Ja=BigInt(1),zu=r=>r?`"${r}" `:"";function je(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 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 Bn(r){let e=Ys(r).toString(16);return e.length&1?"0"+e:e}function Xa(r){if(typeof r!="string")throw new TypeError("hex string expected, got "+typeof r);return r===""?Vs:BigInt("0x"+r)}function Ve(r){return Xa(In(r))}function Xs(r){return Xa(In(Qu(Y(r)).reverse()))}function Fn(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 Fn(r,e).reverse()}function Qu(r){return Uint8Array.from(fe(r))}function za(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 Hn=r=>(Qt(r,"n"),(Ja<<BigInt(r))-Ja);function Qa(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,w=[];for(;g<e;){a=p();let b=a.slice();w.push(b),g+=a.length}return We(...w)};return(g,w)=>{d(),f(g);let b;for(;(b=w(m()))===void 0;)f();return d(),b}}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),tc=BigInt(3),Di=BigInt(4),rc=BigInt(5),Zu=BigInt(7),nc=BigInt(8),qu=BigInt(9),ed=BigInt(15),sc=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 oc(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>>=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 Za(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 ic(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=oc(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 ac(r,e){let t=r,n=(t.ORDER+Q)/Di,s=t.pow(e,n);return vi(t,s,e),s}function rd(r,e){let t=r,n=(t.ORDER-rc)/nc,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 nd(r){let e=Qs(r),t=cc(r),n=t(e,e.neg(e.ONE)),s=t(e,n),o=t(e,e.neg(n)),i=(r+Zu)/sc;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 vi(l,w,a),w})}function cc(r){if(r<tc)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(;qa(s,n)===1;)if(n++>1e3)throw new Error("Cannot find square root: probably non-prime P");if(t===1)return ac;let o=s.pow(n,e),i=(e+Q)/kt;return function(a,l){let u=a;if(u.is0(l))return l;if(qa(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 Pi(r,"Fp.sqrt"),r%Di===tc?ac:r%nc===rc?rd:r%sc===qu?nd(r):cc(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)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),Mn(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 qa(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 id(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 ec=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 oc(e,t,this.ORDER)}div(e,t){return Pe(e*Za(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 Za(e,this.ORDER)}sqrt(e){let t=ec.get(this);return t||ec.set(this,t=sd(this.ORDER)),t(this,e)}toBytes(e){return this.isLE?Ri(e,this.BYTES):Fn(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 lc(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=lc(r);return e+Math.ceil(e/2)}function ki(r,e,t=!1){fe(r);let n=r.length,s=lc(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):Fn(c,s)}var Ni=BigInt(0),$n=BigInt(1),ad=BigInt(4),Li=16,uc=128,cd=5,dc=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 fc(r,e){Fr(r),mc(e,r);let t=Ci(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>dc)throw new Error("invalid window size: table would need ~"+Math.ceil(t/2**20)+" MiB, max "+dc/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 mc(r,e){Mn(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 hc=new WeakMap;function Oi(r){return hc.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>Ni;){let i=0;r&$n&&(i=Number(r&s),i>=n&&(i-=t),r-=BigInt(i)),o.push(i),r>>=$n}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+=$n),c.push(l)}if(r!==Ni)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=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=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),!xi(t,$n,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+uc,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=cd,o=1<<s,i=Hn(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===$n?!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),ld(t,this.bits);let n=Math.ceil((this.bits+uc)/t)+1;ud(n*2**(t-1),this.Point.Fp.BYTES),hc.set(e,t),this.wnafPrecomputes.delete(e)}hasWindowSize(e){return Oi(e)!==1}};function eo(r,e,t,n=!1){if(Fr(r),mc(e,r),je(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 pc(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 gc(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=pc(e.p,t.Fp,n),o=pc(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 yc(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()}},wc=(()=>{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),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(Ya(e,"data"),e.length&1)throw new t("tlv.encode: unpadded data");let n=e.length/2,s=Bn(n);if(s.length/2&128)throw new t("tlv.encode: long form length too big");let o=n>127?Bn(s.length/2|128):"";return Bn(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<gd)throw new e("integer: negative integers are not allowed");let t=Bn(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 bc=(r,e)=>(r+(r>=0?e:-e)/Ec)/e;function yd(r,e,t){Ai("scalar",r,pt,t);let[[n,s],[o,i]]=e,c=bc(i*r,t),a=bc(-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=Hn(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),Ec=BigInt(2),Bi=BigInt(3),wd=BigInt(4);function _c(r,e={}){let t=gc("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?Js: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=Tc(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(je(A,"isCompressed"),A){w();let B=!n.isOdd(I);return We(Sc(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 G=W instanceof Error?": "+W.message:"";throw new Error("bad point: is not on curve, sqrt error"+G)}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,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),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(Gs(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),G=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,G),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(G,Z),ie=n.sub(ie,F),U=x(te),F=n.mul(S,Z),U=n.add(F,U),F=n.sub(G,U),U=n.add(G,U),H=n.mul(F,U),G=n.add(W,W),G=n.add(G,W),Z=x(Z),te=n.mul(S,te),G=n.add(G,Z),Z=n.sub(W,Z),Z=x(Z),te=n.add(te,Z),W=n.mul(G,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,G),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=>fc(K,L),we=new qs(K,m);return we.bits>=6&&K.BASE.precompute(6),Object.freeze(K.prototype),Object.freeze(K),K}function Sc(r){return Uint8Array.of(r?2:3)}function Tc(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?Js:e.randomBytes,s=Object.assign(Tc(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,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,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=yc(c,a);return Object.freeze(d),Object.freeze(s),Object.freeze({getPublicKey:a,getSharedSecret:u,keygen:p,Point:r,utils:d,lengths:s})}function Rc(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?Js:s.randomBytes,i=s.hmac===void 0?(L,T)=>wc(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:w}=bd(r,s),b={prehash:!0,lowS:typeof s.lowS=="boolean"?s.lowS:!0,format:"compact",extraEntropy:!1},y=l*Ec+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=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(Gs(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(Sc((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),G=r.BASE.mulAddUnsafe(U,$,W);if(G.is0())throw new Error("invalid recovery: point at infinify");return G.assertValidity(),G}hasHighS(){return E(this.s)}toBytes(T=b.format){if(Fi(T),T==="der")return Gs(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=Hn(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,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 G=M===!0?o(w.secretKey):M;F.push(fe(G,void 0,"extraEntropy"))}let H=We(...F),U=B;function W(G){let Z=k(G);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)),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=ic(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 Qa(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,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),G=a.inv(U),Z=a.create(W*G),Ce=a.create(H*G),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,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),xc=BigInt(32);function Ed(r,e=!1){return e?{h:Number(r&no),l:Number(r>>xc&no)}:{h:Number(r>>xc&no)|0,l:Number(r&no)|0}}function Ac(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 Dc(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 vc(r,e,t){return r&e^~r&t}function Pc(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)),Dc(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()}},Cc=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),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+vc(c,a,l)+Td[d]+Lt[d]|0,h=(Ke(n,2)^Ke(n,13)^Ke(n,22))+Pc(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,Cc)}};var kc=Un(()=>new $i,zt(1));function Kn(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 Oc(r){return Kn(r,"x"),(r&r-1)===0&&r!==0}function Ki(r,e){if(Kn(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 Nc(r){return Kn(r),31-Math.clz32(r)}function Lc(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(!Oc(e))throw new Error("expected positive power-of-two length, got "+e);let t=Nc(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;Kn(t,"coreOpts.N");let a=Nc(t);if(!Oc(t))throw new Error("FFT: Polynomial size should be power of two");Kn(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&&Lc(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&&Lc(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=_c(Rd),Ic=Rc(xd,kc);var Ad=BigInt(0),Wn=BigInt(1),Dd=BigInt(2),vd=BigInt(7),Pd=BigInt(256),Cd=BigInt(113),Bc=[],Fc=[],Hc=[];for(let r=0,e=Wn,t=1,n=0;r<24;r++){[t,n]=[n,(2*t+3*n)%5],Bc.push(2*(5*n+t)),Fc.push((r+1)*(r+2)/2%64);let s=Ad;for(let o=0;o<7;o++)e=(e<<Wn^(e>>vd)*Cd)%Pd,e&Dd&&(s^=Wn<<(Wn<<BigInt(o))-Wn);Hc.push(s)}var $c=Ac(Hc,!0),kd=$c[0],Ld=$c[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,Uc=(r,e,t)=>t>32?Id(r,e,t):Od(r,e,t),Mc=(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=Uc(a,l,1)^Hr[i],d=Mc(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=Fc[o],c=Uc(n,s,i),a=Mc(n,s,i),l=Bc[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"),ja(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=Nn(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){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?Nn(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}},Kc=(r,e,t,n={})=>Un(()=>new oo(e,r,t),n);var io=Kc(6,136,32,zt(8));var Wc=Kc(6,72,64,zt(10));var jc=(r,e,t,n={})=>Un((s={})=>(s=_i({},s),new oo(e,r,s.dkLen===void 0?t:s.dkLen,!0)),n),Vc=jc(31,168,16,zt(11)),$r=jc(31,136,32,zt(12));var Ge=Y;var ft=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 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=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 _=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}),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)}}},Jc=Fd(Vc);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}),jn=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 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 Jd=(r,e)=>{let t=new Uint16Array(Ee),n=Nn(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 Vn(r,e,t,n){return Jd(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=jn(1),d=jn(l),p=jn(a),f=er("publicKey",ao(jn(12),t),32),m=ao(jn(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(Vn(n,_,k,i)));let x=new Uint16Array(Ee),R=[];for(let k=0;k<t;k++){let N=Vn(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=Vn(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(Vn(n,S,k,i)));let D=s(_);for(let k=0;k<t;k++){let N=Re.NTT.encode(Vn(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:(b,y,E)=>{let[_,S]=f.decode(b),x=s(S),R=w(_,(D,P)=>Vi(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(Vi(_.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(mt(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?ft(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?ft(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=mt(f),h=n(m),g=t.prepare(m);return Object.freeze({publicKey:m,encapsulate:w=>{let b=w===void 0,y=b?ft(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:Wc,KDF:$r,XOF:Jc,PRF:zd},Zd=r=>Xd({...Qd,...r});var Yc=Zd(Kd[768]);var qd=(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 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?mt(d):d,f=[],m=[],h=[],g=[],w=!1;try{for(let b of o.decode(p))f.push(mt(b));for(let b=0;b<s.length;b++){let y=s[b].keygen(f[b]);m.push(y.secretKey),h.push(mt(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?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 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 mt(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=ft(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=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 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(We(d[0],d[1],u[1],l[1],za(r))),e,i)}var Xc=np("MLKEM768-P256",Yc,Ic,128);function zc(r){let e=Xc.encapsulate(r);return{kemCtBase64:Yt(e.cipherText),sharedSecret:e.sharedSecret}}async function Qc(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 Zc(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,po=new Map,uo=new Map;function qc(r){return po.get(r)||null}async function el(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 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}=zc(i),l=await Qc(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 po.set(e,d),d}function tl(r){po.delete(r),uo.delete(r)}var Ji=new Map;async function ip(r,e){let t=Date.now(),n=Ji.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 Ji.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){Ji.delete(r),tl(r)}var rr=[],rl=50,nl=15e3,Gi=3600,fo=0,Jn=!1,sl=Date.now();async function ap(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 cp(r){let t=Math.floor(Date.now()/1e3)+Gi;if(fo=t*1e3,rr.length=0,Jn=!1,console.warn(`[LogBatcher] D1 write quota limit reached! Silencing log writes for ${Gi}s.`),r)try{await v.set(r,"d1:write_quota_tripped",t,Gi)}catch{}}async function mo(r,e){if(Jn=!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 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 ip(r.DB,l);if(u&&(c.set(l,u),"pqc_pk"in u)){let d=qc(l);d||(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 Zc(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 $a(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(Jn)return;Jn=!0;let t=new Promise(n=>setTimeout(n,nl)).then(()=>mo(r,e)).catch(n=>{Jn=!1,console.error("[LogBatcher] Deferred flush error:",n)});e&&typeof e.waitUntil=="function"&&e.waitUntil(t)}function Yn(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>=rl||o-sl>=nl?n.waitUntil(mo(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=ke(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=si(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 Jt(r,l);Yn({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=Jt(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;Yn({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&&Sr.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 Jt(r,h);Yn({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 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(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,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 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"),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 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 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 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 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 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=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 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=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 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=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),w={ciphertext:jr(new Uint8Array(g)),iv:jr(h),kek_version:i};return JSON.stringify(w)}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(`
|
|
327
|
+
`,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 $a(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 ja(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)},Ka=(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 Nn(r){return new Uint32Array(r.buffer,r.byteOffset,Math.floor(r.byteLength/4))}function Pt(...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 Va=new Uint8Array(new Uint32Array([287454020]).buffer)[0]===68;function Ju(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]=Ju(r[e]);return r}var Ir=Va?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 In(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 Wa(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=Wa(r.charCodeAt(o)),c=Wa(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 Ka(r,"defaults"),e!==void 0&&Ka(e,t),Object.assign(Object.create(null),r,e)}function Un(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 Mn(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 Ya(r,e=""){if(typeof r!="string"){let t=e&&`"${e}" `;throw new TypeError(t+"expected string, got type="+typeof r)}return r}function vt(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=In,We=(...r)=>Ei(...r),Gs=r=>bi(r),Ur=Xt,Js=r=>js(r),Vs=BigInt(0),Ja=BigInt(1),zu=r=>r?`"${r}" `:"";function je(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 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 Bn(r){let e=Ys(r).toString(16);return e.length&1?"0"+e:e}function Xa(r){if(typeof r!="string")throw new TypeError("hex string expected, got "+typeof r);return r===""?Vs:BigInt("0x"+r)}function Ve(r){return Xa(In(r))}function Xs(r){return Xa(In(Qu(Y(r)).reverse()))}function Fn(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 Fn(r,e).reverse()}function Qu(r){return Uint8Array.from(fe(r))}function za(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 Hn=r=>(Qt(r,"n"),(Ja<<BigInt(r))-Ja);function Qa(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,w=[];for(;g<e;){a=p();let b=a.slice();w.push(b),g+=a.length}return We(...w)};return(g,w)=>{d(),f(g);let b;for(;(b=w(m()))===void 0;)f();return d(),b}}function rt(r,e={},t={},n="object"){vt(r,n),vt(e,"fields"),vt(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),tc=BigInt(3),Di=BigInt(4),rc=BigInt(5),Zu=BigInt(7),nc=BigInt(8),qu=BigInt(9),ed=BigInt(15),sc=BigInt(16),td=BigInt("0x10000000000000000");function ve(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 oc(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>>=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 Za(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=ve(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 ve(s,e)}function ic(r,e){if(e<=Q)throw new Error("invertCt: expected prime modulus > 1, got "+e);let t=ve(r,e);if(t===ye)throw new Error("invertCt: expected non-zero number");let n=oc(t,e-kt,e);if(ve(t*n,e)!==Q)throw new Error("invertCt: does not exist");return n}function Pi(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 ac(r,e){let t=r,n=(t.ORDER+Q)/Di,s=t.pow(e,n);return Pi(t,s,e),s}function rd(r,e){let t=r,n=(t.ORDER-rc)/nc,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 Pi(t,a,e),a}function nd(r){let e=Qs(r),t=cc(r),n=t(e,e.neg(e.ONE)),s=t(e,n),o=t(e,e.neg(n)),i=(r+Zu)/sc;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 Pi(l,w,a),w})}function cc(r){if(r<tc)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(;qa(s,n)===1;)if(n++>1e3)throw new Error("Cannot find square root: probably non-prime P");if(t===1)return ac;let o=s.pow(n,e),i=(e+Q)/kt;return function(a,l){let u=a;if(u.is0(l))return l;if(qa(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%Di===tc?ac:r%nc===rc?rd:r%sc===qu?nd(r):cc(r)}var od=["create","isValid","is0","neg","inv","sqrt","sqr","eql","add","sub","mul","pow","div","addN","subN","mulN","sqrN"];function Br(r){if(vt(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)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),Mn(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 qa(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&&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 ec=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 ve(e,this.ORDER)}isValid(e){if(typeof e!="bigint")throw new TypeError("invalid field element: expected bigint, got "+typeof e);return ye<=e&&e<this.ORDER}is0(e){return e===ye}isValidNot0(e){return!this.is0(e)&&this.isValid(e)}isOdd(e){return(e&Q)===Q}neg(e){return ve(-e,this.ORDER)}eql(e,t){return e===t}sqr(e){return ve(e*e,this.ORDER)}add(e,t){return ve(e+t,this.ORDER)}sub(e,t){return ve(e-t,this.ORDER)}mul(e,t){return ve(e*t,this.ORDER)}pow(e,t){return oc(e,t,this.ORDER)}div(e,t){return ve(e*Za(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 Za(e,this.ORDER)}sqrt(e){let t=ec.get(this);return t||ec.set(this,t=sd(this.ORDER)),t(this,e)}toBytes(e){return this.isLE?Ri(e,this.BYTES):Fn(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=ve(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 lc(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=lc(r);return e+Math.ceil(e/2)}function ki(r,e,t=!1){fe(r);let n=r.length,s=lc(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=ve(i,e-Q)+Q;return t?Ri(c,s):Fn(c,s)}var Ni=BigInt(0),$n=BigInt(1),ad=BigInt(4),Li=16,uc=128,cd=5,dc=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"),vt(e.BASE,"Point.BASE"),vt(e.ZERO,"Point.ZERO"),Br(e.Fp),Br(e.Fn)}function fc(r,e){Fr(r),mc(e,r);let t=Ci(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>dc)throw new Error("invalid window size: table would need ~"+Math.ceil(t/2**20)+" MiB, max "+dc/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 mc(r,e){Mn(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 hc=new WeakMap;function Oi(r){return hc.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>Ni;){let i=0;r&$n&&(i=Number(r&s),i>=n&&(i-=t),r-=BigInt(i)),o.push(i),r>>=$n}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+=$n),c.push(l)}if(r!==Ni)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=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=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),!xi(t,$n,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+uc,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=cd,o=1<<s,i=Hn(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===$n?!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),ld(t,this.bits);let n=Math.ceil((this.bits+uc)/t)+1;ud(n*2**(t-1),this.Point.Fp.BYTES),hc.set(e,t),this.wnafPrecomputes.delete(e)}hasWindowSize(e){return Oi(e)!==1}};function eo(r,e,t,n=!1){if(Fr(r),mc(e,r),je(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 pc(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 gc(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=pc(e.p,t.Fp,n),o=pc(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 yc(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),Pt(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()}},wc=(()=>{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),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(Ya(e,"data"),e.length&1)throw new t("tlv.encode: unpadded data");let n=e.length/2,s=Bn(n);if(s.length/2&128)throw new t("tlv.encode: long form length too big");let o=n>127?Bn(s.length/2|128):"";return Bn(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<gd)throw new e("integer: negative integers are not allowed");let t=Bn(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 bc=(r,e)=>(r+(r>=0?e:-e)/Ec)/e;function yd(r,e,t){Ai("scalar",r,pt,t);let[[n,s],[o,i]]=e,c=bc(i*r,t),a=bc(-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=Hn(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),Ec=BigInt(2),Bi=BigInt(3),wd=BigInt(4);function _c(r,e={}){let t=gc("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?Js: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=Tc(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(je(A,"isCompressed"),A){w();let B=!n.isOdd(I);return We(Sc(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 G=W instanceof Error?": "+W.message:"";throw new Error("bad point: is not on curve, sqrt error"+G)}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,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 v=n.mul(n.pow(o.a,Bi),wd),k=n.mul(n.sqr(o.b),BigInt(27));if(n.is0(n.add(v,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(Gs(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),G=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,G),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(G,Z),ie=n.sub(ie,F),U=x(te),F=n.mul(S,Z),U=n.add(F,U),F=n.sub(G,U),U=n.add(G,U),H=n.mul(F,U),G=n.add(W,W),G=n.add(G,W),Z=x(Z),te=n.mul(S,te),G=n.add(G,Z),Z=n.sub(W,Z),Z=x(Z),te=n.add(te,Z),W=n.mul(G,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,G),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=>fc(K,L),we=new qs(K,m);return we.bits>=6&&K.BASE.precompute(6),Object.freeze(K.prototype),Object.freeze(K),K}function Sc(r){return Uint8Array.of(r?2:3)}function Tc(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?Js:e.randomBytes,s=Object.assign(Tc(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,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,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=yc(c,a);return Object.freeze(d),Object.freeze(s),Object.freeze({getPublicKey:a,getSharedSecret:u,keygen:p,Point:r,utils:d,lengths:s})}function Rc(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?Js:s.randomBytes,i=s.hmac===void 0?(L,T)=>wc(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:w}=bd(r,s),b={prehash:!0,lowS:typeof s.lowS=="boolean"?s.lowS:!0,format:"compact",extraEntropy:!1},y=l*Ec+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=w.signature,C=T==="compact"?A:T==="recovered"?A+1:void 0;return fe(L,C)}class v{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 v($,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 v(a.fromBytes(M),a.fromBytes(B),C)}static fromHex(T,A){return this.fromBytes(Gs(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 v(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(Sc((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),G=r.BASE.mulAddUnsafe(U,$,W);if(G.is0())throw new Error("invalid recovery: point at infinify");return G.assertValidity(),G}hasHighS(){return E(this.s)}toBytes(T=b.format){if(Fi(T),T==="der")return Gs(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(v.prototype),Object.freeze(v);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=Hn(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,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 G=M===!0?o(w.secretKey):M;F.push(fe(G,void 0,"extraEntropy"))}let H=We(...F),U=B;function W(G){let Z=k(G);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)),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=ic(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 v(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 Qa(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,b);if(A=fe(A,void 0,"publicKey"),T=ue(T,M),!Ur(L)){let $=L instanceof v?", use sig.toBytes()":"";throw new Error("verify expects Uint8Array signature"+$)}D(L,B);try{let $=v.fromBytes(L,B),F=r.fromBytes(A);if(F.is0()||I&&$.hasHighS())return!1;let{r:H,s:U}=$,W=N(T),G=a.inv(U),Z=a.create(W*G),Ce=a.create(H*G),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,b);return T=ue(T,C),v.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:v,hash:n})}var no=BigInt(4294967295),xc=BigInt(32);function Ed(r,e=!1){return e?{h:Number(r&no),l:Number(r>>xc&no)}:{h:Number(r>>xc&no)|0,l:Number(r&no)|0}}function Ac(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 Dc(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 vc(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)),Dc(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()}},Cc=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),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)+Td[d]+Lt[d]|0,h=(Ke(n,2)^Ke(n,13)^Ke(n,22))+vc(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(){Pt(Lt)}destroy(){this.destroyed=!0,this.set(0,0,0,0,0,0,0,0),Pt(this.buffer)}},$i=class extends Hi{constructor(){super(32,Cc)}};var kc=Un(()=>new $i,zt(1));function Kn(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 Oc(r){return Kn(r,"x"),(r&r-1)===0&&r!==0}function Ki(r,e){if(Kn(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 Nc(r){return Kn(r),31-Math.clz32(r)}function Lc(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(!Oc(e))throw new Error("expected positive power-of-two length, got "+e);let t=Nc(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;Kn(t,"coreOpts.N");let a=Nc(t);if(!Oc(t))throw new Error("FFT: Polynomial size should be power of two");Kn(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&&Lc(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],v=d[S];if(u){let k=r.mul(D,R);d[S]=r.add(v,k),d[x]=r.sub(v,k)}else o?(d[S]=r.add(D,v),d[x]=r.mul(r.sub(D,v),R)):(d[S]=r.add(v,D),d[x]=r.mul(r.sub(v,D),R))}}return!s&&c&&Lc(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=_c(Rd),Ic=Rc(xd,kc);var Ad=BigInt(0),Wn=BigInt(1),Dd=BigInt(2),Pd=BigInt(7),vd=BigInt(256),Cd=BigInt(113),Bc=[],Fc=[],Hc=[];for(let r=0,e=Wn,t=1,n=0;r<24;r++){[t,n]=[n,(2*t+3*n)%5],Bc.push(2*(5*n+t)),Fc.push((r+1)*(r+2)/2%64);let s=Ad;for(let o=0;o<7;o++)e=(e<<Wn^(e>>Pd)*Cd)%vd,e&Dd&&(s^=Wn<<(Wn<<BigInt(o))-Wn);Hc.push(s)}var $c=Ac(Hc,!0),kd=$c[0],Ld=$c[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,Uc=(r,e,t)=>t>32?Id(r,e,t):Od(r,e,t),Mc=(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=Uc(a,l,1)^Hr[i],d=Mc(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=Fc[o],c=Uc(n,s,i),a=Mc(n,s,i),l=Bc[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]}Pt(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"),ja(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=Nn(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){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?Nn(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,Pt(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}},Kc=(r,e,t,n={})=>Un(()=>new oo(e,r,t),n);var io=Kc(6,136,32,zt(8));var Wc=Kc(6,72,64,zt(10));var jc=(r,e,t,n={})=>Un((s={})=>(s=_i({},s),new oo(e,r,s.dkLen===void 0?t:s.dkLen,!0)),n),Vc=jc(31,168,16,zt(11)),$r=jc(31,136,32,zt(12));var Ge=Y;var ft=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 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=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 _=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}),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 v=0,k=0,N=0,V=0;v<R.length;v++)for(k|=(E.encode(R[v])&_)<<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,v=0,k=0,N=0;D<x.length;D++)for(v|=x[D]<<k,k+=8;k>=y;k-=y,v>>=y)R[N++]=E.decode(v&_);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)}}},Jc=Fd(Vc);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}),jn=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 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 Jd=(r,e)=>{let t=new Uint16Array(Ee),n=Nn(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 Vn(r,e,t,n){return Jd(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=jn(1),d=jn(l),p=jn(a),f=er("publicKey",ao(jn(12),t),32),m=ao(jn(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(Vn(n,_,k,i)));let x=new Uint16Array(Ee),R=[];for(let k=0;k<t;k++){let N=Vn(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=Vn(n,_,2*t,c);tr(D,Re.NTT.decode(x));let v=u.decode(E);return tr(v,D),X(b,S,x,D),h.encode([R,v])};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(Vn(n,S,k,i)));let D=s(_);for(let k=0;k<t;k++){let N=Re.NTT.encode(Vn(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 v={publicKey:f.encode([R,_]),secretKey:m.encode(x)};return X(_,S,x,R,y,E),v},encrypt:(b,y,E)=>{let[_,S]=f.decode(b),x=s(S),R=w(_,(D,v)=>Vi(x.get(D,v)),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(Vi(_.get(x,R)));return _.clean(),{encrypt:(x,R)=>w(y.map(D=>D.slice()),(D,v)=>S[D*t+v].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(mt(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?ft(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?ft(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)),v=qt(f,D),k=o.create({dkLen:32}).update(_).update(f).digest();return X(S,D,x.subarray(32),v?k:R),v?R:k},prepare:f=>{Ge(f,c.publicKey,"publicKey"),d(f,"prepare");let m=mt(f),h=n(m),g=t.prepare(m);return Object.freeze({publicKey:m,encapsulate:w=>{let b=w===void 0,y=b?ft(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),v=g.encrypt(x,R.subarray(32,64)),k=qt(w,v),N=o.create({dkLen:32}).update(S).update(w).digest();return X(x,v,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:Wc,KDF:$r,XOF:Jc,PRF:zd},Zd=r=>Xd({...Qd,...r});var Yc=Zd(Kd[768]);var qd=(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 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?mt(d):d,f=[],m=[],h=[],g=[],w=!1;try{for(let b of o.decode(p))f.push(mt(b));for(let b=0;b<s.length;b++){let y=s[b].keygen(f[b]);m.push(y.secretKey),h.push(mt(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?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 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 mt(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=ft(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=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 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(We(d[0],d[1],u[1],l[1],za(r))),e,i)}var Xc=np("MLKEM768-P256",Yc,Ic,128);function zc(r){let e=Xc.encapsulate(r);return{kemCtBase64:Yt(e.cipherText),sharedSecret:e.sharedSecret}}async function Qc(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 Zc(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,po=new Map,uo=new Map;function qc(r){return po.get(r)||null}async function el(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 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}=zc(i),l=await Qc(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 po.set(e,d),d}function tl(r){po.delete(r),uo.delete(r)}var Ji=new Map;async function ip(r,e){let t=Date.now(),n=Ji.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 Ji.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){Ji.delete(r),tl(r)}var rr=[],rl=50,nl=15e3,Gi=3600,fo=0,Jn=!1,sl=Date.now();async function ap(r){let e=Date.now();if(fo>e)return!0;if(r)try{let t=await P.get(r,"d1:write_quota_tripped");if(t&&t>Math.floor(e/1e3))return fo=t*1e3,!0}catch{}return!1}async function cp(r){let t=Math.floor(Date.now()/1e3)+Gi;if(fo=t*1e3,rr.length=0,Jn=!1,console.warn(`[LogBatcher] D1 write quota limit reached! Silencing log writes for ${Gi}s.`),r)try{await P.set(r,"d1:write_quota_tripped",t,Gi)}catch{}}async function mo(r,e){if(Jn=!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 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 ip(r.DB,l);if(u&&(c.set(l,u),"pqc_pk"in u)){let d=qc(l);d||(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 Zc(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 $a(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(Jn)return;Jn=!0;let t=new Promise(n=>setTimeout(n,nl)).then(()=>mo(r,e)).catch(n=>{Jn=!1,console.error("[LogBatcher] Deferred flush error:",n)});e&&typeof e.waitUntil=="function"&&e.waitUntil(t)}function Yn(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>=rl||o-sl>=nl?n.waitUntil(mo(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=ke(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=si(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 Jt(r,l);Yn({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=Jt(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;Yn({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&&Sr.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 Jt(r,h);Yn({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 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(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,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 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"),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 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 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 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 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 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=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 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=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 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=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),w={ciphertext:jr(new Uint8Array(g)),iv:jr(h),kek_version:i};return JSON.stringify(w)}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(`
|
|
328
328
|
SELECT
|
|
329
329
|
u.id,
|
|
330
330
|
u.username,
|
|
@@ -362,7 +362,7 @@ SQL: ${this.sql}`),t}}},zo=class{constructor(e,t){this.rawDb=e;this.dbPath=t}raw
|
|
|
362
362
|
FROM user_activity_log
|
|
363
363
|
WHERE user_id = users.id
|
|
364
364
|
) < ?
|
|
365
|
-
`).bind(n),c=await this.db.batch([s,o,i]);return{clearedProfiles:c[1].meta.changes||0,deletedUsers:c[2].meta.changes||0}}};var J=class{secrets;core;security;mfa;lifecycle;constructor(e,t){this.secrets=new yo(e,t),this.core=new wo(e,this.secrets),this.security=new bo(e),this.mfa=new Eo(e,t),this.lifecycle=new _o(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 Gr(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
|
|
365
|
+
`).bind(n),c=await this.db.batch([s,o,i]);return{clearedProfiles:c[1].meta.changes||0,deletedUsers:c[2].meta.changes||0}}};var J=class{secrets;core;security;mfa;lifecycle;constructor(e,t){this.secrets=new yo(e,t),this.core=new wo(e,this.secrets),this.security=new bo(e),this.mfa=new Eo(e,t),this.lifecycle=new _o(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 Gr(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 P.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(P.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(Tr&&t-Tr.ts<3e5)return Tr.data;let n=r.SERVERFULL_DEFAULT_PROFILE_KEY||r.DEFAULT_PROFILE_KEY;if(n){let i=await Gr(n,r,e);if(i)return ai({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 ai({data:o,ts:t}),o}async function pl(r,e,t,n){let s=caches.default,o=null;try{let i=await Gr(n,e,t);if(!i)return new Response("Invalid Profile Key",{status:404});let c=i.id,a=await Zo(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 P.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 P.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 J(e.DB,e).updateLastActiveByProfile(c,f)}catch{}await P.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 Jr(r,e=" "){return r?`
|
|
366
366
|
Tip:
|
|
367
367
|
${Array.isArray(r)?r.map(n=>`${e}${n}`).join(`
|
|
368
368
|
`):`${e}${r}`}
|
|
@@ -396,7 +396,7 @@ ${u}`)}return`
|
|
|
396
396
|
`)+`
|
|
397
397
|
`}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`
|
|
398
398
|
[${e}] Startup Error: ${a}
|
|
399
|
-
`}var Ro=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=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 Gr(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 xo from"node:fs";import gp from"node:tls";import{Buffer as Ao}from"node:buffer";import Xn 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{Xn.accessSync(r,Xn.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{Xn.accessSync(e,Xn.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=Xn.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 zn(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=zn(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:",` ${zn(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=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=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 Gr(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 Dp from"node:http";import vp from"node:https";import ru from"node:fs";import Zi from"node:fs";import vo 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||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=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
|
|
399
|
+
`}var Ro=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=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 Gr(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 xo from"node:fs";import gp from"node:tls";import{Buffer as Ao}from"node:buffer";import Xn 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{Xn.accessSync(r,Xn.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{Xn.accessSync(e,Xn.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=Xn.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 zn(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=zn(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:",` ${zn(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=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=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 Gr(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 Dp from"node:http";import Pp from"node:https";import ru from"node:fs";import Zi from"node:fs";import Po 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||Po.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=Po.normalize(o).replace(/^(\.\.[\/\\])+/,""),c=Po.join(t,i);if(Zi.existsSync(c)&&Zi.statSync(c).isFile()){let a=Po.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
|
|
400
400
|
sudo curl -L 'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64' -o /usr/local/bin/cloudflared
|
|
401
401
|
sudo chmod +x /usr/local/bin/cloudflared
|
|
402
402
|
sudo tee /etc/systemd/system/cloudflared-dns.service > /dev/null <<EOF
|
|
@@ -416,8 +416,8 @@ sudo systemctl daemon-reload
|
|
|
416
416
|
sudo systemctl enable --now cloudflared-dns
|
|
417
417
|
echo "DNS Worker DoH Proxy installed successfully."
|
|
418
418
|
echo "Please change your system DNS to 127.0.0.1"
|
|
419
|
-
`}Qn();async function yl(r,e){let t=new URL(r.url),n=new J(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();He();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 Zn(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 qn(r,e,t){return(await Zn(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
|
|
420
|
-
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 _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=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 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=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 w={kty:"RSA",n:ht(h),e:ht(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=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 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 J(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 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(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 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: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 G=await et(o,a,e);return G<=0?new Response("Invalid Passkey signature",{status:400}):new Response(`Invalid Passkey signature. ${G} attempt${G>1?"s":""} remaining.`,{status:400})}}else if((x||S||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(),G=await Ye(W);await n.updateRecoveryKeys(l,[{hash:G}]),Ae=W,V=!0,ue=1}else if(x&&m){let H=await Zn(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,!!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=ct(A,e,!!b),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,!!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();He();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=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,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}),{headers:b})}pe();Fe();Qn();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=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();Qn();async function Tp(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 Al(r,e){let t=new URL(r.url),n=new J(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 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 $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 Dl(r,e){let t=new URL(r.url),n=t.pathname,s=new J(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 Zn(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 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 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||!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 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 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 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(!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 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?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 Jt(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 kl(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 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(`
|
|
419
|
+
`}Qn();async function yl(r,e){let t=new URL(r.url),n=new J(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();He();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 Zn(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 qn(r,e,t){return(await Zn(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 Ye(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 Ye(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 J(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 P.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}=Rr(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 Ne(e.JWT_SECRET)}catch{return new Response("jwt_secret_invalid",{status:400})}let y=await at(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),v=j(6),k=x==="admin"?7:1;await D.create({id:v,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 Ye(N);await t.updateRecoveryKeys(E,[{hash:V}]);let{session:z,refreshToken:ue}=await vr(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=ct(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(v){console.error("Failed to clean up incomplete user registration:",v)}return new Response(D.message,{status:400})}}pe();He();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)
|
|
420
|
+
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 _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=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 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=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 w={kty:"RSA",n:ht(h),e:ht(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=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 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 J(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 P.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 P.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 v=Number(e.PREAUTH_TTL_SECONDS)||300;return await P.set(o,`preauth_state:${m}`,{nonce:R,failedAttempts:0,passkeyChallenge:x,rpId:t.hostname},v),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 P.isRateLimited(o,`login_fail:${i}`,10,900))return new Response("Too many login attempts",{status:429});let a=Ps(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 P.get(o,`preauth_state:${a}`);if(!u)return await Pn(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,v=S&&!!w;if(!(!!p.totp_skip_password||v)){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 P.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 P.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(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 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: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 G=await et(o,a,e);return G<=0?new Response("Invalid Passkey signature",{status:400}):new Response(`Invalid Passkey signature. ${G} attempt${G>1?"s":""} remaining.`,{status:400})}}else if((x||S||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(),G=await Ye(W);await n.updateRecoveryKeys(l,[{hash:G}]),Ae=W,V=!0,ue=1}else if(x&&m){let H=await Zn(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 P.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 P.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 Pn(e,a),await P.delete(o,`preauth_state:${a}`),await P.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 vr(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=ct(A,e,!!b),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,!!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();He();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 P.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(),vn)),{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?Pe(i):null,_=E?await ee(E.sid,d.id):null;await o.record(d.id,"logout",n,s,{reason:f||"unknown"},_)}return await P.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,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}),{headers:b})}pe();Fe();Qn();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=Le(r.headers.get("Cookie"));if(o){let c=Pe(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();Qn();async function Tp(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 Al(r,e){let t=new URL(r.url),n=new J(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 Pr(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 P.set(o,g,{nonce:h,isLegacy:m},300),new Response(JSON.stringify({nonce:h,legacy:m}),{headers:{"Content-Type":"application/json"}})}catch{return new Response("Unauthorized",{status:401})}}if(t.pathname==="/api/auth/unlock-session"&&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 Pr(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 P.get(o,b);if(!y?.nonce)return new Response("Challenge expired, please start over",{status:400});let E=y.nonce,_=!!y.isLegacy;if(await P.delete(o,b),m!==E)return new Response("Invalid nonce",{status:400});let S=`unlock_fail:${g.id}`,R=(await P.get(o,S))?.count||0,D=await ee(g.id,p.userId),v=!1;if(_)v=await Tp(f,w.pin_hash),v&&await n.updatePinHash(p.userId,f);else{let N=await va(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);v=V===0}}if(!v){let N=R+1;return N>=3?(await h.deleteSession(g.id),await P.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 P.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 P.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 Pr(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 Dl(r,e){let t=new URL(r.url),n=t.pathname,s=new J(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 P.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 P.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 P.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 P.get(i,m);if(!h)return new Response("Recovery session expired or invalid",{status:400});if(h.failedAttempts>=3)return await P.delete(i,m),new Response("Too many failed attempts. Please start over.",{status:429});let g=await s.getById(h.userId);if(!g)return await P.delete(i,m),new Response("User not found",{status:404});if(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 P.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 P.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 P.set(i,m,h,300),new Response("Invalid recovery key",{status:400});await s.consumeRecoveryKey(g.id,E,y),await o.record(g.id,"recovery_key_used",c,a,{flow:"forgot_password",remaining:y.length-1})}else if(d&&g.totp_secret){let y=await Zn(g.totp_secret,d,p);if(!y.valid)return h.failedAttempts++,await P.set(i,m,h,300),new Response("Invalid TOTP code",{status:400});if(y.timeStep!==void 0){let E=`totp_step:${g.id}:${y.timeStep}`;if(await P.get(i,E))return h.failedAttempts++,await P.set(i,m,h,300),new Response("TOTP code already used, please wait for next code",{status:400});await P.set(i,E,!0,180)}await o.record(g.id,"totp_verify_success",c,a,{flow:"forgot_password"})}else return new Response("No valid MFA credential provided",{status:400});await P.delete(i,m);let w=j(32),b={userId:g.id,username:g.username};return await P.set(i,`forgot_pw_reset:${w}`,b,300),new Response(JSON.stringify({success:!0,resetToken:w}),{headers:{"Content-Type":"application/json"}})}if(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 P.get(i,d);if(!p)return new Response("Reset token expired or invalid",{status:400});await P.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 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 vl(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 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 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 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 v=D?`tcp://${w}`:w;if(!lt(v))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?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 Jt(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 kl(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 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(`
|
|
421
421
|
SELECT lb.list_id, lb.bloom_filter_chunk
|
|
422
422
|
FROM list_blooms lb
|
|
423
423
|
JOIN lists l ON lb.list_id = l.id
|
|
@@ -452,7 +452,7 @@ echo "Please change your system DNS to 127.0.0.1"
|
|
|
452
452
|
WHERE l.profile_id = ? AND l.timestamp >= ? AND l.timestamp <= ?
|
|
453
453
|
ORDER BY l.timestamp DESC, l.id DESC
|
|
454
454
|
LIMIT ?;
|
|
455
|
-
`).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 Ie(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),
|
|
455
|
+
`).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 Ie(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),v=D.log_retention_days!==void 0?Math.min(Number(D.log_retention_days),R):R;if(v===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-v*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 P.get(_,S);if(x)return new Response(JSON.stringify(x),{headers:{"Content-Type":"application/json","X-Cache":"HIT","Cache-Control":"private, no-cache"}});let 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"),v=D?parseInt(D,10):void 0;R=await i.getDestinations(c,f,m,p,v!==void 0&&!isNaN(v)?v:void 0)}else if(g==="isps"){let D=a.get("country_code")||void 0,v=a.get("limit"),k=v?parseInt(v,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 P.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 P.get(w,b);if(y)return new Response(JSON.stringify(y),{headers:{"Content-Type":"application/json","X-Cache":"HIT","Cache-Control":"private, no-cache"}});let E=await i.getAnalytics(c,f,m,h,p);return await P.set(w,b,E,60),new Response(JSON.stringify(E),{headers:{"Content-Type":"application/json","X-Cache":"MISS","Cache-Control":"private, no-cache"}})}return new Response("Not Found",{status:404})}async function 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(`
|
|
456
456
|
SELECT upwk.passkey_id
|
|
457
457
|
FROM user_passkey_wrapped_keys upwk
|
|
458
458
|
JOIN passkeys pk ON upwk.passkey_id = pk.id
|
|
@@ -463,7 +463,7 @@ echo "Please change your system DNS to 127.0.0.1"
|
|
|
463
463
|
JOIN passkeys pk ON upwk.passkey_id = pk.id
|
|
464
464
|
WHERE pk.user_id = ?
|
|
465
465
|
LIMIT 1
|
|
466
|
-
`).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();async function Fl(r,e,t,n,s){let o=new J(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 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"?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(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 qn(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 Hl(r,e,t,n,s){let o=new J(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 $l(r,e,t,n,s){let o=new J(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 qn(p,f,m))return new Response("Invalid TOTP code",{status:400});let g=Po(),w=await Promise.all(g.map(async b=>({hash:await Ye(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 qn(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 Kl(r,e,t,n,s){let o=new J(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 Wl(r,e,t,n,s){let o=new J(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:ht(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(!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 jl(r,e,t,n,s){let o=new J(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 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 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(b=>b.id!==p),{invalidateSession:h}=await Promise.resolve().then(()=>(pe(),Pn)),{invalidateAuthUserCache:g}=await Promise.resolve().then(()=>(Qn(),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(()=>(Fe(),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=Le(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":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 Jl(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(`
|
|
466
|
+
`).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?vl(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();async function Fl(r,e,t,n,s){let o=new J(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 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"?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(),vn)),l=r.headers.get("Cookie")||"",u=Le(l),d=u&&Pe(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 P.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 P.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 qn(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 Hl(r,e,t,n,s){let o=new J(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 $l(r,e,t,n,s){let o=new J(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 qn(p,f,m))return new Response("Invalid TOTP code",{status:400});let g=vo(),w=await Promise.all(g.map(async b=>({hash:await Ye(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 qn(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 Kl(r,e,t,n,s){let o=new J(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 Wl(r,e,t,n,s){let o=new J(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 P.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 P.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 P.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 P.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:ht(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 P.get(p,`webauthn_reg_challenge:${t.id}`);if(!f)return new Response("Registration session expired, please try again",{status:400});await P.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(!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 v=!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&&(v=!0)}catch{R.totp_recovery_keys.length>0&&(v=!0)}else R.totp_recovery_keys_encrypted&&(v=!0);if(!v){let k=vo(),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 jl(r,e,t,n,s){let o=new J(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 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 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&&Pe(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&&Pe(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(),vn)),{invalidateAuthUserCache:g}=await Promise.resolve().then(()=>(Qn(),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(()=>(Fe(),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(),vn));await m(e,f);let h=Le(r.headers.get("Cookie")||""),g=h&&Pe(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":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 Jl(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(`
|
|
467
467
|
SELECT upwk.passkey_id
|
|
468
468
|
FROM user_passkey_wrapped_keys upwk
|
|
469
469
|
JOIN passkeys pk ON upwk.passkey_id = pk.id
|
|
@@ -474,9 +474,9 @@ echo "Please change your system DNS to 127.0.0.1"
|
|
|
474
474
|
JOIN passkeys pk ON upwk.passkey_id = pk.id
|
|
475
475
|
WHERE pk.user_id = ?
|
|
476
476
|
LIMIT 1
|
|
477
|
-
`).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"?Gl(r,e,t,n,s):o==="e2ee"?Jl(r,e,t,n,s):new Response("Not Found",{status:404})}pe();Se();async function Xl(r,e,t,n,s){let o=new J(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 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(!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/regions"){let s={};for(let[o,i]of Object.entries(e))if(o.startsWith("IP_REGION_")&&typeof i=="string")try{let c=o.replace("IP_REGION_",""),a=i.trim();a=a.replace(/^"""|"""$/g,"").replace(/^"|"$/g,"").replace(/^'|'$/g,"").trim(),s[c]=JSON.parse(a)}catch{}return Object.keys(s).length===0&&(s.CN=as),new Response(JSON.stringify(s),{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=os;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=is;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 ts=0;async function Zl(r,e,t){try{let n=typeof caches<"u"?caches.default:null,s=Math.floor(Date.now()/1e3),o=!0;ts&&s-ts<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&&(ts=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&&(ts=l,o=!1)}}catch(a){console.warn("[Cron] Failed to read persistent cleanup timestamp:",a)}if(o){ts=s;try{let a=new J(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 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}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=Go(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")(!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 w=!Oe(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/regions","/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)?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/regions"||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=!hr(e)||!e.DB:s==="File"?w=!n||!e.DB:w=n||!e.DB;let b=!Oe(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",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=Go(e)),await Zl(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 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=No(e);if(n&&tt(n)&&!Ap(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=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 Oo.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 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=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()})}},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=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()})}};He();import $p from"node:path";import{parseArgs as Kp}from"node:util";He();import Pp from"node:net";import Cp from"node:dgram";function Mo(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([Mo(r.httpPort,r.host),n?Mo(r.httpsPort,r.host):Promise.resolve("disabled"),r.disableUdp?Promise.resolve("disabled"):nu(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,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=Je({title:`
|
|
478
|
-
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: ${Be()})`,
|
|
479
|
-
Database & Storage:`,items:
|
|
477
|
+
`).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"?Gl(r,e,t,n,s):o==="e2ee"?Jl(r,e,t,n,s):new Response("Not Found",{status:404})}pe();Se();async function Xl(r,e,t,n,s){let o=new J(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 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 P.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/regions"){let s={};for(let[o,i]of Object.entries(e))if(o.startsWith("IP_REGION_")&&typeof i=="string")try{let c=o.replace("IP_REGION_",""),a=i.trim();a=a.replace(/^"""|"""$/g,"").replace(/^"|"$/g,"").replace(/^'|'$/g,"").trim(),s[c]=JSON.parse(a)}catch{}return Object.keys(s).length===0&&(s.CN=as),new Response(JSON.stringify(s),{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=os;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=is;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 ts=0;async function Zl(r,e,t){try{let n=typeof caches<"u"?caches.default:null,s=Math.floor(Date.now()/1e3),o=!0;ts&&s-ts<3600&&(o=!1);let i="cron:last_cleanup_timestamp",c=new de(e.DB);if(o){let a=await P.get(n,i);a&&s-a<3600&&(ts=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&&(ts=l,o=!1)}}catch(a){console.warn("[Cron] Failed to read persistent cleanup timestamp:",a)}if(o){ts=s;try{let a=new J(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 P.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 P.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 P.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 P.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}He();ge();var Oo={async fetch(r,e,t){P.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=Go(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")(!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 w=!Oe(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/regions","/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/")?Pl(r,e):d.pathname==="/api/clientinfo"||d.pathname==="/api/regions"||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=!hr(e)||!e.DB:s==="File"?w=!n||!e.DB:w=n||!e.DB;let b=!Oe(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",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&&P.setOrigin(`https://${e.SUBSTITUTE_DOMAIN}`),cn(e,!1)==="Turso"&&hr(e)&&(e.DB=Go(e)),await Zl(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 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=No(e);if(n&&tt(n)&&!Ap(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=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 Oo.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 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=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()})}},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=ru.readFileSync(o),l=ru.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 $p from"node:path";import{parseArgs as Kp}from"node:util";He();import vp from"node:net";import Cp from"node:dgram";function Mo(r,e,t=300){return new Promise(n=>{let s=new vp.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([Mo(r.httpPort,r.host),n?Mo(r.httpsPort,r.host):Promise.resolve("disabled"),r.disableUdp?Promise.resolve("disabled"):nu(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,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=Je({title:`
|
|
478
|
+
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: ${Be()})`,v=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:Ze()}],k=Je({title:`
|
|
479
|
+
Database & Storage:`,items:v}),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=Je({title:`
|
|
480
480
|
Environment & Security:`,items:[{label:"Node.js Runtime",value:`v${process.versions.node} (${process.platform} ${process.arch})`},{label:"Config Directory",value:gr()},{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=zn(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?Jr(se):"",T=[S,x,k,K,L].filter(Boolean).join(`
|
|
481
481
|
`);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 pr from"node:fs";import Ip from"node:path";import{execSync as Xe}from"node:child_process";var gt="dns-worker",Up=`${gt}.service`,tn=`/etc/systemd/system/${Up}`;function ca(r){let{execCmd:e,workDir:t,user:n}=r;return`[Unit]
|
|
482
482
|
Description=DNS Worker Serverfull Service (UDP DNS, DoT & Web Dashboard)
|