Files
Encelado/DesktopBot/Services/CredentialService.cs
T
2026-06-09 18:29:41 +02:00

100 lines
3.6 KiB
C#

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace DesktopBot.Services
{
/// <summary>
/// Gestisce il salvataggio e il caricamento sicuro delle credenziali Alpaca.
/// Cifra con AES-256 usando una chiave derivata da MachineName + UserName.
/// </summary>
public static class CredentialService
{
private static readonly string SettingsFolder =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "TradingBot");
private static readonly string CredentialsFile =
Path.Combine(SettingsFolder, "credentials.dat");
private static byte[] DeriveKey()
{
var seed = Environment.MachineName + Environment.UserName + "TradingBotSalt_v1";
using (var sha = SHA256.Create())
return sha.ComputeHash(Encoding.UTF8.GetBytes(seed));
}
public static void SaveCredentials(string apiKey, string apiSecret, bool isPaper)
{
if (!Directory.Exists(SettingsFolder))
Directory.CreateDirectory(SettingsFolder);
var plainText = apiKey + "|" + apiSecret + "|" + isPaper;
var plainBytes = Encoding.UTF8.GetBytes(plainText);
var key = DeriveKey();
using (var aes = Aes.Create())
{
aes.Key = key;
aes.GenerateIV();
using (var ms = new MemoryStream())
{
ms.Write(aes.IV, 0, aes.IV.Length);
using (var cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
cs.Write(plainBytes, 0, plainBytes.Length);
File.WriteAllBytes(CredentialsFile, ms.ToArray());
}
}
}
public static AlpacaCredentials LoadCredentials()
{
if (!File.Exists(CredentialsFile))
return null;
try
{
var data = File.ReadAllBytes(CredentialsFile);
var key = DeriveKey();
using (var aes = Aes.Create())
{
aes.Key = key;
var iv = new byte[16];
Array.Copy(data, 0, iv, 0, 16);
aes.IV = iv;
using (var ms = new MemoryStream(data, 16, data.Length - 16))
using (var cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Read))
using (var reader = new StreamReader(cs, Encoding.UTF8))
{
var plain = reader.ReadToEnd();
var parts = plain.Split('|');
if (parts.Length != 3) return null;
return new AlpacaCredentials
{
ApiKey = parts[0],
ApiSecret = parts[1],
IsPaper = bool.Parse(parts[2])
};
}
}
}
catch { return null; }
}
public static bool HasCredentials() => File.Exists(CredentialsFile);
public static void DeleteCredentials()
{
if (File.Exists(CredentialsFile))
File.Delete(CredentialsFile);
}
}
/// <summary>Modello credenziali Alpaca</summary>
public class AlpacaCredentials
{
public string ApiKey { get; set; }
public string ApiSecret { get; set; }
public bool IsPaper { get; set; }
}
}