@mercuryworkshop/wisp-js
Advanced tools
Comparing version 0.2.1 to 0.2.2
@@ -1,1 +0,1 @@ | ||
var wisp_full;(()=>{"use strict";var t={d:(e,s)=>{for(var i in s)t.o(s,i)&&!t.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:s[i]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};t.r(e),t.d(e,{client:()=>i,packet:()=>s,server:()=>n});var s={};t.r(s),t.d(s,{ClosePayload:()=>b,ConnectPayload:()=>f,ContinuePayload:()=>m,DataPayload:()=>y,WispBuffer:()=>d,WispPacket:()=>w,close_reasons:()=>z,packet_classes:()=>k,packet_types:()=>g,stream_types:()=>v});var i={};t.r(i),t.d(i,{ClientConnection:()=>C,WispWebSocket:()=>P,_wisp_connections:()=>E});var n={};t.r(n),t.d(n,{ServerConnection:()=>X,ServerStream:()=>Q,options:()=>I,routeRequest:()=>tt});const a=globalThis.WebSocket,o=globalThis.crypto,r=null,c=null,h=null,l=new TextEncoder,u=l.encode.bind(l),_=new TextDecoder,p=_.decode.bind(_);class d{constructor(t){if(t instanceof Uint8Array)this.from_array(t);else if("number"==typeof t)this.from_array(new Uint8Array(t));else{if("string"!=typeof t)throw console.trace(),"invalid data type passed to wisp buffer constructor";this.from_array(u(t))}}from_array(t){this.size=t.length,this.bytes=t,this.view=new DataView(t.buffer)}concat(t){let e=new d(this.size+t.size);return e.bytes.set(this.bytes,0),e.bytes.set(t.bytes,this.size),e}slice(t,e){let s=this.bytes.slice(t,e);return new d(s)}}class w{static min_size=5;constructor({type:t,stream_id:e,payload:s,payload_bytes:i}){this.type=t,this.stream_id=e,this.payload_bytes=i,this.payload=s}static parse(t){return new w({type:t.view.getUint8(0),stream_id:t.view.getUint32(1,!0),payload_bytes:t.slice(5)})}static parse_all(t){if(t.size<w.min_size)throw"packet too small";let e=w.parse(t),s=k[e.type];if(void 0===s)throw"invalid packet type";if(e.payload_bytes.size<s.size)throw"payload too small";return e.payload=s.parse(e.payload_bytes),e}serialize(){let t=new d(5);return t.view.setUint8(0,this.type),t.view.setUint32(1,this.stream_id,!0),t=t.concat(this.payload.serialize()),t}}class f{static min_size=3;static type=1;static name="CONNECT";constructor({stream_type:t,port:e,hostname:s}){this.stream_type=t,this.port=e,this.hostname=s}static parse(t){return new f({stream_type:t.view.getUint8(0),port:t.view.getUint16(1,!0),hostname:p(t.slice(3).bytes)})}serialize(){let t=new d(3);return t.view.setUint8(0,this.stream_type),t.view.setUint16(1,this.port,!0),t=t.concat(new d(this.hostname)),t}}class y{static min_size=0;static type=2;static name="DATA";constructor({data:t}){this.data=t}static parse(t){return new y({data:t})}serialize(){return this.data}}class m{static type=3;static name="CONTINUE";constructor({buffer_remaining:t}){this.buffer_remaining=t}static parse(t){return new m({buffer_remaining:t.view.getUint32(0,!0)})}serialize(){let t=new d(4);return t.view.setUint32(0,this.buffer_remaining,!0),t}}class b{static min_size=1;static type=4;static name="CLOSE";constructor({reason:t}){this.reason=t}static parse(t){return new b({reason:t.view.getUint8(0)})}serialize(){let t=new d(1);return t.view.setUint8(0,this.buffer_remaining),t}}const k=[void 0,f,y,m,b],g={CONNECT:1,DATA:2,CONTINUE:3,CLOSE:4},v={TCP:1,UDP:2},z={Unknown:1,Voluntary:2,NetworkError:3,InvalidInfo:65,UnreachableHost:66,NoResponse:67,ConnRefused:68,TransferTimeout:71,HostBlocked:72,ConnThrottled:73,ClientError:129};class T{constructor(t,e,s,i,n,a,o){this.hostname=t,this.port=e,this.ws=s,this.buffer_size=i,this.stream_id=n,this.connection=a,this.stream_type=o,this.send_buffer=[],this.open=!0,this.onopen=()=>{},this.onclose=()=>{},this.onmessage=()=>{}}send(t){if(this.buffer_size>0||!this.open||this.stream_type===v.UDP){let e=new w({type:g.DATA,stream_id:this.stream_id,payload:new y({data:new d(t)})});this.ws.send(e.serialize().bytes),this.buffer_size--}else this.send_buffer.push(t)}continue_received(t){for(this.buffer_size=t;this.buffer_size>0&&this.send_buffer.length>0;)this.send(this.send_buffer.shift())}close(t=1){if(!this.open)return;let e=new w({type:g.CLOSE,stream_id,payload:new b({reason:t})});this.ws.send(e.serialize().bytes),this.open=!1,delete this.connection.active_streams[this.stream_id]}}class C{constructor(t){if(!t.endsWith("/"))throw"wisp endpoints must end with a trailing forward slash";this.wisp_url=t,this.max_buffer_size=null,this.active_streams={},this.connected=!1,this.connecting=!1,this.next_stream_id=1,this.onopen=()=>{},this.onclose=()=>{},this.onerror=()=>{},this.onmessage=()=>{},this.connect_ws()}connect_ws(){this.ws=new a(this.wisp_url),this.ws.binaryType="arraybuffer",this.connecting=!0,this.ws.onerror=()=>{this.on_ws_close(),this.onerror()},this.ws.onclose=()=>{this.on_ws_close(),this.onclose()},this.ws.onmessage=t=>{this.on_ws_msg(t),this.connecting&&(this.connected=!0,this.connecting=!1,this.onopen())}}close_stream(t,e){t.onclose(e),delete this.active_streams[t.stream_id]}on_ws_close(){this.connected=!1,this.connecting=!1;for(let t of Object.keys(this.active_streams))this.close_stream(this.active_streams[t],3)}create_stream(t,e,s="tcp"){let i="udp"===s?2:1,n=this.next_stream_id++,a=new T(t,e,this.ws,this.max_buffer_size,n,this,i);this.active_streams[n]=a,a.open=this.connected;let o=new w({type:g.CONNECT,stream_id:n,payload:new f({stream_type:i,port:e,hostname:t})});return this.ws.send(o.serialize().bytes),a}on_ws_msg(t){let e=new d(new Uint8Array(t.data));if(e.size<w.min_size)return void console.warn("wisp client warning: received a packet which is too short");let s=w.parse_all(e),i=this.active_streams[s.stream_id];void 0!==i||0===s.stream_id&&s.type===g.CONTINUE?s.type===g.DATA?i.onmessage(s.payload_bytes.bytes):s.type===g.CONTINUE&&0==s.stream_id?this.max_buffer_size=s.payload.buffer_remaining:s.type===g.CONTINUE?i.continue_received(s.payload.buffer_size):s.type===g.CLOSE?this.close_stream(i,s.payload.reason):console.warn(`wisp client warning: receive an invalid packet of type ${s.type}`):console.warn(`wisp client warning: received a ${k[s.type].name} packet for a stream which doesn't exist`)}}const U=globalThis.CloseEvent||Event,E={};class P extends EventTarget{constructor(t,e){super(),this.url=t,this.protocols=e,this.binaryType="blob",this.stream=null,this.connection=null,this.onopen=()=>{},this.onerror=()=>{},this.onmessage=()=>{},this.onclose=()=>{},this.CONNECTING=0,this.OPEN=1,this.CLOSING=2,this.CLOSED=3,this._ready_state=this.CONNECTING;let s=this.url.split("/"),i=s.pop().split(":");this.host=i[0],this.port=parseInt(i[1]),this.real_url=s.join("/")+"/",this.init_connection()}on_conn_close(){this._ready_state=this.CLOSED,E[this.real_url]&&(this.onerror(new Event("error")),this.dispatchEvent(new Event("error"))),delete E[this.real_url]}init_connection(){if(this.connection=E[this.real_url],this.connection)if(this.connection.connected)this.connection=E[this.real_url],this.init_stream();else{let t=this.connection.onopen;this.connection.onopen=()=>{t(),this.init_stream()}}else this.connection=new C(this.real_url),this.connection.onopen=()=>{this.init_stream()},this.connection.onclose=()=>{this.on_conn_close()},this.connection.onerror=()=>{this.on_conn_close()},E[this.real_url]=this.connection}init_stream(){this._ready_state=this.OPEN,this.stream=this.connection.create_stream(this.host,this.port),this.stream.onmessage=t=>{let e;if("blob"==this.binaryType)e=new Blob(t);else{if("arraybuffer"!=this.binaryType)throw"invalid binaryType string";e=t.buffer}let s=new MessageEvent("message",{data:e});this.onmessage(s),this.dispatchEvent(s)},this.stream.onclose=t=>{this._ready_state=this.CLOSED;let e=new U("close",{code:t});this.onclose(e),this.dispatchEvent(e)};let t=new Event("open");this.onopen(t),this.dispatchEvent(t)}send(t){let e;if(t instanceof Uint8Array)e=t;else if("string"==typeof t)e=(new TextEncoder).encode(t);else{if(t instanceof Blob)return void t.arrayBuffer().then((t=>{this.send(t)}));if(t instanceof ArrayBuffer)e=new Uint8Array(t);else{if(!ArrayBuffer.isView(t))throw"invalid data type to be sent";e=new Uint8Array(t.buffer)}}if(!this.stream)throw"websocket is not ready";this.stream.send(e)}close(){this.stream.close(2)}get bufferedAmount(){let t=0;for(let e of this.stream.send_buffer)t+=e.length;return t}get extensions(){return""}get protocol(){return"binary"}get readyState(){return this._ready_state}}const $=1,N=2,O=3;let S=$;function A(){let[t,e]=(new Date).toJSON().split("T");return t=t.replaceAll("-","/"),e=e.split(".")[0],`[${t} - ${e}]`}function q(...t){S>$||console.info(A()+" info:",...t)}function D(...t){S>N||console.warn(A()+" warn:",...t)}function x(...t){S>O||console.error(A()+" error:",...t)}const I={hostname_blacklist:null,hostname_whitelist:null,port_blacklist:null,port_whitelist:null,allow_direct_ip:!0,allow_private_ips:!1,allow_loopback_ips:!1,client_ip_blacklist:null,client_ip_whitelist:null,stream_limit_per_host:-1,stream_limit_total:-1,allow_udp_streams:!0,allow_tcp_streams:!0};class B extends Error{}function j(t,e){return t===e||t[0]<=e&&t[1]>=e}function H(t,e){let s=!1;for(let i of t)if(e(i)){s=!0;break}return!s}function L(t,e){for(let s of t)if(e(s))return!0;return!1}function W(t,e,s,i){if(!I.allow_tcp_streams&&e===v.TCP)return z.HostBlocked;if(!I.allow_udp_streams&&e===v.UDP)return z.HostBlocked;if(I.hostname_whitelist){if(H(I.hostname_whitelist,(t=>t.test(s))))return z.HostBlocked}else if(I.hostname_blacklist&&L(I.hostname_blacklist,(t=>t.test(s))))return z.HostBlocked;if(I.port_whitelist){if(H(I.port_whitelist,(t=>j(t,i))))return z.HostBlocked}else if(I.port_blacklist&&L(I.port_blacklist,(t=>j(t,i))))return z.HostBlocked;if(!t)return 0;if(-1!==I.stream_limit_total&&Object.keys(t.streams).length>=I.stream_limit_total)return z.ConnThrottled;if(-1!==I.stream_limit_per_host){let e=0;for(let i of t.streams)i.socket.hostname===s&&e++;if(e>=I.stream_limit_per_host)return z.ConnThrottled}return 0}class M{send_buffer_size=33554432;constructor(t){this.ws=t,this.connected=!1,this.data_queue=new R(1)}async connect(){await new Promise(((t,e)=>{this.ws.onopen=()=>{this.connected=!0,t()},this.ws.onmessage=t=>{this.data_queue.put(t.data)},this.ws.onclose=()=>{this.connected?this.data_queue.close():e()},this.ws.readyState===this.ws.OPEN&&(this.connected=!0,t())}))}async recv(){return await this.data_queue.get()}async send(t){if(this.ws.send(t),!(this.ws.bufferedAmount<=this.send_buffer_size))for(;!(this.ws.bufferedAmount<=this.send_buffer_size/2);)await new Promise((t=>{setTimeout(t,10)}))}close(t,e){this.ws.close(t,e),this.data_queue.close()}get buffered_amount(){return this.ws.bufferedAmount}}class R{constructor(t){this.max_size=t,this.queue=[],this.put_callbacks=[],this.get_callbacks=[]}put_now(t){this.queue.push(t),this.get_callbacks.shift()?.()}async put(t){this.size<=this.max_size||await new Promise((t=>{this.put_callbacks.push(t)})),this.put_now(t)}get_now(){return this.put_callbacks.shift()?.(),this.queue.shift()}async get(){return this.size>0||await new Promise((t=>{this.get_callbacks.push(t)})),this.get_now()}close(){let t;for(this.queue=[];t=this.get_callbacks.shift();)t();for(;t=this.put_callbacks.shift();)t()}get size(){return this.queue.length}}const V="undefined"!=typeof process;function G(){if(!V)throw"not running on node.js"}async function J(t){let e=r.isIP(t);return 4===e||6===e?t:(await c.lookup(t)).address}class F{constructor(t,e){G(),this.hostname=t,this.port=e,this.recv_buffer_size=128,this.socket=null,this.paused=!1,this.connected=!1,this.data_queue=new R(this.recv_buffer_size)}async connect(){let t=await J(this.hostname);await new Promise(((e,s)=>{this.socket=new r.Socket,this.socket.setNoDelay(!0),this.socket.on("connect",(()=>{this.connected=!0,e()})),this.socket.on("data",(t=>{this.data_queue.put(t)})),this.socket.on("close",(t=>{t&&!this.connected?s():this.data_queue.close(),this.socket=null})),this.socket.on("error",(t=>{D(`tcp stream to ${this.hostname} ended with error - ${t}`)})),this.socket.on("end",(()=>{this.socket&&(this.socket.destroy(),this.socket=null)})),this.socket.connect({host:t,port:this.port})}))}async recv(){return await this.data_queue.get()}async send(t){await new Promise((e=>{this.socket.write(t,e)}))}async close(){this.socket&&(this.socket.end(),this.socket=null)}pause(){this.data_queue.size>=this.data_queue.max_size&&(this.socket.pause(),this.paused=!0)}resume(){this.socket&&this.paused&&(this.socket.resume(),this.paused=!1)}}class K{constructor(t,e){G(),this.hostname=t,this.port=e,this.connected=!1,this.recv_buffer_size=128,this.data_queue=new R(this.recv_buffer_size)}async connect(){let t=await J(this.hostname),e=r.isIP(t);await new Promise(((s,i)=>{this.socket=null.createSocket(6===e?"udp6":"udp4"),this.socket.on("connect",(()=>{s()})),this.socket.on("message",(t=>{this.data_queue.put(t)})),this.socket.on("error",(()=>{this.connected||i(),this.data_queue.close(),this.socket=null})),this.socket.connect(this.port,t)}))}async recv(){return await this.data_queue.get()}async send(t){this.socket.send(t)}async close(){this.socket&&(this.socket.close(),this.socket=null)}pause(){}resume(){}}class Q{static buffer_size=128;constructor(t,e,s){this.stream_id=t,this.conn=e,this.socket=s,this.send_buffer=new R(Q.buffer_size),this.packets_sent=0}async setup(){await this.socket.connect(),this.tcp_to_ws().catch((t=>{x(`(${this.conn.conn_id}) a tcp/udp to ws task encountered an error - ${t}`),this.close()})),this.ws_to_tcp().catch((t=>{x(`(${this.conn.conn_id}) a ws to tcp/udp task encountered an error - ${t}`),this.close()}))}async tcp_to_ws(){for(;;){let t=await this.socket.recv();if(null==t)break;this.socket.pause();let e=new w({type:y.type,stream_id:this.stream_id,payload:new y({data:new d(new Uint8Array(t))})});await this.conn.ws.send(e.serialize().bytes),this.socket.resume()}await this.conn.close_stream(this.stream_id,z.Voluntary)}async ws_to_tcp(){for(;;){let t=await this.send_buffer.get();if(null==t)break;if(await this.socket.send(t),this.packets_sent++,this.packets_sent%(Q.buffer_size/2)!=0)continue;let e=new w({type:m.type,stream_id:this.stream_id,payload:new m({buffer_remaining:Q.buffer_size-this.send_buffer.size})});this.conn.ws.send(e.serialize().bytes)}await this.close()}async close(t=null){if(this.send_buffer.close(),this.socket.close(),null==t)return;let e=new w({type:b.type,stream_id:this.stream_id,payload:new b({reason:t})});await this.conn.ws.send(e.serialize().bytes)}async put_data(t){await this.send_buffer.put(t)}}class X{constructor(t,e,{TCPSocket:s,UDPSocket:i,ping_interval:n}={}){this.ws=new M(t),this.path=e,this.TCPSocket=s||F,this.UDPSocket=i||K,this.ping_interval=n||30,this.ping_task=null,this.streams={},this.conn_id=o.randomUUID().split("-")[0]}async setup(){q(`setting up new wisp connection with id ${this.conn_id}`),await this.ws.connect();let t=new w({type:m.type,stream_id:0,payload:new m({buffer_remaining:Q.buffer_size})});await this.ws.send(t.serialize().bytes),"function"==typeof this.ws.ws.ping&&(this.ping_task=setInterval((()=>{!function(...t){S>0||console.debug(A()+" debug:",...t)}(`(${this.conn_id}) sending websocket ping`),this.ws.ws.ping()}),1e3*this.ping_interval))}async create_stream(t,e,s,i){let n=W(this,e,s,i);if(n){D(`(${this.conn_id}) refusing to create a stream to ${s}:${i}`);let e=new w({type:b.type,stream_id:t,payload:new b({reason:n})});return void await this.ws.send(e.serialize().bytes)}let a=new(e===v.TCP?this.TCPSocket:this.UDPSocket)(s,i),o=new Q(t,this,a);this.streams[t]=o,o.setup().catch((e=>{D(`(${this.conn_id}) creating a stream to ${s}:${i} failed - ${e}`),this.close_stream(t,z.NetworkError)}))}async close_stream(t,e=null){let s=this.streams[t];null!=s&&(e&&q(`(${this.conn_id}) closing stream to ${s.socket.hostname} for reason ${e}`),await s.close(e),delete this.streams[t])}async route_packet(t){let e=w.parse_all(t),s=this.streams[e.stream_id];if(null!=s||e.type!=y.type)if(e.type===f.type){let t=e.payload.stream_type===v.TCP?"TCP":"UDP";q(`(${this.conn_id}) opening new ${t} stream to ${e.payload.hostname}:${e.payload.port}`),await this.create_stream(e.stream_id,e.payload.stream_type,e.payload.hostname,e.payload.port)}else e.type===y.type?s.put_data(e.payload.data.bytes):e.type==m.type?D(`(${this.conn_id}) client sent a CONTINUE packet, this should never be possible`):e.type==b.type&&await this.close_stream(e.stream_id,e.reason);else D(`(${this.conn_id}) received a DATA packet for a stream which doesn't exist`)}async run(){for(;;){let t;if(t=await this.ws.recv(),null==t)break;try{this.route_packet(new d(new Uint8Array(t)))}catch(t){D(`(${this.conn_id}) routing a packet failed - ${t}`)}}for(let t of Object.keys(this.streams))await this.close_stream(t);clearInterval(this.ping_task),q(`(${this.conn_id}) wisp connection closed`)}}class Y{constructor(t,e){let[s,i]=e.split("/").pop().split(":");if(this.hostname=s,this.port=parseInt(i),0!==W(null,v.TCP,this.hostname,this.port))throw q(`Refusing to create a wsproxy connection to ${this.hostname}:${this.port}`),new B;this.socket=new F(s,i),this.ws=new M(t)}async setup(){await this.ws.connect(),await this.socket.connect(),this.tcp_to_ws().catch((t=>{x(`a tcp to ws task (wsproxy) encountered an error - ${t}`)})),this.ws_to_tcp().catch((t=>{x(`a ws to tcp task (wsproxy) encountered an error - ${t}`)}))}async tcp_to_ws(){for(;;){let t=await this.socket.recv();if(null==t)break;this.socket.pause(),await this.ws.send(t),this.socket.resume()}await this.ws.close()}async ws_to_tcp(){for(;;){let t;if(t=await this.ws.recv(),null==t)break;await this.socket.send(t)}await this.socket.close()}}let Z=null;function tt(t,e,s,i={}){G(),t instanceof h.IncomingMessage?Z.handleUpgrade(t,e,s,(e=>{et(e,t.url,t,i)})):t instanceof a&&et(ws,"/",{})}async function et(t,e,s,i){q(`new connection on ${e} from ${s.socket.address().address}`);try{if(e.endsWith("/")){let s=new X(t,e,i);await s.setup(),await s.run()}else{let s=new Y(t,e,i);await s.setup()}}catch(e){if(t.close(),e instanceof B)return;x("Uncaught server error:\n"+e.stack)}}V&&(Z=new null({noServer:!0})),wisp_full=e})(); | ||
var wisp_full;(()=>{var t={512:function(t){!function(e){"use strict";const s="(0?\\d+|0x[a-f0-9]+)",n={fourOctet:new RegExp(`^${s}\\.${s}\\.${s}\\.${s}$`,"i"),threeOctet:new RegExp(`^${s}\\.${s}\\.${s}$`,"i"),twoOctet:new RegExp(`^${s}\\.${s}$`,"i"),longValue:new RegExp(`^${s}$`,"i")},i=new RegExp("^0[0-7]+$","i"),r=new RegExp("^0x[a-f0-9]+$","i"),o="%[0-9a-z]{1,}",a="(?:[0-9a-f]+::?)+",c={zoneIndex:new RegExp(o,"i"),native:new RegExp(`^(::)?(${a})?([0-9a-f]+)?(::)?(${o})?$`,"i"),deprecatedTransitional:new RegExp(`^(?:::)(${s}\\.${s}\\.${s}\\.${s}(${o})?)$`,"i"),transitional:new RegExp(`^((?:${a})|(?:::)(?:${a})?)${s}\\.${s}\\.${s}\\.${s}(${o})?$`,"i")};function h(t,e){if(t.indexOf("::")!==t.lastIndexOf("::"))return null;let s,n,i=0,r=-1,o=(t.match(c.zoneIndex)||[])[0];for(o&&(o=o.substring(1),t=t.replace(/%.+$/,""));(r=t.indexOf(":",r+1))>=0;)i++;if("::"===t.substr(0,2)&&i--,"::"===t.substr(-2,2)&&i--,i>e)return null;for(n=e-i,s=":";n--;)s+="0:";return":"===(t=t.replace("::",s))[0]&&(t=t.slice(1)),":"===t[t.length-1]&&(t=t.slice(0,-1)),{parts:e=function(){const e=t.split(":"),s=[];for(let t=0;t<e.length;t++)s.push(parseInt(e[t],16));return s}(),zoneId:o}}function l(t,e,s,n){if(t.length!==e.length)throw new Error("ipaddr: cannot match CIDR for objects with different lengths");let i,r=0;for(;n>0;){if(i=s-n,i<0&&(i=0),t[r]>>i!=e[r]>>i)return!1;n-=s,r+=1}return!0}function u(t){if(r.test(t))return parseInt(t,16);if("0"===t[0]&&!isNaN(parseInt(t[1],10))){if(i.test(t))return parseInt(t,8);throw new Error(`ipaddr: cannot parse ${t} as octal`)}return parseInt(t,10)}function p(t,e){for(;t.length<e;)t=`0${t}`;return t}const d={};d.IPv4=function(){function t(t){if(4!==t.length)throw new Error("ipaddr: ipv4 octet count should be 4");let e,s;for(e=0;e<t.length;e++)if(s=t[e],!(0<=s&&s<=255))throw new Error("ipaddr: ipv4 octet should fit in 8 bits");this.octets=t}return t.prototype.SpecialRanges={unspecified:[[new t([0,0,0,0]),8]],broadcast:[[new t([255,255,255,255]),32]],multicast:[[new t([224,0,0,0]),4]],linkLocal:[[new t([169,254,0,0]),16]],loopback:[[new t([127,0,0,0]),8]],carrierGradeNat:[[new t([100,64,0,0]),10]],private:[[new t([10,0,0,0]),8],[new t([172,16,0,0]),12],[new t([192,168,0,0]),16]],reserved:[[new t([192,0,0,0]),24],[new t([192,0,2,0]),24],[new t([192,88,99,0]),24],[new t([198,18,0,0]),15],[new t([198,51,100,0]),24],[new t([203,0,113,0]),24],[new t([240,0,0,0]),4]],as112:[[new t([192,175,48,0]),24],[new t([192,31,196,0]),24]],amt:[[new t([192,52,193,0]),24]]},t.prototype.kind=function(){return"ipv4"},t.prototype.match=function(t,e){let s;if(void 0===e&&(s=t,t=s[0],e=s[1]),"ipv4"!==t.kind())throw new Error("ipaddr: cannot match ipv4 address with non-ipv4 one");return l(this.octets,t.octets,8,e)},t.prototype.prefixLengthFromSubnetMask=function(){let t=0,e=!1;const s={0:8,128:7,192:6,224:5,240:4,248:3,252:2,254:1,255:0};let n,i,r;for(n=3;n>=0;n-=1){if(i=this.octets[n],!(i in s))return null;if(r=s[i],e&&0!==r)return null;8!==r&&(e=!0),t+=r}return 32-t},t.prototype.range=function(){return d.subnetMatch(this,this.SpecialRanges)},t.prototype.toByteArray=function(){return this.octets.slice(0)},t.prototype.toIPv4MappedAddress=function(){return d.IPv6.parse(`::ffff:${this.toString()}`)},t.prototype.toNormalizedString=function(){return this.toString()},t.prototype.toString=function(){return this.octets.join(".")},t}(),d.IPv4.broadcastAddressFromCIDR=function(t){try{const e=this.parseCIDR(t),s=e[0].toByteArray(),n=this.subnetMaskFromPrefixLength(e[1]).toByteArray(),i=[];let r=0;for(;r<4;)i.push(parseInt(s[r],10)|255^parseInt(n[r],10)),r++;return new this(i)}catch(t){throw new Error("ipaddr: the address does not have IPv4 CIDR format")}},d.IPv4.isIPv4=function(t){return null!==this.parser(t)},d.IPv4.isValid=function(t){try{return new this(this.parser(t)),!0}catch(t){return!1}},d.IPv4.isValidCIDR=function(t){try{return this.parseCIDR(t),!0}catch(t){return!1}},d.IPv4.isValidFourPartDecimal=function(t){return!(!d.IPv4.isValid(t)||!t.match(/^(0|[1-9]\d*)(\.(0|[1-9]\d*)){3}$/))},d.IPv4.networkAddressFromCIDR=function(t){let e,s,n,i,r;try{for(e=this.parseCIDR(t),n=e[0].toByteArray(),r=this.subnetMaskFromPrefixLength(e[1]).toByteArray(),i=[],s=0;s<4;)i.push(parseInt(n[s],10)&parseInt(r[s],10)),s++;return new this(i)}catch(t){throw new Error("ipaddr: the address does not have IPv4 CIDR format")}},d.IPv4.parse=function(t){const e=this.parser(t);if(null===e)throw new Error("ipaddr: string is not formatted like an IPv4 Address");return new this(e)},d.IPv4.parseCIDR=function(t){let e;if(e=t.match(/^(.+)\/(\d+)$/)){const t=parseInt(e[2]);if(t>=0&&t<=32){const s=[this.parse(e[1]),t];return Object.defineProperty(s,"toString",{value:function(){return this.join("/")}}),s}}throw new Error("ipaddr: string is not formatted like an IPv4 CIDR range")},d.IPv4.parser=function(t){let e,s,i;if(e=t.match(n.fourOctet))return function(){const t=e.slice(1,6),n=[];for(let e=0;e<t.length;e++)s=t[e],n.push(u(s));return n}();if(e=t.match(n.longValue)){if(i=u(e[1]),i>4294967295||i<0)throw new Error("ipaddr: address outside defined range");return function(){const t=[];let e;for(e=0;e<=24;e+=8)t.push(i>>e&255);return t}().reverse()}return(e=t.match(n.twoOctet))?function(){const t=e.slice(1,4),s=[];if(i=u(t[1]),i>16777215||i<0)throw new Error("ipaddr: address outside defined range");return s.push(u(t[0])),s.push(i>>16&255),s.push(i>>8&255),s.push(255&i),s}():(e=t.match(n.threeOctet))?function(){const t=e.slice(1,5),s=[];if(i=u(t[2]),i>65535||i<0)throw new Error("ipaddr: address outside defined range");return s.push(u(t[0])),s.push(u(t[1])),s.push(i>>8&255),s.push(255&i),s}():null},d.IPv4.subnetMaskFromPrefixLength=function(t){if((t=parseInt(t))<0||t>32)throw new Error("ipaddr: invalid IPv4 prefix length");const e=[0,0,0,0];let s=0;const n=Math.floor(t/8);for(;s<n;)e[s]=255,s++;return n<4&&(e[n]=Math.pow(2,t%8)-1<<8-t%8),new this(e)},d.IPv6=function(){function t(t,e){let s,n;if(16===t.length)for(this.parts=[],s=0;s<=14;s+=2)this.parts.push(t[s]<<8|t[s+1]);else{if(8!==t.length)throw new Error("ipaddr: ipv6 part count should be 8 or 16");this.parts=t}for(s=0;s<this.parts.length;s++)if(n=this.parts[s],!(0<=n&&n<=65535))throw new Error("ipaddr: ipv6 part should fit in 16 bits");e&&(this.zoneId=e)}return t.prototype.SpecialRanges={unspecified:[new t([0,0,0,0,0,0,0,0]),128],linkLocal:[new t([65152,0,0,0,0,0,0,0]),10],multicast:[new t([65280,0,0,0,0,0,0,0]),8],loopback:[new t([0,0,0,0,0,0,0,1]),128],uniqueLocal:[new t([64512,0,0,0,0,0,0,0]),7],ipv4Mapped:[new t([0,0,0,0,0,65535,0,0]),96],discard:[new t([256,0,0,0,0,0,0,0]),64],rfc6145:[new t([0,0,0,0,65535,0,0,0]),96],rfc6052:[new t([100,65435,0,0,0,0,0,0]),96],"6to4":[new t([8194,0,0,0,0,0,0,0]),16],teredo:[new t([8193,0,0,0,0,0,0,0]),32],benchmarking:[new t([8193,2,0,0,0,0,0,0]),48],amt:[new t([8193,3,0,0,0,0,0,0]),32],as112v6:[[new t([8193,4,274,0,0,0,0,0]),48],[new t([9760,79,32768,0,0,0,0,0]),48]],deprecated:[new t([8193,16,0,0,0,0,0,0]),28],orchid2:[new t([8193,32,0,0,0,0,0,0]),28],droneRemoteIdProtocolEntityTags:[new t([8193,48,0,0,0,0,0,0]),28],reserved:[[new t([8193,0,0,0,0,0,0,0]),23],[new t([8193,3512,0,0,0,0,0,0]),32]]},t.prototype.isIPv4MappedAddress=function(){return"ipv4Mapped"===this.range()},t.prototype.kind=function(){return"ipv6"},t.prototype.match=function(t,e){let s;if(void 0===e&&(s=t,t=s[0],e=s[1]),"ipv6"!==t.kind())throw new Error("ipaddr: cannot match ipv6 address with non-ipv6 one");return l(this.parts,t.parts,16,e)},t.prototype.prefixLengthFromSubnetMask=function(){let t=0,e=!1;const s={0:16,32768:15,49152:14,57344:13,61440:12,63488:11,64512:10,65024:9,65280:8,65408:7,65472:6,65504:5,65520:4,65528:3,65532:2,65534:1,65535:0};let n,i;for(let r=7;r>=0;r-=1){if(n=this.parts[r],!(n in s))return null;if(i=s[n],e&&0!==i)return null;16!==i&&(e=!0),t+=i}return 128-t},t.prototype.range=function(){return d.subnetMatch(this,this.SpecialRanges)},t.prototype.toByteArray=function(){let t;const e=[],s=this.parts;for(let n=0;n<s.length;n++)t=s[n],e.push(t>>8),e.push(255&t);return e},t.prototype.toFixedLengthString=function(){const t=function(){const t=[];for(let e=0;e<this.parts.length;e++)t.push(p(this.parts[e].toString(16),4));return t}.call(this).join(":");let e="";return this.zoneId&&(e=`%${this.zoneId}`),t+e},t.prototype.toIPv4Address=function(){if(!this.isIPv4MappedAddress())throw new Error("ipaddr: trying to convert a generic ipv6 address to ipv4");const t=this.parts.slice(-2),e=t[0],s=t[1];return new d.IPv4([e>>8,255&e,s>>8,255&s])},t.prototype.toNormalizedString=function(){const t=function(){const t=[];for(let e=0;e<this.parts.length;e++)t.push(this.parts[e].toString(16));return t}.call(this).join(":");let e="";return this.zoneId&&(e=`%${this.zoneId}`),t+e},t.prototype.toRFC5952String=function(){const t=/((^|:)(0(:|$)){2,})/g,e=this.toNormalizedString();let s,n=0,i=-1;for(;s=t.exec(e);)s[0].length>i&&(n=s.index,i=s[0].length);return i<0?e:`${e.substring(0,n)}::${e.substring(n+i)}`},t.prototype.toString=function(){return this.toRFC5952String()},t}(),d.IPv6.broadcastAddressFromCIDR=function(t){try{const e=this.parseCIDR(t),s=e[0].toByteArray(),n=this.subnetMaskFromPrefixLength(e[1]).toByteArray(),i=[];let r=0;for(;r<16;)i.push(parseInt(s[r],10)|255^parseInt(n[r],10)),r++;return new this(i)}catch(t){throw new Error(`ipaddr: the address does not have IPv6 CIDR format (${t})`)}},d.IPv6.isIPv6=function(t){return null!==this.parser(t)},d.IPv6.isValid=function(t){if("string"==typeof t&&-1===t.indexOf(":"))return!1;try{const e=this.parser(t);return new this(e.parts,e.zoneId),!0}catch(t){return!1}},d.IPv6.isValidCIDR=function(t){if("string"==typeof t&&-1===t.indexOf(":"))return!1;try{return this.parseCIDR(t),!0}catch(t){return!1}},d.IPv6.networkAddressFromCIDR=function(t){let e,s,n,i,r;try{for(e=this.parseCIDR(t),n=e[0].toByteArray(),r=this.subnetMaskFromPrefixLength(e[1]).toByteArray(),i=[],s=0;s<16;)i.push(parseInt(n[s],10)&parseInt(r[s],10)),s++;return new this(i)}catch(t){throw new Error(`ipaddr: the address does not have IPv6 CIDR format (${t})`)}},d.IPv6.parse=function(t){const e=this.parser(t);if(null===e.parts)throw new Error("ipaddr: string is not formatted like an IPv6 Address");return new this(e.parts,e.zoneId)},d.IPv6.parseCIDR=function(t){let e,s,n;if((s=t.match(/^(.+)\/(\d+)$/))&&(e=parseInt(s[2]),e>=0&&e<=128))return n=[this.parse(s[1]),e],Object.defineProperty(n,"toString",{value:function(){return this.join("/")}}),n;throw new Error("ipaddr: string is not formatted like an IPv6 CIDR range")},d.IPv6.parser=function(t){let e,s,n,i,r,o;if(n=t.match(c.deprecatedTransitional))return this.parser(`::ffff:${n[1]}`);if(c.native.test(t))return h(t,8);if((n=t.match(c.transitional))&&(o=n[6]||"",e=n[1],n[1].endsWith("::")||(e=e.slice(0,-1)),e=h(e+o,6),e.parts)){for(r=[parseInt(n[2]),parseInt(n[3]),parseInt(n[4]),parseInt(n[5])],s=0;s<r.length;s++)if(i=r[s],!(0<=i&&i<=255))return null;return e.parts.push(r[0]<<8|r[1]),e.parts.push(r[2]<<8|r[3]),{parts:e.parts,zoneId:e.zoneId}}return null},d.IPv6.subnetMaskFromPrefixLength=function(t){if((t=parseInt(t))<0||t>128)throw new Error("ipaddr: invalid IPv6 prefix length");const e=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];let s=0;const n=Math.floor(t/8);for(;s<n;)e[s]=255,s++;return n<16&&(e[n]=Math.pow(2,t%8)-1<<8-t%8),new this(e)},d.fromByteArray=function(t){const e=t.length;if(4===e)return new d.IPv4(t);if(16===e)return new d.IPv6(t);throw new Error("ipaddr: the binary input is neither an IPv6 nor IPv4 address")},d.isValid=function(t){return d.IPv6.isValid(t)||d.IPv4.isValid(t)},d.isValidCIDR=function(t){return d.IPv6.isValidCIDR(t)||d.IPv4.isValidCIDR(t)},d.parse=function(t){if(d.IPv6.isValid(t))return d.IPv6.parse(t);if(d.IPv4.isValid(t))return d.IPv4.parse(t);throw new Error("ipaddr: the address has neither IPv6 nor IPv4 format")},d.parseCIDR=function(t){try{return d.IPv6.parseCIDR(t)}catch(e){try{return d.IPv4.parseCIDR(t)}catch(t){throw new Error("ipaddr: the address has neither IPv6 nor IPv4 CIDR format")}}},d.process=function(t){const e=this.parse(t);return"ipv6"===e.kind()&&e.isIPv4MappedAddress()?e.toIPv4Address():e},d.subnetMatch=function(t,e,s){let n,i,r,o;for(i in null==s&&(s="unicast"),e)if(Object.prototype.hasOwnProperty.call(e,i))for(r=e[i],!r[0]||r[0]instanceof Array||(r=[r]),n=0;n<r.length;n++)if(o=r[n],t.kind()===o[0].kind()&&t.match.apply(t,o))return i;return s},t.exports?t.exports=d:e.ipaddr=d}(this)}},e={};function s(n){var i=e[n];if(void 0!==i)return i.exports;var r=e[n]={exports:{}};return t[n].call(r.exports,r,r.exports,s),r.exports}s.d=(t,e)=>{for(var n in e)s.o(e,n)&&!s.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},s.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),s.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var n={};(()=>{"use strict";s.r(n),s.d(n,{client:()=>e,packet:()=>t,server:()=>i});var t={};s.r(t),s.d(t,{ClosePayload:()=>v,ConnectPayload:()=>_,ContinuePayload:()=>m,DataPayload:()=>y,WispBuffer:()=>f,WispPacket:()=>w,close_reasons:()=>I,packet_classes:()=>g,packet_types:()=>b,stream_types:()=>k});var e={};s.r(e),s.d(e,{ClientConnection:()=>$,WispWebSocket:()=>z,_wisp_connections:()=>E});var i={};s.r(i),s.d(i,{ServerConnection:()=>tt,ServerStream:()=>Z,options:()=>U,routeRequest:()=>nt});const r=globalThis.WebSocket,o=globalThis.crypto,a=null,c=null,h=null,l=new TextEncoder,u=l.encode.bind(l),p=new TextDecoder,d=p.decode.bind(p);class f{constructor(t){if(t instanceof Uint8Array)this.from_array(t);else if("number"==typeof t)this.from_array(new Uint8Array(t));else{if("string"!=typeof t)throw console.trace(),"invalid data type passed to wisp buffer constructor";this.from_array(u(t))}}from_array(t){this.size=t.length,this.bytes=t,this.view=new DataView(t.buffer)}concat(t){let e=new f(this.size+t.size);return e.bytes.set(this.bytes,0),e.bytes.set(t.bytes,this.size),e}slice(t,e){let s=this.bytes.slice(t,e);return new f(s)}}class w{static min_size=5;constructor({type:t,stream_id:e,payload:s,payload_bytes:n}){this.type=t,this.stream_id=e,this.payload_bytes=n,this.payload=s}static parse(t){return new w({type:t.view.getUint8(0),stream_id:t.view.getUint32(1,!0),payload_bytes:t.slice(5)})}static parse_all(t){if(t.size<w.min_size)throw"packet too small";let e=w.parse(t),s=g[e.type];if(void 0===s)throw"invalid packet type";if(e.payload_bytes.size<s.size)throw"payload too small";return e.payload=s.parse(e.payload_bytes),e}serialize(){let t=new f(5);return t.view.setUint8(0,this.type),t.view.setUint32(1,this.stream_id,!0),t=t.concat(this.payload.serialize()),t}}class _{static min_size=3;static type=1;static name="CONNECT";constructor({stream_type:t,port:e,hostname:s}){this.stream_type=t,this.port=e,this.hostname=s}static parse(t){return new _({stream_type:t.view.getUint8(0),port:t.view.getUint16(1,!0),hostname:d(t.slice(3).bytes)})}serialize(){let t=new f(3);return t.view.setUint8(0,this.stream_type),t.view.setUint16(1,this.port,!0),t=t.concat(new f(this.hostname)),t}}class y{static min_size=0;static type=2;static name="DATA";constructor({data:t}){this.data=t}static parse(t){return new y({data:t})}serialize(){return this.data}}class m{static type=3;static name="CONTINUE";constructor({buffer_remaining:t}){this.buffer_remaining=t}static parse(t){return new m({buffer_remaining:t.view.getUint32(0,!0)})}serialize(){let t=new f(4);return t.view.setUint32(0,this.buffer_remaining,!0),t}}class v{static min_size=1;static type=4;static name="CLOSE";constructor({reason:t}){this.reason=t}static parse(t){return new v({reason:t.view.getUint8(0)})}serialize(){let t=new f(1);return t.view.setUint8(0,this.buffer_remaining),t}}const g=[void 0,_,y,m,v],b={CONNECT:1,DATA:2,CONTINUE:3,CLOSE:4},k={TCP:1,UDP:2},I={Unknown:1,Voluntary:2,NetworkError:3,InvalidInfo:65,UnreachableHost:66,NoResponse:67,ConnRefused:68,TransferTimeout:71,HostBlocked:72,ConnThrottled:73,ClientError:129};class P{constructor(t,e,s,n,i,r,o){this.hostname=t,this.port=e,this.ws=s,this.buffer_size=n,this.stream_id=i,this.connection=r,this.stream_type=o,this.send_buffer=[],this.open=!0,this.onopen=()=>{},this.onclose=()=>{},this.onmessage=()=>{}}send(t){if(this.buffer_size>0||!this.open||this.stream_type===k.UDP){let e=new w({type:b.DATA,stream_id:this.stream_id,payload:new y({data:new f(t)})});this.ws.send(e.serialize().bytes),this.buffer_size--}else this.send_buffer.push(t)}continue_received(t){for(this.buffer_size=t;this.buffer_size>0&&this.send_buffer.length>0;)this.send(this.send_buffer.shift())}close(t=1){if(!this.open)return;let e=new w({type:b.CLOSE,stream_id,payload:new v({reason:t})});this.ws.send(e.serialize().bytes),this.open=!1,delete this.connection.active_streams[this.stream_id]}}class ${constructor(t){if(!t.endsWith("/"))throw"wisp endpoints must end with a trailing forward slash";this.wisp_url=t,this.max_buffer_size=null,this.active_streams={},this.connected=!1,this.connecting=!1,this.next_stream_id=1,this.onopen=()=>{},this.onclose=()=>{},this.onerror=()=>{},this.onmessage=()=>{},this.connect_ws()}connect_ws(){this.ws=new r(this.wisp_url),this.ws.binaryType="arraybuffer",this.connecting=!0,this.ws.onerror=()=>{this.on_ws_close(),this.onerror()},this.ws.onclose=()=>{this.on_ws_close(),this.onclose()},this.ws.onmessage=t=>{this.on_ws_msg(t),this.connecting&&(this.connected=!0,this.connecting=!1,this.onopen())}}close_stream(t,e){t.onclose(e),delete this.active_streams[t.stream_id]}on_ws_close(){this.connected=!1,this.connecting=!1;for(let t of Object.keys(this.active_streams))this.close_stream(this.active_streams[t],3)}create_stream(t,e,s="tcp"){let n="udp"===s?2:1,i=this.next_stream_id++,r=new P(t,e,this.ws,this.max_buffer_size,i,this,n);this.active_streams[i]=r,r.open=this.connected;let o=new w({type:b.CONNECT,stream_id:i,payload:new _({stream_type:n,port:e,hostname:t})});return this.ws.send(o.serialize().bytes),r}on_ws_msg(t){let e=new f(new Uint8Array(t.data));if(e.size<w.min_size)return void console.warn("wisp client warning: received a packet which is too short");let s=w.parse_all(e),n=this.active_streams[s.stream_id];void 0!==n||0===s.stream_id&&s.type===b.CONTINUE?s.type===b.DATA?n.onmessage(s.payload_bytes.bytes):s.type===b.CONTINUE&&0==s.stream_id?this.max_buffer_size=s.payload.buffer_remaining:s.type===b.CONTINUE?n.continue_received(s.payload.buffer_size):s.type===b.CLOSE?this.close_stream(n,s.payload.reason):console.warn(`wisp client warning: receive an invalid packet of type ${s.type}`):console.warn(`wisp client warning: received a ${g[s.type].name} packet for a stream which doesn't exist`)}}const C=globalThis.CloseEvent||Event,E={};class z extends EventTarget{constructor(t,e){super(),this.url=t,this.protocols=e,this.binaryType="blob",this.stream=null,this.connection=null,this.onopen=()=>{},this.onerror=()=>{},this.onmessage=()=>{},this.onclose=()=>{},this.CONNECTING=0,this.OPEN=1,this.CLOSING=2,this.CLOSED=3,this._ready_state=this.CONNECTING;let s=this.url.split("/"),n=s.pop().split(":");this.host=n[0],this.port=parseInt(n[1]),this.real_url=s.join("/")+"/",this.init_connection()}on_conn_close(){this._ready_state=this.CLOSED,E[this.real_url]&&(this.onerror(new Event("error")),this.dispatchEvent(new Event("error"))),delete E[this.real_url]}init_connection(){if(this.connection=E[this.real_url],this.connection)if(this.connection.connected)this.connection=E[this.real_url],this.init_stream();else{let t=this.connection.onopen;this.connection.onopen=()=>{t(),this.init_stream()}}else this.connection=new $(this.real_url),this.connection.onopen=()=>{this.init_stream()},this.connection.onclose=()=>{this.on_conn_close()},this.connection.onerror=()=>{this.on_conn_close()},E[this.real_url]=this.connection}init_stream(){this._ready_state=this.OPEN,this.stream=this.connection.create_stream(this.host,this.port),this.stream.onmessage=t=>{let e;if("blob"==this.binaryType)e=new Blob(t);else{if("arraybuffer"!=this.binaryType)throw"invalid binaryType string";e=t.buffer}let s=new MessageEvent("message",{data:e});this.onmessage(s),this.dispatchEvent(s)},this.stream.onclose=t=>{this._ready_state=this.CLOSED;let e=new C("close",{code:t});this.onclose(e),this.dispatchEvent(e)};let t=new Event("open");this.onopen(t),this.dispatchEvent(t)}send(t){let e;if(t instanceof Uint8Array)e=t;else if("string"==typeof t)e=(new TextEncoder).encode(t);else{if(t instanceof Blob)return void t.arrayBuffer().then((t=>{this.send(t)}));if(t instanceof ArrayBuffer)e=new Uint8Array(t);else{if(!ArrayBuffer.isView(t))throw"invalid data type to be sent";e=new Uint8Array(t.buffer)}}if(!this.stream)throw"websocket is not ready";this.stream.send(e)}close(){this.stream.close(2)}get bufferedAmount(){let t=0;for(let e of this.stream.send_buffer)t+=e.length;return t}get extensions(){return""}get protocol(){return"binary"}get readyState(){return this._ready_state}}const x=1,D=2,S=3;let A=x;function R(){let[t,e]=(new Date).toJSON().split("T");return t=t.replaceAll("-","/"),e=e.split(".")[0],`[${t} - ${e}]`}function T(...t){A>x||console.info(R()+" info:",...t)}function O(...t){A>D||console.warn(R()+" warn:",...t)}function N(...t){A>S||console.error(R()+" error:",...t)}const U={hostname_blacklist:null,hostname_whitelist:null,port_blacklist:null,port_whitelist:null,allow_direct_ip:!0,allow_private_ips:!1,allow_loopback_ips:!1,client_ip_blacklist:null,client_ip_whitelist:null,stream_limit_per_host:-1,stream_limit_total:-1,allow_udp_streams:!0,allow_tcp_streams:!0,dns_ttl:120};class B{send_buffer_size=33554432;constructor(t){this.ws=t,this.connected=!1,this.data_queue=new M(1)}async connect(){await new Promise(((t,e)=>{this.ws.onopen=()=>{this.connected=!0,t()},this.ws.onmessage=t=>{this.data_queue.put(t.data)},this.ws.onclose=()=>{this.connected?this.data_queue.close():e()},this.ws.readyState===this.ws.OPEN&&(this.connected=!0,t())}))}async recv(){return await this.data_queue.get()}async send(t){if(this.ws.send(t),!(this.ws.bufferedAmount<=this.send_buffer_size))for(;!(this.ws.bufferedAmount<=this.send_buffer_size/2);)await new Promise((t=>{setTimeout(t,10)}))}close(t,e){this.ws.close(t,e),this.data_queue.close()}get buffered_amount(){return this.ws.bufferedAmount}}class M{constructor(t){this.max_size=t,this.queue=[],this.put_callbacks=[],this.get_callbacks=[]}put_now(t){this.queue.push(t),this.get_callbacks.shift()?.()}async put(t){this.size<=this.max_size||await new Promise((t=>{this.put_callbacks.push(t)})),this.put_now(t)}get_now(){return this.put_callbacks.shift()?.(),this.queue.shift()}async get(){return this.size>0||await new Promise((t=>{this.get_callbacks.push(t)})),this.get_now()}close(){let t;for(this.queue=[];t=this.get_callbacks.shift();)t();for(;t=this.put_callbacks.shift();)t()}get size(){return this.queue.length}}const q="undefined"!=typeof process,V=new Map;function L(){if(!q)throw"not running on node.js"}async function j(t){if(!q)return t;let e=a.isIP(t);if(4===e||6===e)return t;let s=Date.now();for(let[t,e]of V)s-e.time>U.dns_ttl&&V.delete(t);let n,i=V.get(t);if(i){if(i.error)throw i.error;return i.address}try{n=(await c.lookup(t)).address,V.set(t,{time:Date.now(),address:n})}catch(e){throw V.set(t,{time:Date.now(),error:e}),e}return n}class F{constructor(t,e){L(),this.hostname=t,this.port=e,this.recv_buffer_size=128,this.socket=null,this.paused=!1,this.connected=!1,this.data_queue=new M(this.recv_buffer_size)}async connect(){let t=await j(this.hostname);await new Promise(((e,s)=>{this.socket=new a.Socket,this.socket.setNoDelay(!0),this.socket.on("connect",(()=>{this.connected=!0,e()})),this.socket.on("data",(t=>{this.data_queue.put(t)})),this.socket.on("close",(t=>{t&&!this.connected?s():this.data_queue.close(),this.socket=null})),this.socket.on("error",(t=>{O(`tcp stream to ${this.hostname} ended with error - ${t}`)})),this.socket.on("end",(()=>{this.socket&&(this.socket.destroy(),this.socket=null)})),this.socket.connect({host:t,port:this.port})}))}async recv(){return await this.data_queue.get()}async send(t){await new Promise((e=>{this.socket.write(t,e)}))}async close(){this.socket&&(this.socket.end(),this.socket=null)}pause(){this.data_queue.size>=this.data_queue.max_size&&(this.socket.pause(),this.paused=!0)}resume(){this.socket&&this.paused&&(this.socket.resume(),this.paused=!1)}}class H{constructor(t,e){L(),this.hostname=t,this.port=e,this.connected=!1,this.recv_buffer_size=128,this.data_queue=new M(this.recv_buffer_size)}async connect(){let t=await j(this.hostname),e=a.isIP(t);await new Promise(((s,n)=>{this.socket=null.createSocket(6===e?"udp6":"udp4"),this.socket.on("connect",(()=>{s()})),this.socket.on("message",(t=>{this.data_queue.put(t)})),this.socket.on("error",(()=>{this.connected||n(),this.data_queue.close(),this.socket=null})),this.socket.connect(this.port,t)}))}async recv(){return await this.data_queue.get()}async send(t){this.socket.send(t)}async close(){this.socket&&(this.socket.close(),this.socket=null)}pause(){}resume(){}}var W=s(512);class G extends Error{}function J(t,e){return t===e||t[0]<=e&&t[1]>=e}function K(t,e){let s=!1;for(let n of t)if(e(n)){s=!0;break}return!s}function Q(t,e){for(let s of t)if(e(s))return!0;return!1}function X(t,e){return e.includes(t.range())}async function Y(t,e,s,n){if(!U.allow_tcp_streams&&e===k.TCP)return I.HostBlocked;if(!U.allow_udp_streams&&e===k.UDP)return I.HostBlocked;if(U.hostname_whitelist){if(K(U.hostname_whitelist,(t=>t.test(s))))return I.HostBlocked}else if(U.hostname_blacklist&&Q(U.hostname_blacklist,(t=>t.test(s))))return I.HostBlocked;if(U.port_whitelist){if(K(U.port_whitelist,(t=>J(t,n))))return I.HostBlocked}else if(U.port_blacklist&&Q(U.port_blacklist,(t=>J(t,n))))return I.HostBlocked;let i=s;if(W.isValid(s)){if(!U.allow_direct_ip)return I.HostBlocked}else try{i=await j(s)}catch{}if(function(t){if(!W.isValid(t))return!1;let e=W.parse(t);return!(U.allow_loopback_ips||!X(e,["loopback","unspecified"]))||!(U.allow_private_ips||!X(e,["broadcast","linkLocal","carrierGradeNat","private","reserved"]))}(i))return I.HostBlocked;if(!t)return 0;if(-1!==U.stream_limit_total&&Object.keys(t.streams).length>=U.stream_limit_total)return I.ConnThrottled;if(-1!==U.stream_limit_per_host){let e=0;for(let n of t.streams)n.socket.hostname===s&&e++;if(e>=U.stream_limit_per_host)return I.ConnThrottled}return 0}class Z{static buffer_size=128;constructor(t,e,s){this.stream_id=t,this.conn=e,this.socket=s,this.send_buffer=new M(Z.buffer_size),this.packets_sent=0}async setup(){await this.socket.connect(),this.tcp_to_ws().catch((t=>{N(`(${this.conn.conn_id}) a tcp/udp to ws task encountered an error - ${t}`),this.close()})),this.ws_to_tcp().catch((t=>{N(`(${this.conn.conn_id}) a ws to tcp/udp task encountered an error - ${t}`),this.close()}))}async tcp_to_ws(){for(;;){let t=await this.socket.recv();if(null==t)break;this.socket.pause();let e=new w({type:y.type,stream_id:this.stream_id,payload:new y({data:new f(new Uint8Array(t))})});await this.conn.ws.send(e.serialize().bytes),this.socket.resume()}await this.conn.close_stream(this.stream_id,I.Voluntary)}async ws_to_tcp(){for(;;){let t=await this.send_buffer.get();if(null==t)break;if(await this.socket.send(t),this.packets_sent++,this.packets_sent%(Z.buffer_size/2)!=0)continue;let e=new w({type:m.type,stream_id:this.stream_id,payload:new m({buffer_remaining:Z.buffer_size-this.send_buffer.size})});this.conn.ws.send(e.serialize().bytes)}await this.close()}async close(t=null){if(this.send_buffer.close(),this.socket.close(),null==t)return;let e=new w({type:v.type,stream_id:this.stream_id,payload:new v({reason:t})});await this.conn.ws.send(e.serialize().bytes)}async put_data(t){await this.send_buffer.put(t)}}class tt{constructor(t,e,{TCPSocket:s,UDPSocket:n,ping_interval:i}={}){this.ws=new B(t),this.path=e,this.TCPSocket=s||F,this.UDPSocket=n||H,this.ping_interval=i||30,this.ping_task=null,this.streams={},this.conn_id=o.randomUUID().split("-")[0]}async setup(){T(`setting up new wisp connection with id ${this.conn_id}`),await this.ws.connect();let t=new w({type:m.type,stream_id:0,payload:new m({buffer_remaining:Z.buffer_size})});await this.ws.send(t.serialize().bytes),"function"==typeof this.ws.ws.ping&&(this.ping_task=setInterval((()=>{!function(...t){A>0||console.debug(R()+" debug:",...t)}(`(${this.conn_id}) sending websocket ping`),this.ws.ws.ping()}),1e3*this.ping_interval))}create_stream(t,e,s,n){let i=new(e===k.TCP?this.TCPSocket:this.UDPSocket)(s,n),r=new Z(t,this,i);this.streams[t]=r,(async()=>{let i=await Y(this,e,s,n);if(i)return O(`(${this.conn_id}) refusing to create a stream to ${s}:${n}`),void await this.close_stream(t,i,!0);try{await r.setup()}catch(e){O(`(${this.conn_id}) creating a stream to ${s}:${n} failed - ${e}`),await this.close_stream(t,I.NetworkError)}})()}async close_stream(t,e=null,s=!1){let n=this.streams[t];null!=n&&(e&&!s&&T(`(${this.conn_id}) closing stream to ${n.socket.hostname} for reason ${e}`),await n.close(e),delete this.streams[t])}route_packet(t){let e=w.parse_all(t),s=this.streams[e.stream_id];if(null!=s||e.type!=y.type)if(e.type===_.type){let t=e.payload.stream_type===k.TCP?"TCP":"UDP";T(`(${this.conn_id}) opening new ${t} stream to ${e.payload.hostname}:${e.payload.port}`),this.create_stream(e.stream_id,e.payload.stream_type,e.payload.hostname.trim(),e.payload.port)}else e.type===y.type?s.put_data(e.payload.data.bytes):e.type==m.type?O(`(${this.conn_id}) client sent a CONTINUE packet, this should never be possible`):e.type==v.type&&this.close_stream(e.stream_id,e.reason);else O(`(${this.conn_id}) received a DATA packet for a stream which doesn't exist`)}async run(){for(;;){let t;if(t=await this.ws.recv(),null==t)break;try{this.route_packet(new f(new Uint8Array(t)))}catch(t){O(`(${this.conn_id}) routing a packet failed - ${t}`)}}for(let t of Object.keys(this.streams))await this.close_stream(t);clearInterval(this.ping_task),T(`(${this.conn_id}) wisp connection closed`)}}class et{constructor(t,e){let[s,n]=e.split("/").pop().split(":");this.hostname=s.trim(),this.port=parseInt(n),this.ws=new B(t)}async setup(){if(await this.ws.connect(),0!==await Y(null,k.TCP,this.hostname,this.port))throw T(`Refusing to create a wsproxy connection to ${this.hostname}:${this.port}`),this.ws.close(),new G;this.socket=new F(this.hostname,this.port),await this.socket.connect(),this.tcp_to_ws().catch((t=>{N(`a tcp to ws task (wsproxy) encountered an error - ${t}`)})),this.ws_to_tcp().catch((t=>{N(`a ws to tcp task (wsproxy) encountered an error - ${t}`)}))}async tcp_to_ws(){for(;;){let t=await this.socket.recv();if(null==t)break;this.socket.pause(),await this.ws.send(t),this.socket.resume()}await this.ws.close()}async ws_to_tcp(){for(;;){let t;if(t=await this.ws.recv(),null==t)break;await this.socket.send(t)}await this.socket.close()}}let st=null;function nt(t,e,s,n={}){L(),t instanceof h.IncomingMessage?st.handleUpgrade(t,e,s,(e=>{it(e,t.url,t,n)})):t instanceof r&&it(ws,"/",{})}async function it(t,e,s,n){T(`new connection on ${e} from ${s.socket.address().address}`);try{if(e.endsWith("/")){let s=new tt(t,e,n);await s.setup(),await s.run()}else{let s=new et(t,e,n);await s.setup()}}catch(e){if(t.close(),e instanceof G)return;N("Uncaught server error:\n"+e.stack)}}q&&(st=new null({noServer:!0}))})(),wisp_full=n})(); |
@@ -1,1 +0,1 @@ | ||
var wisp_server;(()=>{"use strict";var t={d:(e,s)=>{for(var i in s)t.o(s,i)&&!t.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:s[i]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};t.r(e),t.d(e,{logging:()=>s,packet:()=>i,server:()=>a});var s={};t.r(s),t.d(s,{DEBUG:()=>n,ERROR:()=>c,INFO:()=>o,NONE:()=>l,WARN:()=>r,debug:()=>_,error:()=>y,get_timestamp:()=>u,info:()=>d,log:()=>w,log_level:()=>h,set_level:()=>p,warn:()=>f});var i={};t.r(i),t.d(i,{ClosePayload:()=>T,ConnectPayload:()=>$,ContinuePayload:()=>U,DataPayload:()=>P,WispBuffer:()=>v,WispPacket:()=>z,close_reasons:()=>N,packet_classes:()=>C,packet_types:()=>S,stream_types:()=>q});var a={};t.r(a),t.d(a,{ServerConnection:()=>X,ServerStream:()=>Q,options:()=>O,routeRequest:()=>tt});const n=0,o=1,r=2,c=3,l=4;let h=o;function u(){let[t,e]=(new Date).toJSON().split("T");return t=t.replaceAll("-","/"),e=e.split(".")[0],`[${t} - ${e}]`}function p(t){h=t}function _(...t){h>n||console.debug(u()+" debug:",...t)}function d(...t){h>o||console.info(u()+" info:",...t)}function w(...t){h>o||console.log(u()+" log:",...t)}function f(...t){h>r||console.warn(u()+" warn:",...t)}function y(...t){h>c||console.error(u()+" error:",...t)}const m=new TextEncoder,k=m.encode.bind(m),b=new TextDecoder,g=b.decode.bind(b);class v{constructor(t){if(t instanceof Uint8Array)this.from_array(t);else if("number"==typeof t)this.from_array(new Uint8Array(t));else{if("string"!=typeof t)throw console.trace(),"invalid data type passed to wisp buffer constructor";this.from_array(k(t))}}from_array(t){this.size=t.length,this.bytes=t,this.view=new DataView(t.buffer)}concat(t){let e=new v(this.size+t.size);return e.bytes.set(this.bytes,0),e.bytes.set(t.bytes,this.size),e}slice(t,e){let s=this.bytes.slice(t,e);return new v(s)}}class z{static min_size=5;constructor({type:t,stream_id:e,payload:s,payload_bytes:i}){this.type=t,this.stream_id=e,this.payload_bytes=i,this.payload=s}static parse(t){return new z({type:t.view.getUint8(0),stream_id:t.view.getUint32(1,!0),payload_bytes:t.slice(5)})}static parse_all(t){if(t.size<z.min_size)throw"packet too small";let e=z.parse(t),s=C[e.type];if(void 0===s)throw"invalid packet type";if(e.payload_bytes.size<s.size)throw"payload too small";return e.payload=s.parse(e.payload_bytes),e}serialize(){let t=new v(5);return t.view.setUint8(0,this.type),t.view.setUint32(1,this.stream_id,!0),t=t.concat(this.payload.serialize()),t}}class ${static min_size=3;static type=1;static name="CONNECT";constructor({stream_type:t,port:e,hostname:s}){this.stream_type=t,this.port=e,this.hostname=s}static parse(t){return new $({stream_type:t.view.getUint8(0),port:t.view.getUint16(1,!0),hostname:g(t.slice(3).bytes)})}serialize(){let t=new v(3);return t.view.setUint8(0,this.stream_type),t.view.setUint16(1,this.port,!0),t=t.concat(new v(this.hostname)),t}}class P{static min_size=0;static type=2;static name="DATA";constructor({data:t}){this.data=t}static parse(t){return new P({data:t})}serialize(){return this.data}}class U{static type=3;static name="CONTINUE";constructor({buffer_remaining:t}){this.buffer_remaining=t}static parse(t){return new U({buffer_remaining:t.view.getUint32(0,!0)})}serialize(){let t=new v(4);return t.view.setUint32(0,this.buffer_remaining,!0),t}}class T{static min_size=1;static type=4;static name="CLOSE";constructor({reason:t}){this.reason=t}static parse(t){return new T({reason:t.view.getUint8(0)})}serialize(){let t=new v(1);return t.view.setUint8(0,this.buffer_remaining),t}}const C=[void 0,$,P,U,T],S={CONNECT:1,DATA:2,CONTINUE:3,CLOSE:4},q={TCP:1,UDP:2},N={Unknown:1,Voluntary:2,NetworkError:3,InvalidInfo:65,UnreachableHost:66,NoResponse:67,ConnRefused:68,TransferTimeout:71,HostBlocked:72,ConnThrottled:73,ClientError:129},O={hostname_blacklist:null,hostname_whitelist:null,port_blacklist:null,port_whitelist:null,allow_direct_ip:!0,allow_private_ips:!1,allow_loopback_ips:!1,client_ip_blacklist:null,client_ip_whitelist:null,stream_limit_per_host:-1,stream_limit_total:-1,allow_udp_streams:!0,allow_tcp_streams:!0};class D extends Error{}function E(t,e){return t===e||t[0]<=e&&t[1]>=e}function A(t,e){let s=!1;for(let i of t)if(e(i)){s=!0;break}return!s}function I(t,e){for(let s of t)if(e(s))return!0;return!1}function x(t,e,s,i){if(!O.allow_tcp_streams&&e===q.TCP)return N.HostBlocked;if(!O.allow_udp_streams&&e===q.UDP)return N.HostBlocked;if(O.hostname_whitelist){if(A(O.hostname_whitelist,(t=>t.test(s))))return N.HostBlocked}else if(O.hostname_blacklist&&I(O.hostname_blacklist,(t=>t.test(s))))return N.HostBlocked;if(O.port_whitelist){if(A(O.port_whitelist,(t=>E(t,i))))return N.HostBlocked}else if(O.port_blacklist&&I(O.port_blacklist,(t=>E(t,i))))return N.HostBlocked;if(!t)return 0;if(-1!==O.stream_limit_total&&Object.keys(t.streams).length>=O.stream_limit_total)return N.ConnThrottled;if(-1!==O.stream_limit_per_host){let e=0;for(let i of t.streams)i.socket.hostname===s&&e++;if(e>=O.stream_limit_per_host)return N.ConnThrottled}return 0}const B=globalThis.WebSocket,H=globalThis.crypto,R=null,j=null,W=null;class M{send_buffer_size=33554432;constructor(t){this.ws=t,this.connected=!1,this.data_queue=new V(1)}async connect(){await new Promise(((t,e)=>{this.ws.onopen=()=>{this.connected=!0,t()},this.ws.onmessage=t=>{this.data_queue.put(t.data)},this.ws.onclose=()=>{this.connected?this.data_queue.close():e()},this.ws.readyState===this.ws.OPEN&&(this.connected=!0,t())}))}async recv(){return await this.data_queue.get()}async send(t){if(this.ws.send(t),!(this.ws.bufferedAmount<=this.send_buffer_size))for(;!(this.ws.bufferedAmount<=this.send_buffer_size/2);)await new Promise((t=>{setTimeout(t,10)}))}close(t,e){this.ws.close(t,e),this.data_queue.close()}get buffered_amount(){return this.ws.bufferedAmount}}class V{constructor(t){this.max_size=t,this.queue=[],this.put_callbacks=[],this.get_callbacks=[]}put_now(t){this.queue.push(t),this.get_callbacks.shift()?.()}async put(t){this.size<=this.max_size||await new Promise((t=>{this.put_callbacks.push(t)})),this.put_now(t)}get_now(){return this.put_callbacks.shift()?.(),this.queue.shift()}async get(){return this.size>0||await new Promise((t=>{this.get_callbacks.push(t)})),this.get_now()}close(){let t;for(this.queue=[];t=this.get_callbacks.shift();)t();for(;t=this.put_callbacks.shift();)t()}get size(){return this.queue.length}}const L="undefined"!=typeof process;function F(){if(!L)throw"not running on node.js"}async function G(t){let e=R.isIP(t);return 4===e||6===e?t:(await j.lookup(t)).address}class J{constructor(t,e){F(),this.hostname=t,this.port=e,this.recv_buffer_size=128,this.socket=null,this.paused=!1,this.connected=!1,this.data_queue=new V(this.recv_buffer_size)}async connect(){let t=await G(this.hostname);await new Promise(((e,s)=>{this.socket=new R.Socket,this.socket.setNoDelay(!0),this.socket.on("connect",(()=>{this.connected=!0,e()})),this.socket.on("data",(t=>{this.data_queue.put(t)})),this.socket.on("close",(t=>{t&&!this.connected?s():this.data_queue.close(),this.socket=null})),this.socket.on("error",(t=>{f(`tcp stream to ${this.hostname} ended with error - ${t}`)})),this.socket.on("end",(()=>{this.socket&&(this.socket.destroy(),this.socket=null)})),this.socket.connect({host:t,port:this.port})}))}async recv(){return await this.data_queue.get()}async send(t){await new Promise((e=>{this.socket.write(t,e)}))}async close(){this.socket&&(this.socket.end(),this.socket=null)}pause(){this.data_queue.size>=this.data_queue.max_size&&(this.socket.pause(),this.paused=!0)}resume(){this.socket&&this.paused&&(this.socket.resume(),this.paused=!1)}}class K{constructor(t,e){F(),this.hostname=t,this.port=e,this.connected=!1,this.recv_buffer_size=128,this.data_queue=new V(this.recv_buffer_size)}async connect(){let t=await G(this.hostname),e=R.isIP(t);await new Promise(((s,i)=>{this.socket=null.createSocket(6===e?"udp6":"udp4"),this.socket.on("connect",(()=>{s()})),this.socket.on("message",(t=>{this.data_queue.put(t)})),this.socket.on("error",(()=>{this.connected||i(),this.data_queue.close(),this.socket=null})),this.socket.connect(this.port,t)}))}async recv(){return await this.data_queue.get()}async send(t){this.socket.send(t)}async close(){this.socket&&(this.socket.close(),this.socket=null)}pause(){}resume(){}}class Q{static buffer_size=128;constructor(t,e,s){this.stream_id=t,this.conn=e,this.socket=s,this.send_buffer=new V(Q.buffer_size),this.packets_sent=0}async setup(){await this.socket.connect(),this.tcp_to_ws().catch((t=>{y(`(${this.conn.conn_id}) a tcp/udp to ws task encountered an error - ${t}`),this.close()})),this.ws_to_tcp().catch((t=>{y(`(${this.conn.conn_id}) a ws to tcp/udp task encountered an error - ${t}`),this.close()}))}async tcp_to_ws(){for(;;){let t=await this.socket.recv();if(null==t)break;this.socket.pause();let e=new z({type:P.type,stream_id:this.stream_id,payload:new P({data:new v(new Uint8Array(t))})});await this.conn.ws.send(e.serialize().bytes),this.socket.resume()}await this.conn.close_stream(this.stream_id,N.Voluntary)}async ws_to_tcp(){for(;;){let t=await this.send_buffer.get();if(null==t)break;if(await this.socket.send(t),this.packets_sent++,this.packets_sent%(Q.buffer_size/2)!=0)continue;let e=new z({type:U.type,stream_id:this.stream_id,payload:new U({buffer_remaining:Q.buffer_size-this.send_buffer.size})});this.conn.ws.send(e.serialize().bytes)}await this.close()}async close(t=null){if(this.send_buffer.close(),this.socket.close(),null==t)return;let e=new z({type:T.type,stream_id:this.stream_id,payload:new T({reason:t})});await this.conn.ws.send(e.serialize().bytes)}async put_data(t){await this.send_buffer.put(t)}}class X{constructor(t,e,{TCPSocket:s,UDPSocket:i,ping_interval:a}={}){this.ws=new M(t),this.path=e,this.TCPSocket=s||J,this.UDPSocket=i||K,this.ping_interval=a||30,this.ping_task=null,this.streams={},this.conn_id=H.randomUUID().split("-")[0]}async setup(){d(`setting up new wisp connection with id ${this.conn_id}`),await this.ws.connect();let t=new z({type:U.type,stream_id:0,payload:new U({buffer_remaining:Q.buffer_size})});await this.ws.send(t.serialize().bytes),"function"==typeof this.ws.ws.ping&&(this.ping_task=setInterval((()=>{_(`(${this.conn_id}) sending websocket ping`),this.ws.ws.ping()}),1e3*this.ping_interval))}async create_stream(t,e,s,i){let a=x(this,e,s,i);if(a){f(`(${this.conn_id}) refusing to create a stream to ${s}:${i}`);let e=new z({type:T.type,stream_id:t,payload:new T({reason:a})});return void await this.ws.send(e.serialize().bytes)}let n=new(e===q.TCP?this.TCPSocket:this.UDPSocket)(s,i),o=new Q(t,this,n);this.streams[t]=o,o.setup().catch((e=>{f(`(${this.conn_id}) creating a stream to ${s}:${i} failed - ${e}`),this.close_stream(t,N.NetworkError)}))}async close_stream(t,e=null){let s=this.streams[t];null!=s&&(e&&d(`(${this.conn_id}) closing stream to ${s.socket.hostname} for reason ${e}`),await s.close(e),delete this.streams[t])}async route_packet(t){let e=z.parse_all(t),s=this.streams[e.stream_id];if(null!=s||e.type!=P.type)if(e.type===$.type){let t=e.payload.stream_type===q.TCP?"TCP":"UDP";d(`(${this.conn_id}) opening new ${t} stream to ${e.payload.hostname}:${e.payload.port}`),await this.create_stream(e.stream_id,e.payload.stream_type,e.payload.hostname,e.payload.port)}else e.type===P.type?s.put_data(e.payload.data.bytes):e.type==U.type?f(`(${this.conn_id}) client sent a CONTINUE packet, this should never be possible`):e.type==T.type&&await this.close_stream(e.stream_id,e.reason);else f(`(${this.conn_id}) received a DATA packet for a stream which doesn't exist`)}async run(){for(;;){let t;if(t=await this.ws.recv(),null==t)break;try{this.route_packet(new v(new Uint8Array(t)))}catch(t){f(`(${this.conn_id}) routing a packet failed - ${t}`)}}for(let t of Object.keys(this.streams))await this.close_stream(t);clearInterval(this.ping_task),d(`(${this.conn_id}) wisp connection closed`)}}class Y{constructor(t,e){let[s,i]=e.split("/").pop().split(":");if(this.hostname=s,this.port=parseInt(i),0!==x(null,q.TCP,this.hostname,this.port))throw d(`Refusing to create a wsproxy connection to ${this.hostname}:${this.port}`),new D;this.socket=new J(s,i),this.ws=new M(t)}async setup(){await this.ws.connect(),await this.socket.connect(),this.tcp_to_ws().catch((t=>{y(`a tcp to ws task (wsproxy) encountered an error - ${t}`)})),this.ws_to_tcp().catch((t=>{y(`a ws to tcp task (wsproxy) encountered an error - ${t}`)}))}async tcp_to_ws(){for(;;){let t=await this.socket.recv();if(null==t)break;this.socket.pause(),await this.ws.send(t),this.socket.resume()}await this.ws.close()}async ws_to_tcp(){for(;;){let t;if(t=await this.ws.recv(),null==t)break;await this.socket.send(t)}await this.socket.close()}}let Z=null;function tt(t,e,s,i={}){F(),t instanceof W.IncomingMessage?Z.handleUpgrade(t,e,s,(e=>{et(e,t.url,t,i)})):t instanceof B&&et(ws,"/",{})}async function et(t,e,s,i){d(`new connection on ${e} from ${s.socket.address().address}`);try{if(e.endsWith("/")){let s=new X(t,e,i);await s.setup(),await s.run()}else{let s=new Y(t,e,i);await s.setup()}}catch(e){if(t.close(),e instanceof D)return;y("Uncaught server error:\n"+e.stack)}}L&&(Z=new null({noServer:!0})),wisp_server=e})(); | ||
var wisp_server;(()=>{var t={512:function(t){!function(e){"use strict";const s="(0?\\d+|0x[a-f0-9]+)",r={fourOctet:new RegExp(`^${s}\\.${s}\\.${s}\\.${s}$`,"i"),threeOctet:new RegExp(`^${s}\\.${s}\\.${s}$`,"i"),twoOctet:new RegExp(`^${s}\\.${s}$`,"i"),longValue:new RegExp(`^${s}$`,"i")},n=new RegExp("^0[0-7]+$","i"),i=new RegExp("^0x[a-f0-9]+$","i"),o="%[0-9a-z]{1,}",a="(?:[0-9a-f]+::?)+",c={zoneIndex:new RegExp(o,"i"),native:new RegExp(`^(::)?(${a})?([0-9a-f]+)?(::)?(${o})?$`,"i"),deprecatedTransitional:new RegExp(`^(?:::)(${s}\\.${s}\\.${s}\\.${s}(${o})?)$`,"i"),transitional:new RegExp(`^((?:${a})|(?:::)(?:${a})?)${s}\\.${s}\\.${s}\\.${s}(${o})?$`,"i")};function l(t,e){if(t.indexOf("::")!==t.lastIndexOf("::"))return null;let s,r,n=0,i=-1,o=(t.match(c.zoneIndex)||[])[0];for(o&&(o=o.substring(1),t=t.replace(/%.+$/,""));(i=t.indexOf(":",i+1))>=0;)n++;if("::"===t.substr(0,2)&&n--,"::"===t.substr(-2,2)&&n--,n>e)return null;for(r=e-n,s=":";r--;)s+="0:";return":"===(t=t.replace("::",s))[0]&&(t=t.slice(1)),":"===t[t.length-1]&&(t=t.slice(0,-1)),{parts:e=function(){const e=t.split(":"),s=[];for(let t=0;t<e.length;t++)s.push(parseInt(e[t],16));return s}(),zoneId:o}}function h(t,e,s,r){if(t.length!==e.length)throw new Error("ipaddr: cannot match CIDR for objects with different lengths");let n,i=0;for(;r>0;){if(n=s-r,n<0&&(n=0),t[i]>>n!=e[i]>>n)return!1;r-=s,i+=1}return!0}function u(t){if(i.test(t))return parseInt(t,16);if("0"===t[0]&&!isNaN(parseInt(t[1],10))){if(n.test(t))return parseInt(t,8);throw new Error(`ipaddr: cannot parse ${t} as octal`)}return parseInt(t,10)}function p(t,e){for(;t.length<e;)t=`0${t}`;return t}const d={};d.IPv4=function(){function t(t){if(4!==t.length)throw new Error("ipaddr: ipv4 octet count should be 4");let e,s;for(e=0;e<t.length;e++)if(s=t[e],!(0<=s&&s<=255))throw new Error("ipaddr: ipv4 octet should fit in 8 bits");this.octets=t}return t.prototype.SpecialRanges={unspecified:[[new t([0,0,0,0]),8]],broadcast:[[new t([255,255,255,255]),32]],multicast:[[new t([224,0,0,0]),4]],linkLocal:[[new t([169,254,0,0]),16]],loopback:[[new t([127,0,0,0]),8]],carrierGradeNat:[[new t([100,64,0,0]),10]],private:[[new t([10,0,0,0]),8],[new t([172,16,0,0]),12],[new t([192,168,0,0]),16]],reserved:[[new t([192,0,0,0]),24],[new t([192,0,2,0]),24],[new t([192,88,99,0]),24],[new t([198,18,0,0]),15],[new t([198,51,100,0]),24],[new t([203,0,113,0]),24],[new t([240,0,0,0]),4]],as112:[[new t([192,175,48,0]),24],[new t([192,31,196,0]),24]],amt:[[new t([192,52,193,0]),24]]},t.prototype.kind=function(){return"ipv4"},t.prototype.match=function(t,e){let s;if(void 0===e&&(s=t,t=s[0],e=s[1]),"ipv4"!==t.kind())throw new Error("ipaddr: cannot match ipv4 address with non-ipv4 one");return h(this.octets,t.octets,8,e)},t.prototype.prefixLengthFromSubnetMask=function(){let t=0,e=!1;const s={0:8,128:7,192:6,224:5,240:4,248:3,252:2,254:1,255:0};let r,n,i;for(r=3;r>=0;r-=1){if(n=this.octets[r],!(n in s))return null;if(i=s[n],e&&0!==i)return null;8!==i&&(e=!0),t+=i}return 32-t},t.prototype.range=function(){return d.subnetMatch(this,this.SpecialRanges)},t.prototype.toByteArray=function(){return this.octets.slice(0)},t.prototype.toIPv4MappedAddress=function(){return d.IPv6.parse(`::ffff:${this.toString()}`)},t.prototype.toNormalizedString=function(){return this.toString()},t.prototype.toString=function(){return this.octets.join(".")},t}(),d.IPv4.broadcastAddressFromCIDR=function(t){try{const e=this.parseCIDR(t),s=e[0].toByteArray(),r=this.subnetMaskFromPrefixLength(e[1]).toByteArray(),n=[];let i=0;for(;i<4;)n.push(parseInt(s[i],10)|255^parseInt(r[i],10)),i++;return new this(n)}catch(t){throw new Error("ipaddr: the address does not have IPv4 CIDR format")}},d.IPv4.isIPv4=function(t){return null!==this.parser(t)},d.IPv4.isValid=function(t){try{return new this(this.parser(t)),!0}catch(t){return!1}},d.IPv4.isValidCIDR=function(t){try{return this.parseCIDR(t),!0}catch(t){return!1}},d.IPv4.isValidFourPartDecimal=function(t){return!(!d.IPv4.isValid(t)||!t.match(/^(0|[1-9]\d*)(\.(0|[1-9]\d*)){3}$/))},d.IPv4.networkAddressFromCIDR=function(t){let e,s,r,n,i;try{for(e=this.parseCIDR(t),r=e[0].toByteArray(),i=this.subnetMaskFromPrefixLength(e[1]).toByteArray(),n=[],s=0;s<4;)n.push(parseInt(r[s],10)&parseInt(i[s],10)),s++;return new this(n)}catch(t){throw new Error("ipaddr: the address does not have IPv4 CIDR format")}},d.IPv4.parse=function(t){const e=this.parser(t);if(null===e)throw new Error("ipaddr: string is not formatted like an IPv4 Address");return new this(e)},d.IPv4.parseCIDR=function(t){let e;if(e=t.match(/^(.+)\/(\d+)$/)){const t=parseInt(e[2]);if(t>=0&&t<=32){const s=[this.parse(e[1]),t];return Object.defineProperty(s,"toString",{value:function(){return this.join("/")}}),s}}throw new Error("ipaddr: string is not formatted like an IPv4 CIDR range")},d.IPv4.parser=function(t){let e,s,n;if(e=t.match(r.fourOctet))return function(){const t=e.slice(1,6),r=[];for(let e=0;e<t.length;e++)s=t[e],r.push(u(s));return r}();if(e=t.match(r.longValue)){if(n=u(e[1]),n>4294967295||n<0)throw new Error("ipaddr: address outside defined range");return function(){const t=[];let e;for(e=0;e<=24;e+=8)t.push(n>>e&255);return t}().reverse()}return(e=t.match(r.twoOctet))?function(){const t=e.slice(1,4),s=[];if(n=u(t[1]),n>16777215||n<0)throw new Error("ipaddr: address outside defined range");return s.push(u(t[0])),s.push(n>>16&255),s.push(n>>8&255),s.push(255&n),s}():(e=t.match(r.threeOctet))?function(){const t=e.slice(1,5),s=[];if(n=u(t[2]),n>65535||n<0)throw new Error("ipaddr: address outside defined range");return s.push(u(t[0])),s.push(u(t[1])),s.push(n>>8&255),s.push(255&n),s}():null},d.IPv4.subnetMaskFromPrefixLength=function(t){if((t=parseInt(t))<0||t>32)throw new Error("ipaddr: invalid IPv4 prefix length");const e=[0,0,0,0];let s=0;const r=Math.floor(t/8);for(;s<r;)e[s]=255,s++;return r<4&&(e[r]=Math.pow(2,t%8)-1<<8-t%8),new this(e)},d.IPv6=function(){function t(t,e){let s,r;if(16===t.length)for(this.parts=[],s=0;s<=14;s+=2)this.parts.push(t[s]<<8|t[s+1]);else{if(8!==t.length)throw new Error("ipaddr: ipv6 part count should be 8 or 16");this.parts=t}for(s=0;s<this.parts.length;s++)if(r=this.parts[s],!(0<=r&&r<=65535))throw new Error("ipaddr: ipv6 part should fit in 16 bits");e&&(this.zoneId=e)}return t.prototype.SpecialRanges={unspecified:[new t([0,0,0,0,0,0,0,0]),128],linkLocal:[new t([65152,0,0,0,0,0,0,0]),10],multicast:[new t([65280,0,0,0,0,0,0,0]),8],loopback:[new t([0,0,0,0,0,0,0,1]),128],uniqueLocal:[new t([64512,0,0,0,0,0,0,0]),7],ipv4Mapped:[new t([0,0,0,0,0,65535,0,0]),96],discard:[new t([256,0,0,0,0,0,0,0]),64],rfc6145:[new t([0,0,0,0,65535,0,0,0]),96],rfc6052:[new t([100,65435,0,0,0,0,0,0]),96],"6to4":[new t([8194,0,0,0,0,0,0,0]),16],teredo:[new t([8193,0,0,0,0,0,0,0]),32],benchmarking:[new t([8193,2,0,0,0,0,0,0]),48],amt:[new t([8193,3,0,0,0,0,0,0]),32],as112v6:[[new t([8193,4,274,0,0,0,0,0]),48],[new t([9760,79,32768,0,0,0,0,0]),48]],deprecated:[new t([8193,16,0,0,0,0,0,0]),28],orchid2:[new t([8193,32,0,0,0,0,0,0]),28],droneRemoteIdProtocolEntityTags:[new t([8193,48,0,0,0,0,0,0]),28],reserved:[[new t([8193,0,0,0,0,0,0,0]),23],[new t([8193,3512,0,0,0,0,0,0]),32]]},t.prototype.isIPv4MappedAddress=function(){return"ipv4Mapped"===this.range()},t.prototype.kind=function(){return"ipv6"},t.prototype.match=function(t,e){let s;if(void 0===e&&(s=t,t=s[0],e=s[1]),"ipv6"!==t.kind())throw new Error("ipaddr: cannot match ipv6 address with non-ipv6 one");return h(this.parts,t.parts,16,e)},t.prototype.prefixLengthFromSubnetMask=function(){let t=0,e=!1;const s={0:16,32768:15,49152:14,57344:13,61440:12,63488:11,64512:10,65024:9,65280:8,65408:7,65472:6,65504:5,65520:4,65528:3,65532:2,65534:1,65535:0};let r,n;for(let i=7;i>=0;i-=1){if(r=this.parts[i],!(r in s))return null;if(n=s[r],e&&0!==n)return null;16!==n&&(e=!0),t+=n}return 128-t},t.prototype.range=function(){return d.subnetMatch(this,this.SpecialRanges)},t.prototype.toByteArray=function(){let t;const e=[],s=this.parts;for(let r=0;r<s.length;r++)t=s[r],e.push(t>>8),e.push(255&t);return e},t.prototype.toFixedLengthString=function(){const t=function(){const t=[];for(let e=0;e<this.parts.length;e++)t.push(p(this.parts[e].toString(16),4));return t}.call(this).join(":");let e="";return this.zoneId&&(e=`%${this.zoneId}`),t+e},t.prototype.toIPv4Address=function(){if(!this.isIPv4MappedAddress())throw new Error("ipaddr: trying to convert a generic ipv6 address to ipv4");const t=this.parts.slice(-2),e=t[0],s=t[1];return new d.IPv4([e>>8,255&e,s>>8,255&s])},t.prototype.toNormalizedString=function(){const t=function(){const t=[];for(let e=0;e<this.parts.length;e++)t.push(this.parts[e].toString(16));return t}.call(this).join(":");let e="";return this.zoneId&&(e=`%${this.zoneId}`),t+e},t.prototype.toRFC5952String=function(){const t=/((^|:)(0(:|$)){2,})/g,e=this.toNormalizedString();let s,r=0,n=-1;for(;s=t.exec(e);)s[0].length>n&&(r=s.index,n=s[0].length);return n<0?e:`${e.substring(0,r)}::${e.substring(r+n)}`},t.prototype.toString=function(){return this.toRFC5952String()},t}(),d.IPv6.broadcastAddressFromCIDR=function(t){try{const e=this.parseCIDR(t),s=e[0].toByteArray(),r=this.subnetMaskFromPrefixLength(e[1]).toByteArray(),n=[];let i=0;for(;i<16;)n.push(parseInt(s[i],10)|255^parseInt(r[i],10)),i++;return new this(n)}catch(t){throw new Error(`ipaddr: the address does not have IPv6 CIDR format (${t})`)}},d.IPv6.isIPv6=function(t){return null!==this.parser(t)},d.IPv6.isValid=function(t){if("string"==typeof t&&-1===t.indexOf(":"))return!1;try{const e=this.parser(t);return new this(e.parts,e.zoneId),!0}catch(t){return!1}},d.IPv6.isValidCIDR=function(t){if("string"==typeof t&&-1===t.indexOf(":"))return!1;try{return this.parseCIDR(t),!0}catch(t){return!1}},d.IPv6.networkAddressFromCIDR=function(t){let e,s,r,n,i;try{for(e=this.parseCIDR(t),r=e[0].toByteArray(),i=this.subnetMaskFromPrefixLength(e[1]).toByteArray(),n=[],s=0;s<16;)n.push(parseInt(r[s],10)&parseInt(i[s],10)),s++;return new this(n)}catch(t){throw new Error(`ipaddr: the address does not have IPv6 CIDR format (${t})`)}},d.IPv6.parse=function(t){const e=this.parser(t);if(null===e.parts)throw new Error("ipaddr: string is not formatted like an IPv6 Address");return new this(e.parts,e.zoneId)},d.IPv6.parseCIDR=function(t){let e,s,r;if((s=t.match(/^(.+)\/(\d+)$/))&&(e=parseInt(s[2]),e>=0&&e<=128))return r=[this.parse(s[1]),e],Object.defineProperty(r,"toString",{value:function(){return this.join("/")}}),r;throw new Error("ipaddr: string is not formatted like an IPv6 CIDR range")},d.IPv6.parser=function(t){let e,s,r,n,i,o;if(r=t.match(c.deprecatedTransitional))return this.parser(`::ffff:${r[1]}`);if(c.native.test(t))return l(t,8);if((r=t.match(c.transitional))&&(o=r[6]||"",e=r[1],r[1].endsWith("::")||(e=e.slice(0,-1)),e=l(e+o,6),e.parts)){for(i=[parseInt(r[2]),parseInt(r[3]),parseInt(r[4]),parseInt(r[5])],s=0;s<i.length;s++)if(n=i[s],!(0<=n&&n<=255))return null;return e.parts.push(i[0]<<8|i[1]),e.parts.push(i[2]<<8|i[3]),{parts:e.parts,zoneId:e.zoneId}}return null},d.IPv6.subnetMaskFromPrefixLength=function(t){if((t=parseInt(t))<0||t>128)throw new Error("ipaddr: invalid IPv6 prefix length");const e=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];let s=0;const r=Math.floor(t/8);for(;s<r;)e[s]=255,s++;return r<16&&(e[r]=Math.pow(2,t%8)-1<<8-t%8),new this(e)},d.fromByteArray=function(t){const e=t.length;if(4===e)return new d.IPv4(t);if(16===e)return new d.IPv6(t);throw new Error("ipaddr: the binary input is neither an IPv6 nor IPv4 address")},d.isValid=function(t){return d.IPv6.isValid(t)||d.IPv4.isValid(t)},d.isValidCIDR=function(t){return d.IPv6.isValidCIDR(t)||d.IPv4.isValidCIDR(t)},d.parse=function(t){if(d.IPv6.isValid(t))return d.IPv6.parse(t);if(d.IPv4.isValid(t))return d.IPv4.parse(t);throw new Error("ipaddr: the address has neither IPv6 nor IPv4 format")},d.parseCIDR=function(t){try{return d.IPv6.parseCIDR(t)}catch(e){try{return d.IPv4.parseCIDR(t)}catch(t){throw new Error("ipaddr: the address has neither IPv6 nor IPv4 CIDR format")}}},d.process=function(t){const e=this.parse(t);return"ipv6"===e.kind()&&e.isIPv4MappedAddress()?e.toIPv4Address():e},d.subnetMatch=function(t,e,s){let r,n,i,o;for(n in null==s&&(s="unicast"),e)if(Object.prototype.hasOwnProperty.call(e,n))for(i=e[n],!i[0]||i[0]instanceof Array||(i=[i]),r=0;r<i.length;r++)if(o=i[r],t.kind()===o[0].kind()&&t.match.apply(t,o))return n;return s},t.exports?t.exports=d:e.ipaddr=d}(this)}},e={};function s(r){var n=e[r];if(void 0!==n)return n.exports;var i=e[r]={exports:{}};return t[r].call(i.exports,i,i.exports,s),i.exports}s.d=(t,e)=>{for(var r in e)s.o(e,r)&&!s.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:e[r]})},s.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),s.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var r={};(()=>{"use strict";s.r(r),s.d(r,{logging:()=>t,packet:()=>e,server:()=>n});var t={};s.r(t),s.d(t,{DEBUG:()=>i,ERROR:()=>c,INFO:()=>o,NONE:()=>l,WARN:()=>a,debug:()=>d,error:()=>y,get_timestamp:()=>u,info:()=>f,log:()=>w,log_level:()=>h,set_level:()=>p,warn:()=>_});var e={};s.r(e),s.d(e,{ClosePayload:()=>C,ConnectPayload:()=>P,ContinuePayload:()=>z,DataPayload:()=>$,WispBuffer:()=>I,WispPacket:()=>b,close_reasons:()=>D,packet_classes:()=>R,packet_types:()=>E,stream_types:()=>x});var n={};s.r(n),s.d(n,{ServerConnection:()=>tt,ServerStream:()=>Z,options:()=>S,routeRequest:()=>rt});const i=0,o=1,a=2,c=3,l=4;let h=o;function u(){let[t,e]=(new Date).toJSON().split("T");return t=t.replaceAll("-","/"),e=e.split(".")[0],`[${t} - ${e}]`}function p(t){h=t}function d(...t){h>i||console.debug(u()+" debug:",...t)}function f(...t){h>o||console.info(u()+" info:",...t)}function w(...t){h>o||console.log(u()+" log:",...t)}function _(...t){h>a||console.warn(u()+" warn:",...t)}function y(...t){h>c||console.error(u()+" error:",...t)}const m=new TextEncoder,v=m.encode.bind(m),g=new TextDecoder,k=g.decode.bind(g);class I{constructor(t){if(t instanceof Uint8Array)this.from_array(t);else if("number"==typeof t)this.from_array(new Uint8Array(t));else{if("string"!=typeof t)throw console.trace(),"invalid data type passed to wisp buffer constructor";this.from_array(v(t))}}from_array(t){this.size=t.length,this.bytes=t,this.view=new DataView(t.buffer)}concat(t){let e=new I(this.size+t.size);return e.bytes.set(this.bytes,0),e.bytes.set(t.bytes,this.size),e}slice(t,e){let s=this.bytes.slice(t,e);return new I(s)}}class b{static min_size=5;constructor({type:t,stream_id:e,payload:s,payload_bytes:r}){this.type=t,this.stream_id=e,this.payload_bytes=r,this.payload=s}static parse(t){return new b({type:t.view.getUint8(0),stream_id:t.view.getUint32(1,!0),payload_bytes:t.slice(5)})}static parse_all(t){if(t.size<b.min_size)throw"packet too small";let e=b.parse(t),s=R[e.type];if(void 0===s)throw"invalid packet type";if(e.payload_bytes.size<s.size)throw"payload too small";return e.payload=s.parse(e.payload_bytes),e}serialize(){let t=new I(5);return t.view.setUint8(0,this.type),t.view.setUint32(1,this.stream_id,!0),t=t.concat(this.payload.serialize()),t}}class P{static min_size=3;static type=1;static name="CONNECT";constructor({stream_type:t,port:e,hostname:s}){this.stream_type=t,this.port=e,this.hostname=s}static parse(t){return new P({stream_type:t.view.getUint8(0),port:t.view.getUint16(1,!0),hostname:k(t.slice(3).bytes)})}serialize(){let t=new I(3);return t.view.setUint8(0,this.stream_type),t.view.setUint16(1,this.port,!0),t=t.concat(new I(this.hostname)),t}}class ${static min_size=0;static type=2;static name="DATA";constructor({data:t}){this.data=t}static parse(t){return new $({data:t})}serialize(){return this.data}}class z{static type=3;static name="CONTINUE";constructor({buffer_remaining:t}){this.buffer_remaining=t}static parse(t){return new z({buffer_remaining:t.view.getUint32(0,!0)})}serialize(){let t=new I(4);return t.view.setUint32(0,this.buffer_remaining,!0),t}}class C{static min_size=1;static type=4;static name="CLOSE";constructor({reason:t}){this.reason=t}static parse(t){return new C({reason:t.view.getUint8(0)})}serialize(){let t=new I(1);return t.view.setUint8(0,this.buffer_remaining),t}}const R=[void 0,P,$,z,C],E={CONNECT:1,DATA:2,CONTINUE:3,CLOSE:4},x={TCP:1,UDP:2},D={Unknown:1,Voluntary:2,NetworkError:3,InvalidInfo:65,UnreachableHost:66,NoResponse:67,ConnRefused:68,TransferTimeout:71,HostBlocked:72,ConnThrottled:73,ClientError:129},S={hostname_blacklist:null,hostname_whitelist:null,port_blacklist:null,port_whitelist:null,allow_direct_ip:!0,allow_private_ips:!1,allow_loopback_ips:!1,client_ip_blacklist:null,client_ip_whitelist:null,stream_limit_per_host:-1,stream_limit_total:-1,allow_udp_streams:!0,allow_tcp_streams:!0,dns_ttl:120},A=globalThis.WebSocket,O=globalThis.crypto,T=null,U=null,N=null;class M{send_buffer_size=33554432;constructor(t){this.ws=t,this.connected=!1,this.data_queue=new q(1)}async connect(){await new Promise(((t,e)=>{this.ws.onopen=()=>{this.connected=!0,t()},this.ws.onmessage=t=>{this.data_queue.put(t.data)},this.ws.onclose=()=>{this.connected?this.data_queue.close():e()},this.ws.readyState===this.ws.OPEN&&(this.connected=!0,t())}))}async recv(){return await this.data_queue.get()}async send(t){if(this.ws.send(t),!(this.ws.bufferedAmount<=this.send_buffer_size))for(;!(this.ws.bufferedAmount<=this.send_buffer_size/2);)await new Promise((t=>{setTimeout(t,10)}))}close(t,e){this.ws.close(t,e),this.data_queue.close()}get buffered_amount(){return this.ws.bufferedAmount}}class q{constructor(t){this.max_size=t,this.queue=[],this.put_callbacks=[],this.get_callbacks=[]}put_now(t){this.queue.push(t),this.get_callbacks.shift()?.()}async put(t){this.size<=this.max_size||await new Promise((t=>{this.put_callbacks.push(t)})),this.put_now(t)}get_now(){return this.put_callbacks.shift()?.(),this.queue.shift()}async get(){return this.size>0||await new Promise((t=>{this.get_callbacks.push(t)})),this.get_now()}close(){let t;for(this.queue=[];t=this.get_callbacks.shift();)t();for(;t=this.put_callbacks.shift();)t()}get size(){return this.queue.length}}const B="undefined"!=typeof process,V=new Map;function F(){if(!B)throw"not running on node.js"}async function j(t){if(!B)return t;let e=T.isIP(t);if(4===e||6===e)return t;let s=Date.now();for(let[t,e]of V)s-e.time>S.dns_ttl&&V.delete(t);let r,n=V.get(t);if(n){if(n.error)throw n.error;return n.address}try{r=(await U.lookup(t)).address,V.set(t,{time:Date.now(),address:r})}catch(e){throw V.set(t,{time:Date.now(),error:e}),e}return r}class L{constructor(t,e){F(),this.hostname=t,this.port=e,this.recv_buffer_size=128,this.socket=null,this.paused=!1,this.connected=!1,this.data_queue=new q(this.recv_buffer_size)}async connect(){let t=await j(this.hostname);await new Promise(((e,s)=>{this.socket=new T.Socket,this.socket.setNoDelay(!0),this.socket.on("connect",(()=>{this.connected=!0,e()})),this.socket.on("data",(t=>{this.data_queue.put(t)})),this.socket.on("close",(t=>{t&&!this.connected?s():this.data_queue.close(),this.socket=null})),this.socket.on("error",(t=>{_(`tcp stream to ${this.hostname} ended with error - ${t}`)})),this.socket.on("end",(()=>{this.socket&&(this.socket.destroy(),this.socket=null)})),this.socket.connect({host:t,port:this.port})}))}async recv(){return await this.data_queue.get()}async send(t){await new Promise((e=>{this.socket.write(t,e)}))}async close(){this.socket&&(this.socket.end(),this.socket=null)}pause(){this.data_queue.size>=this.data_queue.max_size&&(this.socket.pause(),this.paused=!0)}resume(){this.socket&&this.paused&&(this.socket.resume(),this.paused=!1)}}class H{constructor(t,e){F(),this.hostname=t,this.port=e,this.connected=!1,this.recv_buffer_size=128,this.data_queue=new q(this.recv_buffer_size)}async connect(){let t=await j(this.hostname),e=T.isIP(t);await new Promise(((s,r)=>{this.socket=null.createSocket(6===e?"udp6":"udp4"),this.socket.on("connect",(()=>{s()})),this.socket.on("message",(t=>{this.data_queue.put(t)})),this.socket.on("error",(()=>{this.connected||r(),this.data_queue.close(),this.socket=null})),this.socket.connect(this.port,t)}))}async recv(){return await this.data_queue.get()}async send(t){this.socket.send(t)}async close(){this.socket&&(this.socket.close(),this.socket=null)}pause(){}resume(){}}var W=s(512);class G extends Error{}function J(t,e){return t===e||t[0]<=e&&t[1]>=e}function K(t,e){let s=!1;for(let r of t)if(e(r)){s=!0;break}return!s}function Q(t,e){for(let s of t)if(e(s))return!0;return!1}function X(t,e){return e.includes(t.range())}async function Y(t,e,s,r){if(!S.allow_tcp_streams&&e===x.TCP)return D.HostBlocked;if(!S.allow_udp_streams&&e===x.UDP)return D.HostBlocked;if(S.hostname_whitelist){if(K(S.hostname_whitelist,(t=>t.test(s))))return D.HostBlocked}else if(S.hostname_blacklist&&Q(S.hostname_blacklist,(t=>t.test(s))))return D.HostBlocked;if(S.port_whitelist){if(K(S.port_whitelist,(t=>J(t,r))))return D.HostBlocked}else if(S.port_blacklist&&Q(S.port_blacklist,(t=>J(t,r))))return D.HostBlocked;let n=s;if(W.isValid(s)){if(!S.allow_direct_ip)return D.HostBlocked}else try{n=await j(s)}catch{}if(function(t){if(!W.isValid(t))return!1;let e=W.parse(t);return!(S.allow_loopback_ips||!X(e,["loopback","unspecified"]))||!(S.allow_private_ips||!X(e,["broadcast","linkLocal","carrierGradeNat","private","reserved"]))}(n))return D.HostBlocked;if(!t)return 0;if(-1!==S.stream_limit_total&&Object.keys(t.streams).length>=S.stream_limit_total)return D.ConnThrottled;if(-1!==S.stream_limit_per_host){let e=0;for(let r of t.streams)r.socket.hostname===s&&e++;if(e>=S.stream_limit_per_host)return D.ConnThrottled}return 0}class Z{static buffer_size=128;constructor(t,e,s){this.stream_id=t,this.conn=e,this.socket=s,this.send_buffer=new q(Z.buffer_size),this.packets_sent=0}async setup(){await this.socket.connect(),this.tcp_to_ws().catch((t=>{y(`(${this.conn.conn_id}) a tcp/udp to ws task encountered an error - ${t}`),this.close()})),this.ws_to_tcp().catch((t=>{y(`(${this.conn.conn_id}) a ws to tcp/udp task encountered an error - ${t}`),this.close()}))}async tcp_to_ws(){for(;;){let t=await this.socket.recv();if(null==t)break;this.socket.pause();let e=new b({type:$.type,stream_id:this.stream_id,payload:new $({data:new I(new Uint8Array(t))})});await this.conn.ws.send(e.serialize().bytes),this.socket.resume()}await this.conn.close_stream(this.stream_id,D.Voluntary)}async ws_to_tcp(){for(;;){let t=await this.send_buffer.get();if(null==t)break;if(await this.socket.send(t),this.packets_sent++,this.packets_sent%(Z.buffer_size/2)!=0)continue;let e=new b({type:z.type,stream_id:this.stream_id,payload:new z({buffer_remaining:Z.buffer_size-this.send_buffer.size})});this.conn.ws.send(e.serialize().bytes)}await this.close()}async close(t=null){if(this.send_buffer.close(),this.socket.close(),null==t)return;let e=new b({type:C.type,stream_id:this.stream_id,payload:new C({reason:t})});await this.conn.ws.send(e.serialize().bytes)}async put_data(t){await this.send_buffer.put(t)}}class tt{constructor(t,e,{TCPSocket:s,UDPSocket:r,ping_interval:n}={}){this.ws=new M(t),this.path=e,this.TCPSocket=s||L,this.UDPSocket=r||H,this.ping_interval=n||30,this.ping_task=null,this.streams={},this.conn_id=O.randomUUID().split("-")[0]}async setup(){f(`setting up new wisp connection with id ${this.conn_id}`),await this.ws.connect();let t=new b({type:z.type,stream_id:0,payload:new z({buffer_remaining:Z.buffer_size})});await this.ws.send(t.serialize().bytes),"function"==typeof this.ws.ws.ping&&(this.ping_task=setInterval((()=>{d(`(${this.conn_id}) sending websocket ping`),this.ws.ws.ping()}),1e3*this.ping_interval))}create_stream(t,e,s,r){let n=new(e===x.TCP?this.TCPSocket:this.UDPSocket)(s,r),i=new Z(t,this,n);this.streams[t]=i,(async()=>{let n=await Y(this,e,s,r);if(n)return _(`(${this.conn_id}) refusing to create a stream to ${s}:${r}`),void await this.close_stream(t,n,!0);try{await i.setup()}catch(e){_(`(${this.conn_id}) creating a stream to ${s}:${r} failed - ${e}`),await this.close_stream(t,D.NetworkError)}})()}async close_stream(t,e=null,s=!1){let r=this.streams[t];null!=r&&(e&&!s&&f(`(${this.conn_id}) closing stream to ${r.socket.hostname} for reason ${e}`),await r.close(e),delete this.streams[t])}route_packet(t){let e=b.parse_all(t),s=this.streams[e.stream_id];if(null!=s||e.type!=$.type)if(e.type===P.type){let t=e.payload.stream_type===x.TCP?"TCP":"UDP";f(`(${this.conn_id}) opening new ${t} stream to ${e.payload.hostname}:${e.payload.port}`),this.create_stream(e.stream_id,e.payload.stream_type,e.payload.hostname.trim(),e.payload.port)}else e.type===$.type?s.put_data(e.payload.data.bytes):e.type==z.type?_(`(${this.conn_id}) client sent a CONTINUE packet, this should never be possible`):e.type==C.type&&this.close_stream(e.stream_id,e.reason);else _(`(${this.conn_id}) received a DATA packet for a stream which doesn't exist`)}async run(){for(;;){let t;if(t=await this.ws.recv(),null==t)break;try{this.route_packet(new I(new Uint8Array(t)))}catch(t){_(`(${this.conn_id}) routing a packet failed - ${t}`)}}for(let t of Object.keys(this.streams))await this.close_stream(t);clearInterval(this.ping_task),f(`(${this.conn_id}) wisp connection closed`)}}class et{constructor(t,e){let[s,r]=e.split("/").pop().split(":");this.hostname=s.trim(),this.port=parseInt(r),this.ws=new M(t)}async setup(){if(await this.ws.connect(),0!==await Y(null,x.TCP,this.hostname,this.port))throw f(`Refusing to create a wsproxy connection to ${this.hostname}:${this.port}`),this.ws.close(),new G;this.socket=new L(this.hostname,this.port),await this.socket.connect(),this.tcp_to_ws().catch((t=>{y(`a tcp to ws task (wsproxy) encountered an error - ${t}`)})),this.ws_to_tcp().catch((t=>{y(`a ws to tcp task (wsproxy) encountered an error - ${t}`)}))}async tcp_to_ws(){for(;;){let t=await this.socket.recv();if(null==t)break;this.socket.pause(),await this.ws.send(t),this.socket.resume()}await this.ws.close()}async ws_to_tcp(){for(;;){let t;if(t=await this.ws.recv(),null==t)break;await this.socket.send(t)}await this.socket.close()}}let st=null;function rt(t,e,s,r={}){F(),t instanceof N.IncomingMessage?st.handleUpgrade(t,e,s,(e=>{nt(e,t.url,t,r)})):t instanceof A&&nt(ws,"/",{})}async function nt(t,e,s,r){f(`new connection on ${e} from ${s.socket.address().address}`);try{if(e.endsWith("/")){let s=new tt(t,e,r);await s.setup(),await s.run()}else{let s=new et(t,e,r);await s.setup()}}catch(e){if(t.close(),e instanceof G)return;y("Uncaught server error:\n"+e.stack)}}B&&(st=new null({noServer:!0}))})(),wisp_server=r})(); |
{ | ||
"name": "@mercuryworkshop/wisp-js", | ||
"version": "0.2.1", | ||
"version": "0.2.2", | ||
"description": "A client and server for the Wisp protocol, written in Javascript", | ||
@@ -52,2 +52,3 @@ "repository": { | ||
"commander": "^12.1.0", | ||
"ipaddr.js": "^2.2.0", | ||
"ws": "^8.17.1" | ||
@@ -54,0 +55,0 @@ }, |
@@ -187,2 +187,5 @@ # JavaScript Wisp Implementation | ||
- `options.allow_tcp_streams` - If this is `false`, TCP streams will be blocked. Defaults to `true`. | ||
- `options.allow_direct_ip` - Allow connections directly to IP addresses, which bypasses the server-side DNS resolution. Turning this off allows the server administrator to enforce a block list more effectively. Defaults to `true`. | ||
- `options.allow_private_ips` - Allow connections to private IP addresses. Defaults to `false`. | ||
- `options.allow_loopback_ips` - Allow connections to the server's localhost (127.0.0.1) and other loopback IPs. Defaults to `false`. | ||
@@ -189,0 +192,0 @@ For example: |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
285844
1326
224
4
+ Addedipaddr.js@^2.2.0
+ Addedipaddr.js@2.2.0(transitive)