mirror of
https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies.git
synced 2026-07-25 06:14:31 +00:00
a9fdb58cac
Several methods were added and modified in `Storage.cs`, `MainVM_Groups.cs`, `MainVM_Proxy.cs`, and `ProxyManagerVM.cs` to validate if the data can be saved before performing various operations. The `SnackbarController.cs` was modified to increase the minimum snackbar time and adjust the duration calculation. In `MafileSerializer_SessionData.cs`, the check for whether the refresh token is expired or not was moved to a different location within the code. New localization entries were added in `localization.loc.json`. The changes are as follows: 1. Added a new HTML file `changelog\1.4.8.html` to the project `NebulaAuth.sln`. 2. Added a new converter `ProxyDataTextConverter` to `App.xaml`. 3. Imported `AchiesUtilities.Web.Proxy` in `ProxyTextConverter.cs`. 4. Modified the return string in `ProxyTextConverter` to include the port number. 5. Added a new class `ProxyDataTextConverter` in `ProxyTextConverter.cs`. 6. Increased the minimum snackbar time from 1000 to 1200 in `SnackbarController.cs`. 7. Modified the duration calculation in `GetSnackbarTime` method in `SnackbarController.cs`. 8. Added tooltips to ComboBoxes in `MainWindow.xaml`. 9. Added a new method `ValidateCanSave` in `Storage.cs` to validate if the data can be saved. 10. Added a new method `GetProxyString` in `ProxyStorage.cs` to get the proxy string. 11. Modified the `CompareProxy` method in `ProxyStorage.cs` to compare the address and port of the proxy data. 12. Removed a logger info line in `Shell.cs`. 13. Added a new property `DuplicateFound` in `Storage.cs`. 14. Modified the `CreatePathForMafile` method in `Storage.cs` to create a file name based on the account name or steam id. 15. Modified the `AddGroup` method in `MainVM_Groups.cs` to validate if the data can be saved before adding a group. 16. Modified the `AddToGroup` method in `MainVM_Groups.cs` to validate if the data can be saved before adding to a group. 17. Modified the `RemoveGroup` method in `MainVM_Groups.cs` to validate if the data can be saved before removing a group. 18. Modified the `PerformQuery` method in `MainVM_Groups.cs` to set `SelectedMafile` to the first item in `MaFiles`. 19. Modified the `RemoveProxy` method in `MainVM_Proxy.cs` to validate if the data can be saved before removing a proxy. 20. Modified the `SelectedProxyChanged` method in `MainVM_Proxy.cs` to validate if the data can be saved before changing the selected proxy. 21. Added a new method `ValidateCanSaveAndWarn` in `MainVM_Proxy.cs` to validate if the data can be saved and send a snackbar message if it can't. 22. Modified the `TimerCheckSeconds` property in `MainVM_Timer.cs` to send a snackbar message when the timer is changed. 23. Added a new method `RemoveProxy` in `LoginAgainOnImportVM.cs` to remove the selected proxy. 24. Modified the `AddProxy` method in `ProxyManagerVM.cs` to use the `DefaultScheme` to parse the proxy data. 25. Modified the `AddProxy` method in `ProxyManagerVM.cs` to use the `DefaultScheme` to parse the proxy data and get the proxy string. 26. Modified the `CopyProxy` method in `ProxyManagerVM.cs` to get the proxy string. 27. Added new localization entries in `localization.loc.json`. 28. The `update.xml` file was updated to reflect the new version of the software (1.4.8.0) and the corresponding download URL and changelog URL were updated accordingly. 29. In `AdmissionHelper.cs`, a new constant `SESSION_ID_COOKIE_NAME` was added to replace hardcoded "sessionid" strings. The same was done for `LANGUAGE_COOKIE_NAME` replacing "Steam_Language". This change was reflected in multiple methods within the `AdmissionHelper` class. 30. A new method `CloneCookie` was added to `AdmissionHelper.cs` to create a copy of a given cookie. This method was then used to replace repetitive code in the `TransferCommunityCookies` method. 31. In `MafileSerializer_SessionData.cs`, the check for whether the refresh token is expired or not was moved to a different location within the code. This change does not affect the functionality but may improve readability or maintainability of the code.
307 lines
9.5 KiB
C#
307 lines
9.5 KiB
C#
using NebulaAuth.Model.Entities;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Linq;
|
|
using SteamLib;
|
|
using SteamLib.Account;
|
|
using SteamLib.Exceptions;
|
|
using SteamLib.SteamMobile;
|
|
using SteamLib.Utility.MaFiles;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.DirectoryServices.ActiveDirectory;
|
|
using System.IO;
|
|
using System.Linq;
|
|
|
|
namespace NebulaAuth.Model;
|
|
|
|
public static class Storage
|
|
{
|
|
public const string MAFILE_F = "maFiles";
|
|
public const string REMOVED_F = "maFiles_removed";
|
|
|
|
public static string MafileFolder { get; } = Path.GetFullPath(MAFILE_F);
|
|
public static string RemovedMafileFolder { get; } = Path.GetFullPath(REMOVED_F);
|
|
|
|
public static ObservableCollection<Mafile> MaFiles { get; } = new();
|
|
|
|
public static readonly int DuplicateFound;
|
|
static Storage()
|
|
{
|
|
if (Directory.Exists(MafileFolder) == false)
|
|
{
|
|
Directory.CreateDirectory(MafileFolder);
|
|
}
|
|
|
|
if (Directory.Exists(RemovedMafileFolder) == false)
|
|
{
|
|
Directory.CreateDirectory(RemovedMafileFolder);
|
|
}
|
|
|
|
var files = Directory.GetFiles(MafileFolder);
|
|
var hashNames = new HashSet<string>();
|
|
var hashIds = new HashSet<SteamId>();
|
|
var comparer = new MafileNameComparer(Settings.Instance.UseAccountNameAsMafileName);
|
|
var ordered = files.Order(comparer).ToList();
|
|
foreach (var file in ordered)
|
|
{
|
|
if (Path.GetExtension(file).Equals(".mafile", StringComparison.OrdinalIgnoreCase) == false) continue;
|
|
try
|
|
{
|
|
var data = ReadMafile(file);
|
|
|
|
if (hashNames.Contains(data.AccountName) || (data.SessionData != null && hashIds.Contains(data.SessionData.SteamId)))
|
|
{
|
|
DuplicateFound++;
|
|
Shell.Logger.Error("Duplicate mafile {file}", Path.GetFileName(file));
|
|
continue;
|
|
}
|
|
hashNames.Add(data.AccountName);
|
|
if (data.SessionData != null) hashIds.Add(data.SessionData.SteamId);
|
|
MaFiles.Add(data);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Shell.Logger.Error(ex, "Can't load mafile {file}", Path.GetFileName(file));
|
|
}
|
|
}
|
|
|
|
MaFiles = new ObservableCollection<Mafile>(MaFiles.OrderBy(m => m.AccountName));
|
|
}
|
|
|
|
|
|
public static void AddNewMafile(string path, bool overwrite)
|
|
{
|
|
Mafile data;
|
|
try
|
|
{
|
|
data = ReadMafile(path);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Shell.Logger.Warn(ex, "Can't load mafile");
|
|
throw new FormatException("File data is not valid", ex);
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(data.AccountName))
|
|
throw new FormatException("File data is not valid. Missing AccountName");
|
|
|
|
try
|
|
{
|
|
var code = SteamGuardCodeGenerator.GenerateCode(data.SharedSecret);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new FormatException("Can't generate code on this mafile", ex);
|
|
}
|
|
|
|
|
|
if (data.SessionData == null)
|
|
throw new SessionInvalidException("File data is not valid. Missing SessionData")
|
|
{
|
|
Data = { { "mafile", data } }
|
|
};
|
|
|
|
|
|
if (overwrite == false && File.Exists(CreatePathForMafile(data)))
|
|
{
|
|
throw new IOException("File already exist and overwrite is False");
|
|
}
|
|
|
|
|
|
SaveMafile(data);
|
|
}
|
|
|
|
|
|
public static Mafile ReadMafile(string path)
|
|
{
|
|
var str = File.ReadAllText(path);
|
|
var mafile = MafileSerializer.Deserialize(str, out var mafileData);
|
|
if (mafileData.IsExtended == false)
|
|
throw new FormatException("Mafile is not extended data");
|
|
|
|
|
|
var props = mafileData.UnusedProperties ?? new Dictionary<string, JProperty>();
|
|
var proxy = GetPropertyValue<MaProxy>("Proxy", props);
|
|
var group = GetPropertyValue<string>("Group", props);
|
|
var password = GetPropertyValue<string>("Password", props);
|
|
return Mafile.FromMobileDataExtended((MobileDataExtended)mafile, proxy, group, password);
|
|
}
|
|
|
|
public static string SerializeMafile(Mafile data)
|
|
{
|
|
var props = new Dictionary<string, object?>
|
|
{
|
|
{nameof(Mafile.Proxy), data.Proxy},
|
|
{nameof(Mafile.Group), data.Group},
|
|
{nameof(Mafile.Password), data.Password}
|
|
};
|
|
return SerializeMafile(data, props);
|
|
}
|
|
|
|
public static string SerializeMafile(MobileDataExtended data, Dictionary<string, object?>? properties)
|
|
{
|
|
if (Settings.Instance.LegacyMode)
|
|
{
|
|
return MafileSerializer.SerializeLegacy(data, Formatting.Indented, properties);
|
|
}
|
|
else
|
|
{
|
|
return MafileSerializer.Serialize(data);
|
|
}
|
|
}
|
|
|
|
|
|
private static T? GetPropertyValue<T>(string name, Dictionary<string, JProperty> dictionary)
|
|
{
|
|
if (dictionary.TryGetValue(name, out var prop) == false) return default;
|
|
var value = prop.Value;
|
|
try
|
|
{
|
|
return value.ToObject<T>();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Shell.Logger.Warn(ex, "Can't deserialize property {name}", name);
|
|
return default;
|
|
}
|
|
}
|
|
|
|
public static void SaveMafile(Mafile data)
|
|
{
|
|
var path = CreatePathForMafile(data);
|
|
var str = SerializeMafile(data);
|
|
File.WriteAllText(Path.GetFullPath(path), str);
|
|
|
|
var existed = MaFiles.SingleOrDefault(m => m.AccountName == data.AccountName);
|
|
if (existed != null)
|
|
{
|
|
var index = MaFiles.IndexOf(existed);
|
|
MaFiles[index] = data;
|
|
}
|
|
else
|
|
{
|
|
MaFiles.Add(data);
|
|
}
|
|
}
|
|
|
|
public static void UpdateMafile(Mafile data)
|
|
{
|
|
var path = CreatePathForMafile(data);
|
|
var str = SerializeMafile(data);
|
|
File.WriteAllText(Path.GetFullPath(path), str);
|
|
}
|
|
|
|
public static void RemoveMafile(Mafile data)
|
|
{
|
|
var path = CreatePathForMafile(data);
|
|
if (File.Exists(path))
|
|
{
|
|
File.Delete(path);
|
|
}
|
|
MaFiles.Remove(data);
|
|
}
|
|
public static void MoveToRemoved(Mafile data)
|
|
{
|
|
var path = CreatePathForMafile(data);
|
|
var copyPath = Path.Combine(REMOVED_F, data.SessionData!.SteamId + ".mafile");
|
|
var copyPathCompleted = copyPath;
|
|
var i = 0;
|
|
while (File.Exists(copyPathCompleted))
|
|
{
|
|
i++;
|
|
copyPathCompleted = copyPath + $" ({i})";
|
|
}
|
|
File.Copy(path, copyPathCompleted, false);
|
|
File.Delete(path);
|
|
MaFiles.Remove(data);
|
|
}
|
|
|
|
private static string CreatePathForMafile(Mafile data)
|
|
{
|
|
string fileName;
|
|
if (Settings.Instance.UseAccountNameAsMafileName)
|
|
{
|
|
fileName = CreateFileNameWithAccountName(data.AccountName);
|
|
}
|
|
else
|
|
{
|
|
if(data.SessionData == null)
|
|
throw new NullReferenceException("SessionData was null can't retrieve SteamId"); //FIXME: think about better way to handle
|
|
|
|
fileName = CreateFileNameWithSteamId(data.SessionData.SteamId);
|
|
}
|
|
|
|
return Path.Combine(MafileFolder, fileName);
|
|
}
|
|
|
|
private static string CreateFileNameWithAccountName(string accountName) => accountName + ".mafile";
|
|
private static string CreateFileNameWithSteamId(SteamId steamId) => steamId.Steam64.Id + ".mafile";
|
|
|
|
public static string? TryFindMafilePath(Mafile data)
|
|
//FIXME: write mode to mafile instead of searching it. Search sometimes represents not actual mafile (in case of duplicate steamId + accountName)
|
|
{
|
|
var pathFileName = Path.Combine(MafileFolder, CreateFileNameWithAccountName(data.AccountName));
|
|
string? pathSteamId = null;
|
|
if (data.SessionData != null)
|
|
{
|
|
pathSteamId = Path.Combine(MafileFolder, CreateFileNameWithSteamId(data.SessionData.SteamId));
|
|
}
|
|
|
|
var steamIdExist = pathSteamId != null && File.Exists(pathSteamId);
|
|
var accountNameExist = File.Exists(pathFileName);
|
|
|
|
if (steamIdExist && accountNameExist)
|
|
{
|
|
return Settings.Instance.UseAccountNameAsMafileName ? pathFileName : pathSteamId;
|
|
}
|
|
if (steamIdExist ^ accountNameExist)
|
|
{
|
|
return steamIdExist ? pathSteamId : pathFileName;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static bool ValidateCanSave(Mafile data)
|
|
{
|
|
return Settings.Instance.UseAccountNameAsMafileName || data.SessionData != null;
|
|
}
|
|
}
|
|
|
|
internal class MafileNameComparer : IComparer<string>
|
|
{
|
|
public bool MafileNameMode { get; }
|
|
private const string MAF_64_START = "765";
|
|
private static readonly IComparer<string> _defaultComparer = Comparer<string>.Default;
|
|
public MafileNameComparer(bool mafileNameMode)
|
|
{
|
|
MafileNameMode = mafileNameMode;
|
|
}
|
|
|
|
|
|
public int Compare(string? x, string? y)
|
|
{
|
|
if (x == null && y == null) return 0;
|
|
if (x == null) return -1;
|
|
if (y == null) return 1;
|
|
|
|
|
|
bool xisSteamId = Path.GetFileName(x).StartsWith(MAF_64_START);
|
|
bool yisSteamId = Path.GetFileName(y).StartsWith(MAF_64_START);
|
|
|
|
if (xisSteamId ^ yisSteamId)
|
|
{
|
|
if (MafileNameMode)
|
|
{
|
|
return xisSteamId ? 1 : -1;
|
|
}
|
|
else
|
|
{
|
|
return yisSteamId ? 1 : -1;
|
|
}
|
|
}
|
|
|
|
return _defaultComparer.Compare(x, y);
|
|
}
|
|
|
|
} |