-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtelemetry.php
More file actions
129 lines (109 loc) · 4.31 KB
/
Copy pathtelemetry.php
File metadata and controls
129 lines (109 loc) · 4.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
<?php
/**
* NEO SSH-Win Manager - Telemetry Counter
*
* Empfängt Telemetrie-Ereignisse vom Client.
* Serverseitiger Schutz via IP Rate-Limiting, da Open-Source-Clients keine Geheimnisse wahren können.
*/
define('DATA_FILE', __DIR__ . '/telemetry_data.json');
define('IP_LOG_FILE', __DIR__ . '/telemetry_ips.json');
define('MAX_LOG_ENTRIES', 500);
function load_telemetry_rate_limit_salt(): string
{
$config_file = __DIR__ . '/telemetry.local.php';
if (is_file($config_file)) {
$config = include $config_file;
if (is_array($config)) {
$salt = trim((string) ($config['rate_limit_salt'] ?? ''));
if ($salt !== '') {
return $salt;
}
}
}
$env_salt = getenv('NEOSSH_RATE_LIMIT_SALT');
if (is_string($env_salt)) {
$env_salt = trim($env_salt);
if ($env_salt !== '') {
return $env_salt;
}
}
return '';
}
header('Content-Type: application/json');
$action = isset($_GET['action']) ? $_GET['action'] : '';
if (!in_array($action, ['install', 'login'])) {
http_response_code(400);
exit(json_encode(["status" => "error", "message" => "Invalid action"]));
}
// Einfacher Schutz vor primitiven Web-Scrapern
if (!isset($_SERVER['HTTP_USER_AGENT']) || strpos($_SERVER['HTTP_USER_AGENT'], 'NeoSSHWinManager') === false) {
http_response_code(401);
exit(json_encode(["status" => "error", "message" => "Invalid client"]));
}
// --- 1. IP Rate Limiting (Zero-Log mit täglichem Hash) ---
// Um PII (IP-Adressen) nicht zu speichern, wird ein gehashter Wert generiert.
// Dieser Hash ist unwiderruflich und wechselt um Mitternacht automatisch.
// SECURITY: Load salt from a local config file or environment variable; never hardcode secrets in source.
$_salt = load_telemetry_rate_limit_salt();
if (!$_salt) {
http_response_code(500);
exit(json_encode([
"status" => "error",
"message" => "Server misconfiguration: set rate_limit_salt in telemetry.local.php or NEOSSH_RATE_LIMIT_SALT"
]));
}
define('RATE_LIMIT_SALT', $_salt);
$client_ip = $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1';
$daily_salt = date('Y-m-d');
$anonymous_client_hash = hash('sha256', $client_ip . RATE_LIMIT_SALT . $daily_salt);
$current_time = time();
$limit_data = [];
if (file_exists(IP_LOG_FILE)) {
$content = file_get_contents(IP_LOG_FILE);
$limit_data = json_decode($content, true) ?: [];
}
// Eintrag initialisieren
if (!isset($limit_data[$anonymous_client_hash])) {
$limit_data[$anonymous_client_hash] = ['last_install' => 0, 'logins' => []];
}
if ($action === 'install') {
if ($current_time - $limit_data[$anonymous_client_hash]['last_install'] < 86400) {
http_response_code(429);
exit(json_encode(["status" => "error", "message" => "Rate limit exceeded for install"]));
}
$limit_data[$anonymous_client_hash]['last_install'] = $current_time;
} elseif ($action === 'login') {
$recent_logins = array_filter($limit_data[$anonymous_client_hash]['logins'], function($t) use ($current_time) {
return ($current_time - $t) < 3600;
});
if (count($recent_logins) >= 10) {
http_response_code(429);
exit(json_encode(["status" => "error", "message" => "Rate limit exceeded for logins"]));
}
$recent_logins[] = $current_time;
$limit_data[$anonymous_client_hash]['logins'] = $recent_logins;
}
// Bereinigen
$limit_data = array_filter($limit_data, function($data) use ($current_time) {
$recent_login = !empty($data['logins']) ? max($data['logins']) : 0;
return ($current_time - $data['last_install'] < 86400) || ($current_time - $recent_login < 3600);
});
file_put_contents(IP_LOG_FILE, json_encode($limit_data));
// --- 2. Counter aktuallisieren ---
$data = ["installs" => 0, "logins" => 0, "recent_logs" => []];
if (file_exists(DATA_FILE)) {
$data = json_decode(file_get_contents(DATA_FILE), true) ?: $data;
}
if ($action === 'install') {
$data['installs']++;
} elseif ($action === 'login') {
$data['logins']++;
}
array_unshift($data['recent_logs'], [
"action" => $action,
"time" => date("Y-m-d\TH:i:sP"),
]);
$data['recent_logs'] = array_slice($data['recent_logs'], 0, MAX_LOG_ENTRIES);
file_put_contents(DATA_FILE, json_encode($data, JSON_PRETTY_PRINT));
echo json_encode(["status" => "success", "message" => "Counter updated", "action" => $action]);
?>