Files
Barış Keser 83be058d23 feat: Athena v2 — Discord auth, AthenaCore mod, cross-platform launcher, CI
Backend (PHP+SQLite): Discord OAuth2 + JWT, coklu hesap (1 Discord = 3-5),
tek-kullanimlik join token (/api/join/prepare+verify), custom skin yukleme/sunma,
hesap/Discord/HWID ban, admin paneli kartlari; deterministik offline UUID (PHP<->C#
paritesi dogrulandi). 25 entegrasyon testi gecti.

AthenaCore (Forge 1.12.2): tek client+server mod — join token dogrulama + kick,
grace-gate, custom skin uygulama. Sunucu offline-mode kalir (UUID/dunya verisi korunur).

Masaustu: WPF -> Avalonia (Windows+Linux), Discord giris/hesap/skin/oyna; WMI/DPAPI
yerine cross-platform (machine-id HWID, AES-GCM secret store). Derlenir + calisir.

CI: athenacore-mod.yml (JDK8), desktop-release.yml (Win+Linux self-contained).
Deploy: deploy.sh (.env uretimi, php-gd, nginx Authorization gecisi) + HANDOFF.md.
Android: backend hazir; entegrasyon spec'i ANDROID_INTEGRATION.md.
2026-06-13 23:45:21 +03:00

100 lines
3.3 KiB
C#

using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
namespace OfflineMinecraftLauncher.Services;
/// <summary>Cross-platform machine info (replaces the Windows-only WMI calls).</summary>
public static class PlatformInfo
{
/// <summary>
/// Stable per-machine (or per-install) hardware id, MD5-hex like the legacy
/// launcher so the backend's HWID ban list keeps working. Uses /etc/machine-id
/// on Linux and a persisted GUID file otherwise.
/// </summary>
public static string GetHwid()
{
try
{
string? raw = null;
foreach (var p in new[] { "/etc/machine-id", "/var/lib/dbus/machine-id" })
{
if (File.Exists(p))
{
var v = File.ReadAllText(p).Trim();
if (!string.IsNullOrWhiteSpace(v)) { raw = v; break; }
}
}
if (string.IsNullOrWhiteSpace(raw))
raw = PersistedMachineGuid();
using var md5 = MD5.Create();
return Convert.ToHexString(md5.ComputeHash(Encoding.ASCII.GetBytes(raw!))).ToLowerInvariant();
}
catch { return "UNKNOWN_HWID"; }
}
private static string PersistedMachineGuid()
{
var dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), AppConfig.AppDataFolder);
Directory.CreateDirectory(dir);
var f = Path.Combine(dir, "machine.id");
if (File.Exists(f))
{
var v = File.ReadAllText(f).Trim();
if (!string.IsNullOrWhiteSpace(v)) return v;
}
var g = Guid.NewGuid().ToString("N");
File.WriteAllText(f, g);
return g;
}
public static long GetTotalRamMb()
{
try
{
if (OperatingSystem.IsLinux() && File.Exists("/proc/meminfo"))
{
foreach (var line in File.ReadLines("/proc/meminfo"))
{
if (line.StartsWith("MemTotal:", StringComparison.Ordinal))
{
var parts = line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length >= 2 && long.TryParse(parts[1], out var kb))
return kb / 1024;
}
}
}
var info = GC.GetGCMemoryInfo();
if (info.TotalAvailableMemoryBytes > 0)
return info.TotalAvailableMemoryBytes / 1024 / 1024;
}
catch { }
return 0;
}
public static string GetCpu()
{
try
{
if (OperatingSystem.IsLinux() && File.Exists("/proc/cpuinfo"))
{
var model = File.ReadLines("/proc/cpuinfo")
.FirstOrDefault(l => l.StartsWith("model name", StringComparison.OrdinalIgnoreCase));
if (model != null)
{
var idx = model.IndexOf(':');
if (idx >= 0) return model[(idx + 1)..].Trim();
}
}
}
catch { }
// Reasonable cross-platform fallback.
var arch = RuntimeInformation.ProcessArchitecture.ToString();
return $"{arch} ({Environment.ProcessorCount} cores)";
}
}