topnic-https 1.2.5 → 1.2.7
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 +2 -2
- package/src/sharing/directServer.js +38 -68
- package/src/sharing/shareManager.js +16 -21
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "topnic-https",
|
3
|
-
"version": "1.2.
|
3
|
+
"version": "1.2.7",
|
4
4
|
"main": "./src/main/index.js",
|
5
5
|
"type": "commonjs",
|
6
6
|
"scripts": {
|
@@ -91,10 +91,10 @@
|
|
91
91
|
"chokidar": "^4.0.1",
|
92
92
|
"commander": "^12.1.0",
|
93
93
|
"crypto": "^1.0.1",
|
94
|
+
"dns": "^0.2.2",
|
94
95
|
"electron": "^33.2.0",
|
95
96
|
"fs": "^0.0.1-security",
|
96
97
|
"https": "^1.0.0",
|
97
|
-
"localtunnel": "^2.0.2",
|
98
98
|
"nanoid": "^5.0.8",
|
99
99
|
"net": "^1.0.2",
|
100
100
|
"ngrok": "^5.0.0-beta.2",
|
@@ -3,75 +3,60 @@ const WebSocket = require('ws');
|
|
3
3
|
const { nanoid } = require('nanoid/non-secure');
|
4
4
|
const os = require('os');
|
5
5
|
const net = require('net');
|
6
|
+
const dns = require('dns');
|
6
7
|
|
7
8
|
class DirectServer {
|
8
9
|
constructor() {
|
9
10
|
this.connections = new Map();
|
10
11
|
this.server = http.createServer(this.handleRequest.bind(this));
|
11
12
|
this.wss = new WebSocket.Server({ server: this.server });
|
12
|
-
this.publicIp =
|
13
|
+
this.publicIp = null;
|
13
14
|
}
|
14
15
|
|
15
|
-
getPublicIp() {
|
16
|
-
const interfaces = os.networkInterfaces();
|
17
|
-
for (const iface of Object.values(interfaces)) {
|
18
|
-
const nonLocalIpv4 = iface.find(addr => addr.family === 'IPv4' && !addr.internal);
|
19
|
-
if (nonLocalIpv4) return nonLocalIpv4.address;
|
20
|
-
}
|
21
|
-
return 'localhost';
|
22
|
-
}
|
23
|
-
|
24
|
-
async isPortAvailable(port) {
|
16
|
+
async getPublicIp() {
|
25
17
|
return new Promise((resolve) => {
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
.
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
18
|
+
// أولاً نحاول الحصول على IP المحلي
|
19
|
+
const interfaces = os.networkInterfaces();
|
20
|
+
let localIp = 'localhost';
|
21
|
+
|
22
|
+
for (const iface of Object.values(interfaces)) {
|
23
|
+
const nonLocalIpv4 = iface.find(addr =>
|
24
|
+
addr.family === 'IPv4' &&
|
25
|
+
!addr.internal &&
|
26
|
+
addr.address !== '127.0.0.1'
|
27
|
+
);
|
28
|
+
if (nonLocalIpv4) {
|
29
|
+
localIp = nonLocalIpv4.address;
|
30
|
+
break;
|
31
|
+
}
|
32
|
+
}
|
40
33
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
34
|
+
// نحاول الحصول على IP العام
|
35
|
+
dns.lookup(os.hostname(), (err, address, family) => {
|
36
|
+
if (!err && address && address !== '127.0.0.1') {
|
37
|
+
resolve(address);
|
38
|
+
} else {
|
39
|
+
resolve(localIp);
|
40
|
+
}
|
46
41
|
});
|
47
42
|
});
|
48
43
|
}
|
49
44
|
|
50
|
-
async
|
51
|
-
let port = startPort;
|
52
|
-
while (!(await this.isPortAvailable(port))) {
|
53
|
-
port++;
|
54
|
-
}
|
55
|
-
return port;
|
56
|
-
}
|
57
|
-
|
58
|
-
async verifyTargetPort(port) {
|
45
|
+
async start(port = 3500) {
|
59
46
|
try {
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
req.on('error', reject);
|
70
|
-
req.end();
|
47
|
+
this.publicIp = await this.getPublicIp();
|
48
|
+
|
49
|
+
return new Promise((resolve) => {
|
50
|
+
this.server.listen(port, '0.0.0.0', () => {
|
51
|
+
console.log(`🚀 خادم المشاركة يعمل على المنفذ ${port}`);
|
52
|
+
console.log(`📡 عنوان IP: ${this.publicIp}:${port}`);
|
53
|
+
console.log(`🌐 يمكنك الوصول محلياً عبر: http://localhost:${port}`);
|
54
|
+
resolve(port);
|
55
|
+
});
|
71
56
|
});
|
72
|
-
return true;
|
73
57
|
} catch (error) {
|
74
|
-
|
58
|
+
console.error('خطأ في بدء الخادم:', error);
|
59
|
+
throw error;
|
75
60
|
}
|
76
61
|
}
|
77
62
|
|
@@ -91,12 +76,10 @@ class DirectServer {
|
|
91
76
|
const connectionId = urlParts[1];
|
92
77
|
const connection = this.connections.get(connectionId);
|
93
78
|
|
94
|
-
// إضافة CORS headers
|
95
79
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
96
80
|
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
97
81
|
res.setHeader('Access-Control-Allow-Headers', '*');
|
98
82
|
|
99
|
-
// معالجة طلبات OPTIONS
|
100
83
|
if (req.method === 'OPTIONS') {
|
101
84
|
res.writeHead(200);
|
102
85
|
res.end();
|
@@ -109,17 +92,8 @@ class DirectServer {
|
|
109
92
|
return;
|
110
93
|
}
|
111
94
|
|
112
|
-
// التحقق من أن الخدمة المحلية تعمل
|
113
|
-
if (!(await this.verifyTargetPort(connection.port))) {
|
114
|
-
res.writeHead(502);
|
115
|
-
res.end('الخدمة المحلية غير متاحة');
|
116
|
-
return;
|
117
|
-
}
|
118
|
-
|
119
|
-
// إعادة بناء المسار الأصلي
|
120
95
|
const originalPath = urlParts.length > 2 ? '/' + urlParts.slice(2).join('/') : '/';
|
121
96
|
|
122
|
-
// إضافة معلومات التوجيه
|
123
97
|
const options = {
|
124
98
|
hostname: 'localhost',
|
125
99
|
port: connection.port,
|
@@ -129,14 +103,12 @@ class DirectServer {
|
|
129
103
|
...req.headers,
|
130
104
|
'X-Forwarded-Host': req.headers.host,
|
131
105
|
'X-Forwarded-Proto': 'http',
|
132
|
-
'X-
|
106
|
+
'X-Real-IP': req.socket.remoteAddress,
|
133
107
|
host: `localhost:${connection.port}`
|
134
108
|
}
|
135
109
|
};
|
136
110
|
|
137
|
-
// إنشاء طلب التوجيه
|
138
111
|
const proxyReq = http.request(options, (proxyRes) => {
|
139
|
-
// نسخ headers الاستجابة
|
140
112
|
Object.keys(proxyRes.headers).forEach(key => {
|
141
113
|
res.setHeader(key, proxyRes.headers[key]);
|
142
114
|
});
|
@@ -145,7 +117,6 @@ class DirectServer {
|
|
145
117
|
proxyRes.pipe(res);
|
146
118
|
});
|
147
119
|
|
148
|
-
// معالجة أخطاء التوجيه
|
149
120
|
proxyReq.on('error', (error) => {
|
150
121
|
console.error('خطأ في التوجيه:', error);
|
151
122
|
if (!res.headersSent) {
|
@@ -154,7 +125,6 @@ class DirectServer {
|
|
154
125
|
}
|
155
126
|
});
|
156
127
|
|
157
|
-
// إرسال البيانات إلى التطبيق المحلي
|
158
128
|
if (!req.readableEnded) {
|
159
129
|
req.pipe(proxyReq);
|
160
130
|
} else {
|
@@ -12,25 +12,31 @@ class ShareManager {
|
|
12
12
|
|
13
13
|
async createShare(port) {
|
14
14
|
try {
|
15
|
-
const
|
16
|
-
const
|
15
|
+
const id = this.server.createConnection(port);
|
16
|
+
const serverPort = this.server.getPort();
|
17
|
+
const serverIp = await this.server.getPublicIp();
|
18
|
+
|
19
|
+
const shareUrl = `http://${serverIp}:${serverPort}/${id}`;
|
20
|
+
const localUrl = `http://localhost:${serverPort}/${id}`;
|
17
21
|
|
18
22
|
const share = {
|
19
23
|
id,
|
20
24
|
url: shareUrl,
|
21
|
-
|
25
|
+
localUrl,
|
22
26
|
port: port,
|
23
27
|
startTime: Date.now()
|
24
28
|
};
|
25
29
|
|
26
30
|
this.activeShares.set(id, share);
|
27
31
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
console.log('\n🌐 تم إنشاء المشاركة بنجاح!');
|
33
|
+
console.log('--------------------------------');
|
34
|
+
console.log('📡 الروابط المتاحة:');
|
35
|
+
console.log(`🏠 محلي: ${localUrl}`);
|
36
|
+
console.log(`🌍 خارجي: ${shareUrl}`);
|
37
|
+
console.log('--------------------------------\n');
|
38
|
+
|
39
|
+
return share;
|
34
40
|
} catch (error) {
|
35
41
|
throw new Error(`فشل إنشاء المشاركة: ${error.message}`);
|
36
42
|
}
|
@@ -44,18 +50,7 @@ class ShareManager {
|
|
44
50
|
|
45
51
|
this.server.removeConnection(shareId);
|
46
52
|
this.activeShares.delete(shareId);
|
47
|
-
|
48
|
-
|
49
|
-
getShareStats(shareId) {
|
50
|
-
const share = this.activeShares.get(shareId);
|
51
|
-
if (!share) return null;
|
52
|
-
|
53
|
-
const stats = this.server.getConnectionStats(shareId);
|
54
|
-
return {
|
55
|
-
...share,
|
56
|
-
...stats,
|
57
|
-
uptime: Math.floor((Date.now() - share.startTime) / 1000 / 60) // بالدقائق
|
58
|
-
};
|
53
|
+
console.log(`\n✅ تم إغلاق المشاركة: ${shareId}`);
|
59
54
|
}
|
60
55
|
}
|
61
56
|
|