@balaji003/lantransfer 1.0.4 → 1.0.5

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/server.js +83 -41
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@balaji003/lantransfer",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "LAN File Transfer — peer-to-peer file sharing over local network. Zero dependencies.",
5
5
  "main": "server.js",
6
6
  "bin": {
package/server.js CHANGED
@@ -165,6 +165,20 @@ const server = http.createServer(async (req, res) => {
165
165
  return;
166
166
  }
167
167
 
168
+ // ── Ping endpoint for HTTP-based discovery ──
169
+ if (req.method === 'GET' && req.url === '/api/ping') {
170
+ res.writeHead(200, {
171
+ 'Content-Type': 'application/json',
172
+ 'Access-Control-Allow-Origin': '*',
173
+ });
174
+ res.end(JSON.stringify({
175
+ app: 'lantransfer',
176
+ device_name: deviceName,
177
+ tcp_port: TRANSFER_PORT,
178
+ }));
179
+ return;
180
+ }
181
+
168
182
  // ── SSE stream ──
169
183
  if (req.method === 'GET' && req.url === '/events') {
170
184
  res.writeHead(200, {
@@ -504,52 +518,83 @@ function formatSize(bytes) {
504
518
  }
505
519
 
506
520
  // ──────────────────────────────────────────────────────────────────────────────
507
- // Windows Firewall check
521
+ // HTTP-based discovery (no firewall rules needed — outbound TCP only)
508
522
  // ──────────────────────────────────────────────────────────────────────────────
509
- function checkWindowsFirewall() {
510
- if (process.platform !== 'win32') return;
511
-
512
- const ruleName = 'LAN Transfer (lantransfer)';
513
- const nodeExe = process.execPath;
514
-
515
- // Check if a firewall rule already exists
516
- exec(`netsh advfirewall firewall show rule name="${ruleName}"`, { windowsHide: true }, (err, stdout) => {
517
- if (!err && stdout.includes(ruleName)) {
518
- if (stdout.includes('Enabled:') && stdout.includes('Yes')) {
519
- console.log(' Firewall: Allowed');
520
- return;
523
+ function getSubnetIPs() {
524
+ const results = [];
525
+ for (const ifaces of Object.values(os.networkInterfaces())) {
526
+ for (const iface of ifaces) {
527
+ if (iface.family === 'IPv4' && !iface.internal && iface.netmask) {
528
+ const ipParts = iface.address.split('.').map(Number);
529
+ const maskParts = iface.netmask.split('.').map(Number);
530
+ // Only scan /24 or smaller subnets to keep it fast
531
+ if (maskParts[2] === 255) {
532
+ const base = ipParts.slice(0, 3).join('.');
533
+ for (let i = 1; i < 255; i++) {
534
+ const ip = `${base}.${i}`;
535
+ if (ip !== iface.address) results.push(ip);
536
+ }
537
+ }
521
538
  }
522
539
  }
540
+ }
541
+ return results;
542
+ }
523
543
 
524
- // No rule — prompt user via UAC elevation
525
- console.log('');
526
- console.log(' !! Firewall rule not found for LAN Transfer.');
527
- console.log(' !! Device discovery requires UDP/TCP through Windows Firewall.');
528
- console.log(' !! Requesting permission (UAC prompt)...');
529
- console.log('');
530
-
531
- const addCmd = [
532
- `netsh advfirewall firewall add rule name="${ruleName}" dir=in action=allow protocol=UDP localport=${DISCOVERY_PORT} program="${nodeExe}" enable=yes`,
533
- `netsh advfirewall firewall add rule name="${ruleName}" dir=in action=allow protocol=TCP localport=${TRANSFER_PORT} program="${nodeExe}" enable=yes`,
534
- ].join(' & ');
535
-
536
- const psCmd = `powershell -Command "Start-Process cmd -ArgumentList '/c ${addCmd.replace(/"/g, '\\"')}' -Verb RunAs -Wait"`;
537
-
538
- exec(psCmd, { windowsHide: false, timeout: 60_000 }, (err2) => {
539
- if (err2) {
540
- console.log(' !! Firewall permission denied. Discovery will NOT work.');
541
- console.log(' !! To fix manually:');
542
- console.log(' !! 1. Open Windows Security > Firewall & network protection');
543
- console.log(' !! 2. Click "Allow an app through firewall"');
544
- console.log(' !! 3. Add Node.js and allow Private + Public networks');
545
- console.log('');
546
- } else {
547
- console.log(' Firewall: Rule added! Discovery should work now.');
548
- }
544
+ function pingHost(ip) {
545
+ return new Promise(resolve => {
546
+ const req = http.get(`http://${ip}:${HTTP_PORT}/api/ping`, { timeout: 800 }, res => {
547
+ let body = '';
548
+ res.on('data', c => body += c);
549
+ res.on('end', () => {
550
+ try {
551
+ const d = JSON.parse(body);
552
+ if (d.app === 'lantransfer' && d.device_name !== deviceName) {
553
+ resolve({ ip, device_name: d.device_name, tcp_port: d.tcp_port });
554
+ } else resolve(null);
555
+ } catch { resolve(null); }
556
+ });
549
557
  });
558
+ req.on('error', () => resolve(null));
559
+ req.on('timeout', () => { req.destroy(); resolve(null); });
550
560
  });
551
561
  }
552
562
 
563
+ let httpScanning = false;
564
+ async function httpDiscoveryScan() {
565
+ if (!isDiscoverable || httpScanning) return;
566
+ httpScanning = true;
567
+ try {
568
+ const ips = getSubnetIPs();
569
+ // Scan in batches of 50 to avoid fd exhaustion
570
+ for (let i = 0; i < ips.length; i += 50) {
571
+ const batch = ips.slice(i, i + 50);
572
+ const results = await Promise.all(batch.map(pingHost));
573
+ for (const r of results) {
574
+ if (!r) continue;
575
+ const id = `${r.ip}:${r.tcp_port}`;
576
+ const isNew = !peers.has(id);
577
+ peers.set(id, {
578
+ device_name: r.device_name,
579
+ ip: r.ip,
580
+ tcp_port: r.tcp_port,
581
+ last_seen: Date.now(),
582
+ });
583
+ if (isNew) {
584
+ console.log(` Found: ${r.device_name} (${r.ip})`);
585
+ broadcast();
586
+ }
587
+ }
588
+ }
589
+ } catch { /* scan error, ignore */ }
590
+ httpScanning = false;
591
+ }
592
+
593
+ // Run HTTP discovery scan every 5 seconds
594
+ setInterval(httpDiscoveryScan, 5_000);
595
+ // Also run immediately on start (after a short delay for server to be ready)
596
+ setTimeout(httpDiscoveryScan, 1_000);
597
+
553
598
  // ──────────────────────────────────────────────────────────────────────────────
554
599
  // Start
555
600
  // ──────────────────────────────────────────────────────────────────────────────
@@ -570,9 +615,6 @@ server.listen(HTTP_PORT, () => {
570
615
  console.log(` UI: http://localhost:${HTTP_PORT}`);
571
616
  console.log('');
572
617
 
573
- // Check firewall on Windows
574
- checkWindowsFirewall();
575
-
576
618
  // Auto-open browser
577
619
  const url = `http://localhost:${HTTP_PORT}`;
578
620
  if (process.platform === 'win32') exec(`start "" "${url}"`);