Files
waylume_server/lib/services/vpn_session_service.dart

105 lines
3.6 KiB
Dart

import 'dart:convert';
import 'dart:io';
import 'package:supabase/supabase.dart';
import 'package:waylume_server/config/supabase_config.dart';
class VpnSessionService {
/// Detects existing VPN sessions for this server and prints their IDs with keepalive info
static Future<void> detectSessions() async {
try {
final serverId = fromEnivronment('SERVER_ID');
if (serverId == null) {
print('ERROR: SERVER_ID environment variable not set');
return;
}
// Get all sessions for this server
final sessions = await SUPABASE_CLIENT
.from('vpn_sessions')
.select('id, peer_info')
.eq('server_id', serverId);
if (sessions.isEmpty) {
print('No VPN sessions found for server: $serverId');
} else {
print('Found ${sessions.length} VPN sessions for server: $serverId');
for (final session in sessions) {
final sessionId = session['id'];
final peerInfo = session['peer_info'];
if (peerInfo != null && peerInfo['peer'] != null && peerInfo['peer']['publicKey'] != null) {
final publicKey = peerInfo['peer']['publicKey'] as String;
final keepaliveInfo = await _getKeepaliveForPeer(publicKey);
print('Session ID: $sessionId - Peer: ${publicKey.substring(0, 8)}... - $keepaliveInfo');
} else {
print('Session ID: $sessionId - No peer public key available');
}
}
}
} catch (e) {
print('Error detecting sessions: $e');
}
}
/// Generates public key from private key
static Future<String> _getPublicKeyFromPrivateKey(String privateKey) async {
try {
final pubProcess = await Process.start('wg', ['pubkey']);
pubProcess.stdin.writeln(privateKey);
await pubProcess.stdin.close();
final publicKey = await pubProcess.stdout.transform(utf8.decoder).join();
return publicKey.trim();
} catch (e) {
return 'Error generating public key: $e';
}
}
/// Gets keepalive info for a specific peer
static Future<String> _getKeepaliveForPeer(String publicKey) async {
try {
final result = await Process.run('wg', ['show', 'wg0', 'dump']);
if (result.exitCode != 0) {
return 'Failed to get WireGuard info';
}
final lines = result.stdout.toString().trim().split('\n');
// Skip first line (server info) and look for this peer
for (int i = 1; i < lines.length; i++) {
final line = lines[i].trim();
if (line.isEmpty) continue;
final parts = line.split('\t');
if (parts.length >= 5 && parts[0] == publicKey) {
final latestHandshake = parts[4];
final handshakeTime = int.tryParse(latestHandshake) ?? 0;
if (handshakeTime == 0) {
return 'No handshake yet';
} else {
final handshakeDateTime = DateTime.fromMillisecondsSinceEpoch(handshakeTime * 1000);
final now = DateTime.now();
final duration = now.difference(handshakeDateTime);
// Check if connection is dead (more than 2 minutes 30 seconds)
if (duration.inSeconds > 150) {
return 'DEAD - Last handshake: ${handshakeDateTime.toLocal()} (${duration.inMinutes}m ${duration.inSeconds % 60}s ago)';
} else {
return 'ALIVE - Last handshake: ${handshakeDateTime.toLocal()} (${duration.inSeconds}s ago)';
}
}
}
}
return 'Peer not found in WireGuard';
} catch (e) {
return 'Error checking keepalive: $e';
}
}
}