tunli 0.0.21 → 0.0.22

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tunli",
3
3
  "description": "Node.js application for creating HTTP tunnels to make local software projects accessible over the internet.",
4
- "version": "0.0.21",
4
+ "version": "0.0.22",
5
5
  "main": "bin/tunli",
6
6
  "bin": {
7
7
  "tunli": "bin/tunli"
@@ -10,6 +10,7 @@ import {renewProxyUrlRegistration, requestNewProxyUrl} from "#lib/Flow/proxyUrl"
10
10
  import {getCurrentIp} from "#lib/Flow/getCurrentIp";
11
11
  import {arrayUnique} from "#src/utils/arrayFunctions";
12
12
  import {initDashboard} from "#src/cli-app/Dashboard";
13
+ import {proxy} from "#lib/Proxy";
13
14
 
14
15
  /**
15
16
  * @callback httpCommandExec
@@ -94,9 +95,15 @@ const exec = (configRef, cmd, program) => {
94
95
  protocol: options.protocol
95
96
  }
96
97
 
98
+ const useDashboard = process.env.DASHBOARD !== 'off'
99
+
97
100
  const client = new TunnelClient(clientOptions)
98
- const dashboard = initDashboard(client, clientOptions, config)
101
+ const dashboard = useDashboard ? initDashboard(client, clientOptions, config) : null
99
102
  await client.init(dashboard)
103
+
104
+ if (!useDashboard) {
105
+ console.log(clientOptions)
106
+ }
100
107
  }
101
108
  }
102
109
  /**
@@ -0,0 +1,42 @@
1
+ import {ConfigManager} from "#src/config/ConfigManager";
2
+ import {TunnelClient} from "#src/tunnel-client/TunnelClient";
3
+ import {renewProxyUrlRegistration} from "#lib/Flow/proxyUrl";
4
+
5
+ const prepareOptions = async (options) => {
6
+
7
+ options ??= {}
8
+ const localConf = ConfigManager.loadLocalOnly()
9
+ const globalConf = ConfigManager.loadGlobalOnly()
10
+
11
+ const authToken = globalConf.authToken
12
+
13
+ let preparedOptions = {authToken, ...localConf.dump(), ...options}
14
+
15
+ preparedOptions.server = await renewProxyUrlRegistration(preparedOptions.proxyURL, preparedOptions.authToken)
16
+ preparedOptions.denyCidr ??= []
17
+ preparedOptions.allowCidr ??= []
18
+
19
+ console.log(preparedOptions)
20
+
21
+ return preparedOptions
22
+ }
23
+
24
+ /**
25
+ *
26
+ * @param {tunliProxyOptions} options
27
+ */
28
+ export const proxy = async (options) => {
29
+
30
+ options = await prepareOptions(options)
31
+ const client = new TunnelClient(options)
32
+
33
+ await client.init()
34
+ console.log('INIT')
35
+ return options
36
+ }
37
+
38
+ const tunli = {
39
+ proxy
40
+ }
41
+
42
+ export default tunli
@@ -109,11 +109,15 @@ export const forwardTunnelRequestToProxyTarget = (req, eventEmitter, options) =>
109
109
  setupErrorHandlers(tunnelRequest, localReq)
110
110
 
111
111
  const onLocalResponse = (localRes) => {
112
+
112
113
  localReq.off('error', onLocalError)
114
+
113
115
  if (isWebSocket && localRes.upgrade) {
114
116
  return
115
117
  }
116
118
 
119
+ if (!isWebSocket) rewriteResponse(localRes, options)
120
+
117
121
  const tunnelResponse = new TunnelResponse({
118
122
  responseId: req.requestId,
119
123
  socket: req.tunnelSocket,
@@ -175,3 +179,51 @@ export const forwardTunnelRequestToProxyTarget = (req, eventEmitter, options) =>
175
179
  localReq.on('upgrade', onUpgrade)
176
180
  }
177
181
  }
182
+
183
+
184
+ /**
185
+ * @param {Response<IncomingMessage>} localRes
186
+ * @param {tunnelClientOptions} options
187
+ */
188
+ const rewriteResponse = (localRes, options) => {
189
+
190
+ options.proxyURL ??= options.server
191
+
192
+ const hostSearch = options.origin ?? options.host
193
+ const {protocol: protocolReplace, hostname: hostReplace} = new URL(options.proxyURL)
194
+ const baseURL = new URL(`${options.protocol}://${hostSearch}:${options.port}`).toString()
195
+
196
+ if (localRes.statusCode === 301) {
197
+ delete localRes.headers.location
198
+ }
199
+
200
+ let location = localRes.headers.location
201
+ let setCookie = localRes.headers['set-cookie']
202
+
203
+ if (!setCookie || !Array.isArray(setCookie)) {
204
+ setCookie = null
205
+ }
206
+
207
+ if (location) {
208
+ location = new URL(location, baseURL).toString()
209
+ }
210
+
211
+ if (location && location.charAt(0) !== '/' && location.startsWith(baseURL)) {
212
+ localRes.headers.location = location.replace(baseURL, options.proxyURL)
213
+ }
214
+
215
+ if (setCookie) {
216
+ localRes.headers['set-cookie'] = setCookie.map(cookie => {
217
+ return updateCookieDomain(cookie, hostReplace) // TODO MOVE THIS PART TO SERVER
218
+ })
219
+ }
220
+ }
221
+
222
+ function extractDomainFromCookieString(cookie) {
223
+ const domainMatch = cookie.match(/Domain=([^;]+)/);
224
+ return domainMatch ? domainMatch[1] : null;
225
+ }
226
+
227
+ function updateCookieDomain(cookie, newDomain) {
228
+ return cookie.replace(/Domain=[^;]+/, `Domain=${newDomain}`);
229
+ }
@@ -94,6 +94,10 @@ export class TunnelClient extends EventEmitter {
94
94
  setInterval(ping, 5000)
95
95
  }
96
96
 
97
+ /**
98
+ * @param [dashboard]
99
+ * @return {Promise<TunnelClient>}
100
+ */
97
101
  async init(dashboard) {
98
102
 
99
103
  const params = await this.#createParameters(dashboard)
@@ -108,7 +112,7 @@ export class TunnelClient extends EventEmitter {
108
112
  const webSocketCapturePath = await securedHttpClient(options.authToken).get('/capture_path')
109
113
 
110
114
  if (webSocketCapturePath.error) {
111
- dashboard.destroy()
115
+ dashboard?.destroy()
112
116
  if (webSocketCapturePath.error?.message === 'Request failed with status code 401') {
113
117
  console.error('missing authorization, check your registration and try again')
114
118
  } else {
package/types/index.d.ts CHANGED
@@ -111,3 +111,8 @@ export type keypressEventDetails = {
111
111
  export interface keypressEventListener {
112
112
  (char: string, details: keypressEventDetails): void
113
113
  }
114
+
115
+
116
+ export type tunliProxyOptions = {
117
+
118
+ }