using System;
using System.Text.Json;
namespace Elfisa.Core;
/// Текущая сессия пользователя (токен, роль, логин). Сохраняется между запусками.
public sealed class Session
{
public static Session Current { get; } = new();
public string? Token { get; set; }
public string? Role { get; set; }
public string? Username { get; set; }
public bool IsAuthenticated => !string.IsNullOrWhiteSpace(Token);
/// Сохранить сессию в настройки (чтобы не логиниться каждый раз).
public void Save()
{
SettingsStore.Current.Token = Token;
SettingsStore.Current.Role = Role;
SettingsStore.Current.Username = Username;
SettingsStore.Save();
}
/// Восстановить сессию из настроек, если токен есть и не истёк.
public static bool TryRestore()
{
var s = SettingsStore.Current;
if (string.IsNullOrWhiteSpace(s.Token) || IsJwtExpired(s.Token))
return false;
Current.Token = s.Token;
Current.Role = s.Role;
Current.Username = s.Username;
return true;
}
public void Clear()
{
Token = null;
Role = null;
Username = null;
SettingsStore.Current.Token = null;
SettingsStore.Current.Role = null;
SettingsStore.Current.Username = null;
SettingsStore.Save();
}
/// Проверяет, истёк ли JWT (по claim exp), с запасом в 1 минуту.
private static bool IsJwtExpired(string token)
{
try
{
var parts = token.Split('.');
if (parts.Length != 3) return true;
var payload = parts[1].Replace('-', '+').Replace('_', '/');
switch (payload.Length % 4)
{
case 2: payload += "=="; break;
case 3: payload += "="; break;
}
var json = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(payload));
using var doc = JsonDocument.Parse(json);
if (doc.RootElement.TryGetProperty("exp", out var exp) && exp.TryGetInt64(out var expUnix))
return DateTimeOffset.UtcNow.ToUnixTimeSeconds() >= expUnix - 60;
return false; // нет exp — считаем валидным
}
catch { return true; }
}
}