Implement authentication middleware and rolling codes service for secure API access

This commit is contained in:
ImBenji
2025-08-19 20:30:43 +01:00
parent f829bd5fe1
commit 17091bcc95
4 changed files with 380 additions and 44 deletions

View File

@@ -4,9 +4,10 @@
import 'dart:io';
import 'dart:isolate';
import 'dart:math';
import 'package:supabase/supabase.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:waylume_server/config/supabase_config.dart';
import 'package:waylume_server/services/rolling_codes_service.dart';
void initHeartbeat() {
@@ -18,18 +19,122 @@ void initHeartbeat() {
while (true) {
DateTime now = DateTime.now().toUtc();
try {
// Wait until rolling codes service is initialized and registered
if (!RollingCodesService.isRegistered) {
print("Server not registered yet, skipping heartbeat");
await Future.delayed(Duration(seconds: 30));
continue;
}
// Generate operational rolling code for heartbeat authentication
String authCode = RollingCodesService.generateOperationalCode();
// Get server status (CPU, memory, active connections)
Map<String, dynamic> serverStatus = await _getServerStatus();
// Send heartbeat to server-manager endpoint
String serverManagerUrl = '${fromEnivronment("SUPABASE_URL")}/functions/v1/server-manager/heartbeat';
Map<String, dynamic> heartbeatData = {
'server_id': fromEnivronment("SERVER_ID")!,
'timestamp': now.toIso8601String(),
'auth_code': authCode,
'status': serverStatus
};
final response = await http.post(
Uri.parse(serverManagerUrl),
headers: {
'Content-Type': 'application/json',
'apikey': fromEnivronment('SUPABASE_ANON_KEY')!,
},
body: jsonEncode(heartbeatData),
);
if (response.statusCode == 200) {
final responseData = jsonDecode(response.body);
if (responseData['success']) {
print("Heartbeat sent successfully at ${now.toIso8601String()}");
} else {
print("Heartbeat failed: ${responseData['error']}");
}
} else {
print("Heartbeat request failed: ${response.statusCode}");
}
} catch (e) {
print("Error sending heartbeat: $e");
}
await SUPABASE_CLIENT
.from("waylume_servers")
.update({ "last_heartbeat": now.toIso8601String() })
.eq("id", fromEnivronment("SERVER_ID")!);
print("Heartbeat sent to Supabase at ${now.toIso8601String()}");
// Wait 30 seconds before sending the next heartbeat
await Future.delayed(Duration(seconds: 30));
// Wait 120 seconds (2 minutes) before sending the next heartbeat
await Future.delayed(Duration(seconds: 120));
}
}, null);
}
Future<Map<String, dynamic>> _getServerStatus() async {
// Get basic server status information
// This is a simplified implementation - could be enhanced with actual metrics
int activeConnections = 0;
double cpuUsage = 0.0;
double memoryUsage = 0.0;
try {
// Get active WireGuard connections count
ProcessResult wgShowResult = await Process.run('wg', ['show', 'wg0']);
if (wgShowResult.exitCode == 0) {
// Count peer entries (simplified - each peer has multiple lines)
String output = wgShowResult.stdout as String;
activeConnections = 'peer:'.allMatches(output).length;
}
} catch (e) {
print("Error getting WireGuard status: $e");
}
try {
// Get basic system info (simplified)
ProcessResult uptimeResult = await Process.run('uptime', []);
if (uptimeResult.exitCode == 0) {
String output = uptimeResult.stdout as String;
// Parse load average as a rough CPU usage indicator
RegExp loadRegex = RegExp(r'load average: (\d+\.?\d*),');
Match? match = loadRegex.firstMatch(output);
if (match != null) {
cpuUsage = double.tryParse(match.group(1) ?? '0') ?? 0.0;
cpuUsage = (cpuUsage * 100).clamp(0, 100); // Convert to percentage
}
}
} catch (e) {
print("Error getting CPU usage: $e");
}
try {
// Get memory usage (simplified)
ProcessResult freeResult = await Process.run('free', ['-m']);
if (freeResult.exitCode == 0) {
String output = freeResult.stdout as String;
List<String> lines = output.split('\n');
if (lines.length > 1) {
List<String> memLine = lines[1].split(RegExp(r'\s+'));
if (memLine.length > 2) {
int total = int.tryParse(memLine[1]) ?? 1;
int used = int.tryParse(memLine[2]) ?? 0;
memoryUsage = (used / total * 100).clamp(0, 100);
}
}
}
} catch (e) {
print("Error getting memory usage: $e");
}
return {
'active_connections': activeConnections,
'cpu_usage': cpuUsage,
'memory_usage': memoryUsage,
};
}