100 lines
3.6 KiB
C#
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; }
|
|
}
|
|
}
|