pinggy 0.4.4 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-HUN2MRZO.js → chunk-3RTRUYNW.js} +3 -1
- package/dist/{chunk-MBN3YBO4.js → chunk-STEISST3.js} +203 -41
- package/dist/index.cjs +357 -103
- package/dist/index.d.cts +20 -11
- package/dist/index.d.ts +20 -11
- package/dist/index.js +10 -7
- package/dist/{main-PFPDXIRG.js → main-XKFFUSKJ.js} +148 -59
- package/dist/workers/file_serve_worker.js +1 -1
- package/package.json +3 -2
package/dist/index.d.cts
CHANGED
|
@@ -589,15 +589,15 @@ interface TunnelResponseV2 {
|
|
|
589
589
|
greetmsg?: string;
|
|
590
590
|
}
|
|
591
591
|
interface TunnelHandler {
|
|
592
|
-
handleStart(config: TunnelConfig): Promise<TunnelResponse | ErrorResponse>;
|
|
593
|
-
handleStartV2(config: TunnelConfigV1): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
594
|
-
handleUpdateConfig(config: TunnelConfig): Promise<TunnelResponse | ErrorResponse>;
|
|
595
|
-
handleUpdateConfigV2(config: TunnelConfigV1): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
592
|
+
handleStart(config: TunnelConfig, noWait?: boolean): Promise<TunnelResponse | ErrorResponse>;
|
|
593
|
+
handleStartV2(config: TunnelConfigV1, noWait?: boolean): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
594
|
+
handleUpdateConfig(config: TunnelConfig, noWait?: boolean): Promise<TunnelResponse | ErrorResponse>;
|
|
595
|
+
handleUpdateConfigV2(config: TunnelConfigV1, noWait?: boolean): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
596
596
|
handleList(): Promise<TunnelResponse[] | ErrorResponse>;
|
|
597
597
|
handleListV2(): Promise<TunnelResponseV2[] | ErrorResponse>;
|
|
598
598
|
handleStop(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
|
|
599
599
|
handleGet(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
|
|
600
|
-
handleRestart(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
|
|
600
|
+
handleRestart(tunnelid: string, noWait?: boolean): Promise<TunnelResponse | ErrorResponse>;
|
|
601
601
|
handleRegisterStatsListener(tunnelid: string, listener: (tunnelId: string, stats: TunnelUsageType) => void): void;
|
|
602
602
|
handleUnregisterStatsListener(tunnelid: string, listnerId: string): void;
|
|
603
603
|
handleGetTunnelStats(tunnelid: string): TunnelUsageType[] | ErrorResponse;
|
|
@@ -609,18 +609,20 @@ declare class TunnelOperations implements TunnelHandler {
|
|
|
609
609
|
private tunnelManager;
|
|
610
610
|
constructor();
|
|
611
611
|
private buildStatus;
|
|
612
|
+
private buildPendingTunnelResponse;
|
|
613
|
+
private buildPendingTunnelResponseV2;
|
|
612
614
|
private buildTunnelResponse;
|
|
613
615
|
private buildTunnelResponseV2;
|
|
614
616
|
private error;
|
|
615
|
-
handleStart(config: TunnelConfig): Promise<TunnelResponse | ErrorResponse>;
|
|
616
|
-
handleStartV2(config: TunnelConfigV1): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
617
|
-
handleUpdateConfig(config: TunnelConfig): Promise<TunnelResponse | ErrorResponse>;
|
|
618
|
-
handleUpdateConfigV2(config: TunnelConfigV1): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
617
|
+
handleStart(config: TunnelConfig, noWait?: boolean): Promise<TunnelResponse | ErrorResponse>;
|
|
618
|
+
handleStartV2(config: TunnelConfigV1, noWait?: boolean): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
619
|
+
handleUpdateConfig(config: TunnelConfig, noWait?: boolean): Promise<TunnelResponse | ErrorResponse>;
|
|
620
|
+
handleUpdateConfigV2(config: TunnelConfigV1, noWait?: boolean): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
619
621
|
handleListV2(): Promise<TunnelResponseV2[] | ErrorResponse>;
|
|
620
622
|
handleList(): Promise<TunnelResponse[] | ErrorResponse>;
|
|
621
623
|
handleStop(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
|
|
622
624
|
handleGet(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
|
|
623
|
-
handleRestart(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
|
|
625
|
+
handleRestart(tunnelid: string, noWait?: boolean): Promise<TunnelResponse | ErrorResponse>;
|
|
624
626
|
handleRegisterStatsListener(tunnelid: string, listener: (tunnelId: string, stats: TunnelUsageType) => void): void;
|
|
625
627
|
handleUnregisterStatsListener(tunnelid: string, listnerId: string): void;
|
|
626
628
|
handleGetTunnelStats(tunnelid: string): TunnelUsageType[] | ErrorResponse;
|
|
@@ -640,6 +642,9 @@ interface BaseLogConfig {
|
|
|
640
642
|
type BaseLogConfigType = BaseLogConfig;
|
|
641
643
|
declare function enablePackageLogging(opts?: BaseLogConfigType): winston.Logger;
|
|
642
644
|
|
|
645
|
+
declare class RemoteManagementUnauthorizedError extends Error {
|
|
646
|
+
constructor();
|
|
647
|
+
}
|
|
643
648
|
/**
|
|
644
649
|
* Initiate remote management mode with a WebSocket connection.
|
|
645
650
|
* - Connect with Authorization: Bearer <token>
|
|
@@ -649,6 +654,10 @@ declare function enablePackageLogging(opts?: BaseLogConfigType): winston.Logger;
|
|
|
649
654
|
*/
|
|
650
655
|
declare function initiateRemoteManagement(remoteManagementConfig: RemoteManagementConfig): Promise<RemoteManagementState>;
|
|
651
656
|
declare function closeRemoteManagement(timeoutMs?: number): Promise<RemoteManagementState>;
|
|
657
|
+
/**
|
|
658
|
+
* Start remote management loop in background; returns after first connection attempt.
|
|
659
|
+
*/
|
|
660
|
+
declare function startRemoteManagement(remoteManagementConfig: RemoteManagementConfig): Promise<RemoteManagementState>;
|
|
652
661
|
declare function getRemoteManagementState(): RemoteManagementState;
|
|
653
662
|
|
|
654
|
-
export { type AdditionalForwarding, type DisconnectListener, type ErrorListener, type FinalConfig, type ITunnelManager, type ManagedTunnel, type ReconnectingListener, type ReconnectionCompletedListener, type ReconnectionFailedListener, type StartListener, type StatsListener, type Status, TunnelErrorCodeType, type TunnelList, TunnelManager, TunnelOperations, type TunnelResponse, TunnelStateType, type TunnelStatus, TunnelWarningCode, type TunnelWorkerErrorListner, type Warning, type WillReconnectListener, closeRemoteManagement, enablePackageLogging, getRemoteManagementState, initiateRemoteManagement };
|
|
663
|
+
export { type AdditionalForwarding, type DisconnectListener, type ErrorListener, type FinalConfig, type ITunnelManager, type ManagedTunnel, type ReconnectingListener, type ReconnectionCompletedListener, type ReconnectionFailedListener, RemoteManagementUnauthorizedError, type StartListener, type StatsListener, type Status, TunnelErrorCodeType, type TunnelList, TunnelManager, TunnelOperations, type TunnelResponse, TunnelStateType, type TunnelStatus, TunnelWarningCode, type TunnelWorkerErrorListner, type Warning, type WillReconnectListener, closeRemoteManagement, enablePackageLogging, getRemoteManagementState, initiateRemoteManagement, startRemoteManagement };
|
package/dist/index.d.ts
CHANGED
|
@@ -589,15 +589,15 @@ interface TunnelResponseV2 {
|
|
|
589
589
|
greetmsg?: string;
|
|
590
590
|
}
|
|
591
591
|
interface TunnelHandler {
|
|
592
|
-
handleStart(config: TunnelConfig): Promise<TunnelResponse | ErrorResponse>;
|
|
593
|
-
handleStartV2(config: TunnelConfigV1): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
594
|
-
handleUpdateConfig(config: TunnelConfig): Promise<TunnelResponse | ErrorResponse>;
|
|
595
|
-
handleUpdateConfigV2(config: TunnelConfigV1): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
592
|
+
handleStart(config: TunnelConfig, noWait?: boolean): Promise<TunnelResponse | ErrorResponse>;
|
|
593
|
+
handleStartV2(config: TunnelConfigV1, noWait?: boolean): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
594
|
+
handleUpdateConfig(config: TunnelConfig, noWait?: boolean): Promise<TunnelResponse | ErrorResponse>;
|
|
595
|
+
handleUpdateConfigV2(config: TunnelConfigV1, noWait?: boolean): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
596
596
|
handleList(): Promise<TunnelResponse[] | ErrorResponse>;
|
|
597
597
|
handleListV2(): Promise<TunnelResponseV2[] | ErrorResponse>;
|
|
598
598
|
handleStop(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
|
|
599
599
|
handleGet(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
|
|
600
|
-
handleRestart(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
|
|
600
|
+
handleRestart(tunnelid: string, noWait?: boolean): Promise<TunnelResponse | ErrorResponse>;
|
|
601
601
|
handleRegisterStatsListener(tunnelid: string, listener: (tunnelId: string, stats: TunnelUsageType) => void): void;
|
|
602
602
|
handleUnregisterStatsListener(tunnelid: string, listnerId: string): void;
|
|
603
603
|
handleGetTunnelStats(tunnelid: string): TunnelUsageType[] | ErrorResponse;
|
|
@@ -609,18 +609,20 @@ declare class TunnelOperations implements TunnelHandler {
|
|
|
609
609
|
private tunnelManager;
|
|
610
610
|
constructor();
|
|
611
611
|
private buildStatus;
|
|
612
|
+
private buildPendingTunnelResponse;
|
|
613
|
+
private buildPendingTunnelResponseV2;
|
|
612
614
|
private buildTunnelResponse;
|
|
613
615
|
private buildTunnelResponseV2;
|
|
614
616
|
private error;
|
|
615
|
-
handleStart(config: TunnelConfig): Promise<TunnelResponse | ErrorResponse>;
|
|
616
|
-
handleStartV2(config: TunnelConfigV1): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
617
|
-
handleUpdateConfig(config: TunnelConfig): Promise<TunnelResponse | ErrorResponse>;
|
|
618
|
-
handleUpdateConfigV2(config: TunnelConfigV1): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
617
|
+
handleStart(config: TunnelConfig, noWait?: boolean): Promise<TunnelResponse | ErrorResponse>;
|
|
618
|
+
handleStartV2(config: TunnelConfigV1, noWait?: boolean): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
619
|
+
handleUpdateConfig(config: TunnelConfig, noWait?: boolean): Promise<TunnelResponse | ErrorResponse>;
|
|
620
|
+
handleUpdateConfigV2(config: TunnelConfigV1, noWait?: boolean): Promise<TunnelResponseV2 | ErrorResponse>;
|
|
619
621
|
handleListV2(): Promise<TunnelResponseV2[] | ErrorResponse>;
|
|
620
622
|
handleList(): Promise<TunnelResponse[] | ErrorResponse>;
|
|
621
623
|
handleStop(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
|
|
622
624
|
handleGet(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
|
|
623
|
-
handleRestart(tunnelid: string): Promise<TunnelResponse | ErrorResponse>;
|
|
625
|
+
handleRestart(tunnelid: string, noWait?: boolean): Promise<TunnelResponse | ErrorResponse>;
|
|
624
626
|
handleRegisterStatsListener(tunnelid: string, listener: (tunnelId: string, stats: TunnelUsageType) => void): void;
|
|
625
627
|
handleUnregisterStatsListener(tunnelid: string, listnerId: string): void;
|
|
626
628
|
handleGetTunnelStats(tunnelid: string): TunnelUsageType[] | ErrorResponse;
|
|
@@ -640,6 +642,9 @@ interface BaseLogConfig {
|
|
|
640
642
|
type BaseLogConfigType = BaseLogConfig;
|
|
641
643
|
declare function enablePackageLogging(opts?: BaseLogConfigType): winston.Logger;
|
|
642
644
|
|
|
645
|
+
declare class RemoteManagementUnauthorizedError extends Error {
|
|
646
|
+
constructor();
|
|
647
|
+
}
|
|
643
648
|
/**
|
|
644
649
|
* Initiate remote management mode with a WebSocket connection.
|
|
645
650
|
* - Connect with Authorization: Bearer <token>
|
|
@@ -649,6 +654,10 @@ declare function enablePackageLogging(opts?: BaseLogConfigType): winston.Logger;
|
|
|
649
654
|
*/
|
|
650
655
|
declare function initiateRemoteManagement(remoteManagementConfig: RemoteManagementConfig): Promise<RemoteManagementState>;
|
|
651
656
|
declare function closeRemoteManagement(timeoutMs?: number): Promise<RemoteManagementState>;
|
|
657
|
+
/**
|
|
658
|
+
* Start remote management loop in background; returns after first connection attempt.
|
|
659
|
+
*/
|
|
660
|
+
declare function startRemoteManagement(remoteManagementConfig: RemoteManagementConfig): Promise<RemoteManagementState>;
|
|
652
661
|
declare function getRemoteManagementState(): RemoteManagementState;
|
|
653
662
|
|
|
654
|
-
export { type AdditionalForwarding, type DisconnectListener, type ErrorListener, type FinalConfig, type ITunnelManager, type ManagedTunnel, type ReconnectingListener, type ReconnectionCompletedListener, type ReconnectionFailedListener, type StartListener, type StatsListener, type Status, TunnelErrorCodeType, type TunnelList, TunnelManager, TunnelOperations, type TunnelResponse, TunnelStateType, type TunnelStatus, TunnelWarningCode, type TunnelWorkerErrorListner, type Warning, type WillReconnectListener, closeRemoteManagement, enablePackageLogging, getRemoteManagementState, initiateRemoteManagement };
|
|
663
|
+
export { type AdditionalForwarding, type DisconnectListener, type ErrorListener, type FinalConfig, type ITunnelManager, type ManagedTunnel, type ReconnectingListener, type ReconnectionCompletedListener, type ReconnectionFailedListener, RemoteManagementUnauthorizedError, type StartListener, type StatsListener, type Status, TunnelErrorCodeType, type TunnelList, TunnelManager, TunnelOperations, type TunnelResponse, TunnelStateType, type TunnelStatus, TunnelWarningCode, type TunnelWorkerErrorListner, type Warning, type WillReconnectListener, closeRemoteManagement, enablePackageLogging, getRemoteManagementState, initiateRemoteManagement, startRemoteManagement };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
RemoteManagementUnauthorizedError,
|
|
3
4
|
TunnelErrorCodeType,
|
|
4
5
|
TunnelManager,
|
|
5
6
|
TunnelOperations,
|
|
@@ -8,11 +9,12 @@ import {
|
|
|
8
9
|
closeRemoteManagement,
|
|
9
10
|
getRemoteManagementState,
|
|
10
11
|
initiateRemoteManagement,
|
|
11
|
-
printer_default
|
|
12
|
-
|
|
12
|
+
printer_default,
|
|
13
|
+
startRemoteManagement
|
|
14
|
+
} from "./chunk-STEISST3.js";
|
|
13
15
|
import {
|
|
14
16
|
enablePackageLogging
|
|
15
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-3RTRUYNW.js";
|
|
16
18
|
|
|
17
19
|
// src/utils/detect_vc_redist_on_windows.ts
|
|
18
20
|
import fs from "fs";
|
|
@@ -104,13 +106,13 @@ async function verifyAndLoad() {
|
|
|
104
106
|
process.exit(1);
|
|
105
107
|
}
|
|
106
108
|
}
|
|
107
|
-
await import("./main-
|
|
109
|
+
await import("./main-XKFFUSKJ.js");
|
|
108
110
|
}
|
|
109
111
|
verifyAndLoad().catch((err) => {
|
|
110
|
-
printer_default.
|
|
111
|
-
process.exit(1);
|
|
112
|
+
printer_default.fatal(`Failed to start CLI:, ${err}`);
|
|
112
113
|
});
|
|
113
114
|
export {
|
|
115
|
+
RemoteManagementUnauthorizedError,
|
|
114
116
|
TunnelErrorCodeType,
|
|
115
117
|
TunnelManager,
|
|
116
118
|
TunnelOperations,
|
|
@@ -119,5 +121,6 @@ export {
|
|
|
119
121
|
closeRemoteManagement,
|
|
120
122
|
enablePackageLogging,
|
|
121
123
|
getRemoteManagementState,
|
|
122
|
-
initiateRemoteManagement
|
|
124
|
+
initiateRemoteManagement,
|
|
125
|
+
startRemoteManagement
|
|
123
126
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
RemoteManagementUnauthorizedError,
|
|
3
4
|
TunnelManager,
|
|
4
5
|
TunnelOperations,
|
|
5
6
|
closeRemoteManagement,
|
|
@@ -10,12 +11,12 @@ import {
|
|
|
10
11
|
isValidPort,
|
|
11
12
|
parseRemoteManagement,
|
|
12
13
|
printer_default
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-STEISST3.js";
|
|
14
15
|
import {
|
|
15
16
|
configureLogger,
|
|
16
17
|
enablePackageLogging,
|
|
17
18
|
logger
|
|
18
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-3RTRUYNW.js";
|
|
19
20
|
|
|
20
21
|
// src/cli/options.ts
|
|
21
22
|
var cliOptions = {
|
|
@@ -256,6 +257,19 @@ import fs from "fs";
|
|
|
256
257
|
import path from "path";
|
|
257
258
|
import { isIP as isIP2 } from "net";
|
|
258
259
|
var domainRegex = /^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
|
|
260
|
+
function removeIPv6Brackets(ip) {
|
|
261
|
+
if (ip.startsWith("[") && ip.endsWith("]")) {
|
|
262
|
+
return ip.slice(1, -1);
|
|
263
|
+
}
|
|
264
|
+
return ip;
|
|
265
|
+
}
|
|
266
|
+
function isValidServerAddress(host) {
|
|
267
|
+
const normalized = removeIPv6Brackets(host.trim());
|
|
268
|
+
if (!normalized) {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
return domainRegex.test(normalized) || isIP2(normalized) !== 0;
|
|
272
|
+
}
|
|
259
273
|
var KEYWORDS = /* @__PURE__ */ new Set([
|
|
260
274
|
TunnelType.Http,
|
|
261
275
|
TunnelType.Tcp,
|
|
@@ -274,10 +288,12 @@ function parseUserAndDomain(str) {
|
|
|
274
288
|
let server;
|
|
275
289
|
let qrCode;
|
|
276
290
|
let forceFlag;
|
|
277
|
-
if (!str)
|
|
291
|
+
if (!str) {
|
|
292
|
+
return { token, type, server, qrCode, forceFlag };
|
|
293
|
+
}
|
|
278
294
|
if (str.includes("@")) {
|
|
279
295
|
const [user, domain] = str.split("@", 2);
|
|
280
|
-
if (
|
|
296
|
+
if (isValidServerAddress(domain)) {
|
|
281
297
|
let processKeyword2 = function(keyword) {
|
|
282
298
|
if ([TunnelType.Http, TunnelType.Tcp, TunnelType.Tls, TunnelType.Udp, TunnelType.TlsTcp].includes(keyword)) {
|
|
283
299
|
type = keyword;
|
|
@@ -313,7 +329,7 @@ function parseUserAndDomain(str) {
|
|
|
313
329
|
}
|
|
314
330
|
}
|
|
315
331
|
}
|
|
316
|
-
} else if (
|
|
332
|
+
} else if (isValidServerAddress(str)) {
|
|
317
333
|
server = str;
|
|
318
334
|
}
|
|
319
335
|
return { token, type, server, qrCode, forceFlag };
|
|
@@ -327,21 +343,39 @@ function parseUsers(positionalArgs, explicitToken) {
|
|
|
327
343
|
let remaining = [...positionalArgs];
|
|
328
344
|
if (typeof explicitToken === "string") {
|
|
329
345
|
const parsed = parseUserAndDomain(explicitToken);
|
|
330
|
-
if (parsed.server)
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
if (parsed.
|
|
334
|
-
|
|
346
|
+
if (parsed.server) {
|
|
347
|
+
server = parsed.server;
|
|
348
|
+
}
|
|
349
|
+
if (parsed.type) {
|
|
350
|
+
type = parsed.type;
|
|
351
|
+
}
|
|
352
|
+
if (parsed.token) {
|
|
353
|
+
token = parsed.token;
|
|
354
|
+
}
|
|
355
|
+
if (parsed.forceFlag) {
|
|
356
|
+
forceFlag = true;
|
|
357
|
+
}
|
|
358
|
+
if (parsed.qrCode) {
|
|
359
|
+
qrCode = true;
|
|
360
|
+
}
|
|
335
361
|
}
|
|
336
362
|
if (remaining.length > 0) {
|
|
337
363
|
const first = remaining[0];
|
|
338
364
|
const parsed = parseUserAndDomain(first);
|
|
339
365
|
if (parsed.server) {
|
|
340
366
|
server = parsed.server;
|
|
341
|
-
if (parsed.type)
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
if (parsed.
|
|
367
|
+
if (parsed.type) {
|
|
368
|
+
type = parsed.type;
|
|
369
|
+
}
|
|
370
|
+
if (parsed.token) {
|
|
371
|
+
token = parsed.token;
|
|
372
|
+
}
|
|
373
|
+
if (parsed.forceFlag) {
|
|
374
|
+
forceFlag = true;
|
|
375
|
+
}
|
|
376
|
+
if (parsed.qrCode) {
|
|
377
|
+
qrCode = true;
|
|
378
|
+
}
|
|
345
379
|
remaining = remaining.slice(1);
|
|
346
380
|
}
|
|
347
381
|
}
|
|
@@ -354,7 +388,9 @@ function parseType(finalConfig, values, inferredType) {
|
|
|
354
388
|
}
|
|
355
389
|
}
|
|
356
390
|
function parseLocalPort(finalConfig, values) {
|
|
357
|
-
if (typeof values.localport !== "string")
|
|
391
|
+
if (typeof values.localport !== "string") {
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
358
394
|
let lp = values.localport.trim();
|
|
359
395
|
let isHttps = false;
|
|
360
396
|
if (lp.startsWith("https://")) {
|
|
@@ -384,15 +420,11 @@ function parseLocalPort(finalConfig, values) {
|
|
|
384
420
|
}
|
|
385
421
|
return null;
|
|
386
422
|
}
|
|
387
|
-
function removeIPv6Brackets(ip) {
|
|
388
|
-
if (ip.startsWith("[") && ip.endsWith("]")) {
|
|
389
|
-
return ip.slice(1, -1);
|
|
390
|
-
}
|
|
391
|
-
return ip;
|
|
392
|
-
}
|
|
393
423
|
function isValidHostAddress(host) {
|
|
394
424
|
const normalized = removeIPv6Brackets(host.trim());
|
|
395
|
-
if (normalized.length === 0)
|
|
425
|
+
if (normalized.length === 0) {
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
396
428
|
return normalized === "localhost" || isIP2(normalized) !== 0;
|
|
397
429
|
}
|
|
398
430
|
function ipv6SafeSplitColon(s) {
|
|
@@ -416,7 +448,7 @@ function ipv6SafeSplitColon(s) {
|
|
|
416
448
|
result.push(buf);
|
|
417
449
|
return result;
|
|
418
450
|
}
|
|
419
|
-
var VALID_PROTOCOLS = [
|
|
451
|
+
var VALID_PROTOCOLS = [TunnelType.Http, TunnelType.Tcp, TunnelType.Udp, TunnelType.Tls, TunnelType.TlsTcp];
|
|
420
452
|
function parseDefaultForwarding(forwarding) {
|
|
421
453
|
const parts = ipv6SafeSplitColon(forwarding);
|
|
422
454
|
if (parts.length === 3) {
|
|
@@ -436,7 +468,9 @@ function parseDefaultForwarding(forwarding) {
|
|
|
436
468
|
}
|
|
437
469
|
function parseAdditionalForwarding(forwarding) {
|
|
438
470
|
const toPort = (v) => {
|
|
439
|
-
if (!v)
|
|
471
|
+
if (!v) {
|
|
472
|
+
return null;
|
|
473
|
+
}
|
|
440
474
|
const n = parseInt(v, 10);
|
|
441
475
|
return Number.isNaN(n) ? null : n;
|
|
442
476
|
};
|
|
@@ -448,7 +482,7 @@ function parseAdditionalForwarding(forwarding) {
|
|
|
448
482
|
}
|
|
449
483
|
const firstPart = parsed[0];
|
|
450
484
|
const [hostPart] = firstPart.split("@");
|
|
451
|
-
let protocol =
|
|
485
|
+
let protocol = TunnelType.Http;
|
|
452
486
|
let remoteDomainRaw;
|
|
453
487
|
let remotePort = 0;
|
|
454
488
|
if (hostPart.includes("//")) {
|
|
@@ -462,7 +496,7 @@ function parseAdditionalForwarding(forwarding) {
|
|
|
462
496
|
return new Error("invalid forwarding address format");
|
|
463
497
|
}
|
|
464
498
|
remoteDomainRaw = domainAndPort[0];
|
|
465
|
-
if (!remoteDomainRaw || !
|
|
499
|
+
if (!remoteDomainRaw || !isValidServerAddress(remoteDomainRaw)) {
|
|
466
500
|
return new Error("invalid remote domain");
|
|
467
501
|
}
|
|
468
502
|
const parsedRemotePort = toPort(domainAndPort[1]);
|
|
@@ -478,10 +512,10 @@ function parseAdditionalForwarding(forwarding) {
|
|
|
478
512
|
}
|
|
479
513
|
} else {
|
|
480
514
|
remoteDomainRaw = hostPart;
|
|
481
|
-
if (!
|
|
515
|
+
if (!isValidServerAddress(remoteDomainRaw)) {
|
|
482
516
|
return new Error("invalid remote domain");
|
|
483
517
|
}
|
|
484
|
-
protocol =
|
|
518
|
+
protocol = TunnelType.Http;
|
|
485
519
|
remotePort = 0;
|
|
486
520
|
}
|
|
487
521
|
const localDomain = removeIPv6Brackets(parsed[2] || "localhost");
|
|
@@ -515,7 +549,9 @@ function parseReverseTunnelAddr(finalConfig, values, primaryType) {
|
|
|
515
549
|
});
|
|
516
550
|
} else if (slicedForwarding.length === 4) {
|
|
517
551
|
const parsed = parseAdditionalForwarding(forwarding);
|
|
518
|
-
if (parsed instanceof Error)
|
|
552
|
+
if (parsed instanceof Error) {
|
|
553
|
+
return parsed;
|
|
554
|
+
}
|
|
519
555
|
forwardingData.push(parsed);
|
|
520
556
|
} else {
|
|
521
557
|
return new Error(
|
|
@@ -527,7 +563,9 @@ function parseReverseTunnelAddr(finalConfig, values, primaryType) {
|
|
|
527
563
|
return null;
|
|
528
564
|
}
|
|
529
565
|
function parseLocalTunnelAddr(finalConfig, values) {
|
|
530
|
-
if (!Array.isArray(values.L) || values.L.length === 0)
|
|
566
|
+
if (!Array.isArray(values.L) || values.L.length === 0) {
|
|
567
|
+
return null;
|
|
568
|
+
}
|
|
531
569
|
const firstL = values.L[0];
|
|
532
570
|
const parts = ipv6SafeSplitColon(firstL);
|
|
533
571
|
let debuggerHost = "localhost";
|
|
@@ -551,7 +589,9 @@ function parseLocalTunnelAddr(finalConfig, values) {
|
|
|
551
589
|
}
|
|
552
590
|
function parseDebugger(finalConfig, values) {
|
|
553
591
|
let dbg = values.debugger;
|
|
554
|
-
if (typeof dbg !== "string")
|
|
592
|
+
if (typeof dbg !== "string") {
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
555
595
|
dbg = dbg.startsWith(":") ? dbg.slice(1) : dbg;
|
|
556
596
|
const d = parseInt(dbg, 10);
|
|
557
597
|
if (!Number.isNaN(d) && isValidPort(d)) {
|
|
@@ -610,7 +650,9 @@ function isSaveConfOption(values) {
|
|
|
610
650
|
}
|
|
611
651
|
function parseServe(finalConfig, values) {
|
|
612
652
|
const sv = values.serve;
|
|
613
|
-
if (typeof sv !== "string" || sv.trim().length === 0)
|
|
653
|
+
if (typeof sv !== "string" || sv.trim().length === 0) {
|
|
654
|
+
return null;
|
|
655
|
+
}
|
|
614
656
|
finalConfig.optional.serve = sv;
|
|
615
657
|
return null;
|
|
616
658
|
}
|
|
@@ -651,7 +693,7 @@ async function buildFinalConfig(values, positionals) {
|
|
|
651
693
|
// Apply loaded config on top of defaults
|
|
652
694
|
configId: getRandomId(),
|
|
653
695
|
token: token || (configFromFile?.token || (typeof values.token === "string" ? values.token : "")),
|
|
654
|
-
serverAddress: server
|
|
696
|
+
serverAddress: server ? removeIPv6Brackets(server) : configFromFile?.serverAddress || defaultOptions.serverAddress,
|
|
655
697
|
isQRCode: qrCode || (configFromFile?.isQRCode || false),
|
|
656
698
|
autoReconnect: configFromFile?.autoReconnect ? configFromFile.autoReconnect : defaultOptions.autoReconnect,
|
|
657
699
|
optional: {
|
|
@@ -662,18 +704,32 @@ async function buildFinalConfig(values, positionals) {
|
|
|
662
704
|
type = parseType(finalConfig, values, type);
|
|
663
705
|
parseToken(finalConfig, token || values.token);
|
|
664
706
|
const dbgErr = parseDebugger(finalConfig, values);
|
|
665
|
-
if (dbgErr instanceof Error)
|
|
707
|
+
if (dbgErr instanceof Error) {
|
|
708
|
+
throw dbgErr;
|
|
709
|
+
}
|
|
666
710
|
const lpErr = parseLocalPort(finalConfig, values);
|
|
667
|
-
if (lpErr instanceof Error)
|
|
711
|
+
if (lpErr instanceof Error) {
|
|
712
|
+
throw lpErr;
|
|
713
|
+
}
|
|
668
714
|
const rErr = parseReverseTunnelAddr(finalConfig, values, type);
|
|
669
|
-
if (rErr instanceof Error)
|
|
715
|
+
if (rErr instanceof Error) {
|
|
716
|
+
throw rErr;
|
|
717
|
+
}
|
|
670
718
|
const lErr = parseLocalTunnelAddr(finalConfig, values);
|
|
671
|
-
if (lErr instanceof Error)
|
|
719
|
+
if (lErr instanceof Error) {
|
|
720
|
+
throw lErr;
|
|
721
|
+
}
|
|
672
722
|
const serveErr = parseServe(finalConfig, values);
|
|
673
|
-
if (serveErr instanceof Error)
|
|
723
|
+
if (serveErr instanceof Error) {
|
|
724
|
+
throw serveErr;
|
|
725
|
+
}
|
|
674
726
|
const autoReconnectErr = parseAutoReconnect(finalConfig, values);
|
|
675
|
-
if (autoReconnectErr instanceof Error)
|
|
676
|
-
|
|
727
|
+
if (autoReconnectErr instanceof Error) {
|
|
728
|
+
throw autoReconnectErr;
|
|
729
|
+
}
|
|
730
|
+
if (forceFlag || values.force) {
|
|
731
|
+
finalConfig.force = true;
|
|
732
|
+
}
|
|
677
733
|
parseArgs(finalConfig, remainingPositionals);
|
|
678
734
|
storeJson(finalConfig, saveconf);
|
|
679
735
|
return finalConfig;
|
|
@@ -686,15 +742,26 @@ function isAttachedReverseOrLocalFlag(arg) {
|
|
|
686
742
|
return /^-[RL].+/.test(arg);
|
|
687
743
|
}
|
|
688
744
|
function shouldMergeReverseOrLocalFragment(current, next) {
|
|
689
|
-
if (next.startsWith("-"))
|
|
690
|
-
|
|
745
|
+
if (next.startsWith("-")) {
|
|
746
|
+
return false;
|
|
747
|
+
}
|
|
748
|
+
if (next.startsWith(".")) {
|
|
749
|
+
return true;
|
|
750
|
+
}
|
|
691
751
|
const body = current.slice(2);
|
|
692
|
-
if (body.endsWith(":"))
|
|
693
|
-
|
|
752
|
+
if (body.endsWith(":")) {
|
|
753
|
+
return true;
|
|
754
|
+
}
|
|
755
|
+
if (body.includes("//") && !body.includes(":")) {
|
|
756
|
+
return true;
|
|
757
|
+
}
|
|
694
758
|
return false;
|
|
695
759
|
}
|
|
696
760
|
function preprocessWindowsArgs(args) {
|
|
697
|
-
if (os.platform() !== "win32")
|
|
761
|
+
if (os.platform() !== "win32") {
|
|
762
|
+
return args;
|
|
763
|
+
}
|
|
764
|
+
;
|
|
698
765
|
const out = [];
|
|
699
766
|
let i = 0;
|
|
700
767
|
while (i < args.length) {
|
|
@@ -772,13 +839,12 @@ import QRCode from "qrcode";
|
|
|
772
839
|
async function createQrCodes(urls) {
|
|
773
840
|
const codes = [];
|
|
774
841
|
for (const url of urls) {
|
|
775
|
-
const
|
|
776
|
-
type: "
|
|
777
|
-
|
|
778
|
-
margin: 0,
|
|
842
|
+
const raw = await QRCode.toString(url, {
|
|
843
|
+
type: "utf8",
|
|
844
|
+
margin: 2,
|
|
779
845
|
errorCorrectionLevel: "L"
|
|
780
846
|
});
|
|
781
|
-
codes.push(
|
|
847
|
+
codes.push(raw);
|
|
782
848
|
}
|
|
783
849
|
return codes;
|
|
784
850
|
}
|
|
@@ -790,6 +856,7 @@ import WebSocket from "ws";
|
|
|
790
856
|
var defaultTuiConfig = {
|
|
791
857
|
maxRequestPairs: 100,
|
|
792
858
|
visibleRequestCount: 10,
|
|
859
|
+
visibleUrlCount: 7,
|
|
793
860
|
viewportScrollMargin: 2,
|
|
794
861
|
inactivityHttpSelectorTimeoutMs: 1e4
|
|
795
862
|
};
|
|
@@ -797,6 +864,7 @@ function getTuiConfig() {
|
|
|
797
864
|
return {
|
|
798
865
|
maxRequestPairs: defaultTuiConfig.maxRequestPairs,
|
|
799
866
|
visibleRequestCount: defaultTuiConfig.visibleRequestCount,
|
|
867
|
+
visibleUrlCount: defaultTuiConfig.visibleUrlCount,
|
|
800
868
|
viewportScrollMargin: defaultTuiConfig.viewportScrollMargin,
|
|
801
869
|
inactivityHttpSelectorTimeoutMs: defaultTuiConfig.inactivityHttpSelectorTimeoutMs
|
|
802
870
|
};
|
|
@@ -1024,7 +1092,7 @@ function createFullUI(screen, urls, greet, tunnelConfig) {
|
|
|
1024
1092
|
width: "100%-2",
|
|
1025
1093
|
height: `100%-${lowerSectionTop + 6}`
|
|
1026
1094
|
});
|
|
1027
|
-
const isQrCodeRequested = tunnelConfig?.
|
|
1095
|
+
const isQrCodeRequested = tunnelConfig?.isQRCode || false;
|
|
1028
1096
|
const requestsBox = blessed.box({
|
|
1029
1097
|
parent: lowerSection,
|
|
1030
1098
|
top: 0,
|
|
@@ -1167,8 +1235,24 @@ function getBytesInt(b) {
|
|
|
1167
1235
|
// src/tui/blessed/components/DisplayUpdaters.ts
|
|
1168
1236
|
function updateUrlsDisplay(urlsBox, screen, urls, currentQrIndex) {
|
|
1169
1237
|
if (!urlsBox) return;
|
|
1170
|
-
|
|
1171
|
-
|
|
1238
|
+
const config = getTuiConfig();
|
|
1239
|
+
const { visibleUrlCount } = config;
|
|
1240
|
+
let viewportStart = 0;
|
|
1241
|
+
if (urls.length > visibleUrlCount) {
|
|
1242
|
+
viewportStart = Math.max(0, Math.min(
|
|
1243
|
+
currentQrIndex - Math.floor(visibleUrlCount / 2),
|
|
1244
|
+
urls.length - visibleUrlCount
|
|
1245
|
+
));
|
|
1246
|
+
}
|
|
1247
|
+
const viewportEnd = Math.min(viewportStart + visibleUrlCount, urls.length);
|
|
1248
|
+
const visibleUrls = urls.slice(viewportStart, viewportEnd);
|
|
1249
|
+
let content = "{green-fg}{bold}Public URLs{/bold}{/green-fg}";
|
|
1250
|
+
if (viewportStart > 0) {
|
|
1251
|
+
content += ` {gray-fg}\u2191 ${viewportStart} more{/gray-fg}`;
|
|
1252
|
+
}
|
|
1253
|
+
content += "\n";
|
|
1254
|
+
visibleUrls.forEach((url, i) => {
|
|
1255
|
+
const index = viewportStart + i;
|
|
1172
1256
|
const isSelected = index === currentQrIndex;
|
|
1173
1257
|
const prefix = isSelected ? "\u2192 " : "\u2022 ";
|
|
1174
1258
|
const color = isSelected ? "yellow" : "magenta";
|
|
@@ -1180,6 +1264,11 @@ function updateUrlsDisplay(urlsBox, screen, urls, currentQrIndex) {
|
|
|
1180
1264
|
`;
|
|
1181
1265
|
}
|
|
1182
1266
|
});
|
|
1267
|
+
const itemsBelow = urls.length - viewportEnd;
|
|
1268
|
+
if (itemsBelow > 0) {
|
|
1269
|
+
content += `{gray-fg}\u2193 ${itemsBelow} more{/gray-fg}
|
|
1270
|
+
`;
|
|
1271
|
+
}
|
|
1183
1272
|
urlsBox.setContent(content);
|
|
1184
1273
|
screen.render();
|
|
1185
1274
|
}
|
|
@@ -1847,7 +1936,7 @@ var TunnelTui = class {
|
|
|
1847
1936
|
}
|
|
1848
1937
|
}
|
|
1849
1938
|
async generateQrCodes() {
|
|
1850
|
-
if (this.tunnelConfig?.
|
|
1939
|
+
if (this.tunnelConfig?.isQRCode && this.urls.length > 0) {
|
|
1851
1940
|
this.qrCodes = await createQrCodes(this.urls);
|
|
1852
1941
|
this.updateQrCodeDisplay();
|
|
1853
1942
|
}
|
|
@@ -2080,7 +2169,7 @@ async function startCli(finalConfig, manager) {
|
|
|
2080
2169
|
});
|
|
2081
2170
|
}
|
|
2082
2171
|
manager2.registerWorkerErrorListner(tunnel.tunnelid, (_tunnelid, error) => {
|
|
2083
|
-
printer_default.
|
|
2172
|
+
printer_default.fatal(`${error.message}`);
|
|
2084
2173
|
});
|
|
2085
2174
|
await manager2.startTunnel(tunnel.tunnelid);
|
|
2086
2175
|
printer_default.stopSpinnerSuccess(" Connected to Pinggy");
|
|
@@ -2205,7 +2294,7 @@ async function startCli(finalConfig, manager) {
|
|
|
2205
2294
|
}
|
|
2206
2295
|
} catch (err) {
|
|
2207
2296
|
printer_default.stopSpinnerFail("Failed to connect");
|
|
2208
|
-
printer_default.
|
|
2297
|
+
printer_default.fatal(err.message || "Unknown error");
|
|
2209
2298
|
throw err;
|
|
2210
2299
|
}
|
|
2211
2300
|
}
|
|
@@ -2236,9 +2325,8 @@ async function main() {
|
|
|
2236
2325
|
}
|
|
2237
2326
|
const parseResult = await parseRemoteManagement(values);
|
|
2238
2327
|
if (parseResult?.ok === false) {
|
|
2239
|
-
printer_default.error(parseResult.error);
|
|
2240
2328
|
logger.error("Failed to initiate remote management:", parseResult.error);
|
|
2241
|
-
|
|
2329
|
+
printer_default.fatal(parseResult.error);
|
|
2242
2330
|
}
|
|
2243
2331
|
logger.debug("Building final config from CLI values and positionals", { values, positionals });
|
|
2244
2332
|
const finalConfig = await buildFinalConfig(values, positionals);
|
|
@@ -2246,7 +2334,7 @@ async function main() {
|
|
|
2246
2334
|
await startCli(finalConfig, manager);
|
|
2247
2335
|
} catch (error) {
|
|
2248
2336
|
logger.error("Unhandled error in CLI:", error);
|
|
2249
|
-
printer_default.
|
|
2337
|
+
printer_default.fatal(error);
|
|
2250
2338
|
}
|
|
2251
2339
|
}
|
|
2252
2340
|
var currentFile = fileURLToPath(import.meta.url);
|
|
@@ -2260,6 +2348,7 @@ if (entryFile && entryFile === currentFile) {
|
|
|
2260
2348
|
main();
|
|
2261
2349
|
}
|
|
2262
2350
|
export {
|
|
2351
|
+
RemoteManagementUnauthorizedError,
|
|
2263
2352
|
TunnelManager,
|
|
2264
2353
|
TunnelOperations,
|
|
2265
2354
|
closeRemoteManagement,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pinggy",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.6",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Create secure, shareable tunnels to your localhost and manage them from the command line. ",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
]
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@pinggy/pinggy": "^0.4.
|
|
54
|
+
"@pinggy/pinggy": "^0.4.3",
|
|
55
55
|
"blessed": "^0.1.81",
|
|
56
56
|
"clipboardy": "^5.0.0",
|
|
57
57
|
"mime": "^4.1.0",
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"@types/blessed": "^0.1.25",
|
|
66
66
|
"@types/jest": "^30.0.0",
|
|
67
67
|
"@types/node": "^24.3.0",
|
|
68
|
+
"@types/qrcode": "^1.5.6",
|
|
68
69
|
"@types/qrcode-terminal": "^0.12.2",
|
|
69
70
|
"@types/ws": "^8.18.1",
|
|
70
71
|
"@yao-pkg/pkg": "^6.11.0",
|