Skip to content

Commit

Permalink
not bullet proof but good enough
Browse files Browse the repository at this point in the history
  • Loading branch information
4sval committed Aug 7, 2022
1 parent a8c60ac commit 947d501
Show file tree
Hide file tree
Showing 14 changed files with 253 additions and 163 deletions.
79 changes: 67 additions & 12 deletions FModel/Framework/FEndpoint.cs
@@ -1,16 +1,24 @@
namespace FModel.Framework;
using System.Linq;
using FModel.ViewModels.ApiEndpoints;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace FModel.Framework;

public class FEndpoint : ViewModel
{
private string _url;
public string Url
{
get => _url;
set
{
SetProperty(ref _url, value);
RaisePropertyChanged(nameof(IsEnabled));
}
set => SetProperty(ref _url, value);
}

private string _path;
public string Path
{
get => _path;
set => SetProperty(ref _path, value);
}

private bool _overwrite;
Expand All @@ -20,18 +28,65 @@ public bool Overwrite
set => SetProperty(ref _overwrite, value);
}

private string _path;
public string Path
private string _filePath;
public string FilePath
{
get => _path;
set => SetProperty(ref _path, value);
get => _filePath;
set => SetProperty(ref _filePath, value);
}

private bool _isValid;
public bool IsValid
{
get => _isValid;
set
{
SetProperty(ref _isValid, value);
RaisePropertyChanged(nameof(Label));
}
}

public bool IsEnabled => !string.IsNullOrWhiteSpace(_url); // change this later
[JsonIgnore]
public string Label => IsValid ?
"Your endpoint configuration is valid! Please, avoid any unnecessary modifications!" :
"Your endpoint configuration DOES NOT seem to be valid yet! Please, test it out!";

public FEndpoint() {}
public FEndpoint(string url)
public FEndpoint(string url, string path)
{
Url = url;
Path = path;
IsValid = !string.IsNullOrEmpty(url) && !string.IsNullOrEmpty(path); // be careful with this
}

public void TryValidate(DynamicApiEndpoint endpoint, EEndpointType type, out JToken response)
{
response = null;
if (string.IsNullOrEmpty(Url) || string.IsNullOrEmpty(Path))
{
IsValid = false;
}
else switch (type)
{
case EEndpointType.Aes:
{
var r = endpoint.GetAesKeys(default, Url, Path);
response = JToken.FromObject(r);
IsValid = r.IsValid;
break;
}
case EEndpointType.Mapping:
{
var r = endpoint.GetMappings(default, Url, Path);
response = JToken.FromObject(r);
IsValid = r.Any(x => x.IsValid);
break;
}
default:
{
IsValid = false;
break;
}
}
}
}
11 changes: 11 additions & 0 deletions FModel/Helper.cs
Expand Up @@ -21,6 +21,17 @@ public static bool IAmThePanda(string key)
key.StartsWith("mu", StringComparison.OrdinalIgnoreCase) &&
key.EndsWith("sus", StringComparison.OrdinalIgnoreCase);

public static string FixKey(string key)
{
if (string.IsNullOrEmpty(key))
return string.Empty;

if (key.StartsWith("0x"))
key = key[2..];

return "0x" + key.ToUpper().Trim();
}

public static void OpenWindow<T>(string windowName, Action action) where T : Window
{
if (!IsWindowOpen<T>(windowName))
Expand Down
8 changes: 4 additions & 4 deletions FModel/Settings/UserSettings.cs
Expand Up @@ -39,14 +39,14 @@ public static void Delete()
if (File.Exists(FilePath)) File.Delete(FilePath);
}

public static bool IsEndpointEnabled(FGame game, EEndpointType type, out FEndpoint endpoint)
public static bool IsEndpointValid(FGame game, EEndpointType type, out FEndpoint endpoint)
{
endpoint = null;
if (!Default.CustomEndpoints.TryGetValue(game, out var endpoints))
return false;

endpoint = endpoints[(int) type];
return endpoint.IsEnabled;
return endpoint.IsValid;
}

private bool _showChangelog = true;
Expand Down Expand Up @@ -384,8 +384,8 @@ public bool SaveMorphTargets
{
FGame.FortniteGame, new []
{
new FEndpoint("https://fortnitecentral.gmatrixgames.ga/api/v1/aes"),
new FEndpoint("https://fortnitecentral.gmatrixgames.ga/api/v1/mappings")
new FEndpoint("https://fortnitecentral.gmatrixgames.ga/api/v1/aes", "$.['mainKey','dynamicKeys']"),
new FEndpoint("https://fortnitecentral.gmatrixgames.ga/api/v1/mappings", "$.[?(@.meta.compressionMethod=='Oodle')].['url','fileName']")
}
},
{FGame.ShooterGame, new FEndpoint[]{new (), new ()}},
Expand Down
21 changes: 5 additions & 16 deletions FModel/ViewModels/AesManagerViewModel.cs
Expand Up @@ -51,7 +51,7 @@ public async Task InitAes()
DynamicKeys = null
};
_mainKey.Key = FixKey(_keysFromSettings.MainKey);
_mainKey.Key = Helper.FixKey(_keysFromSettings.MainKey);
AesKeys = new FullyObservableCollection<FileItem>(EnumerateAesKeys());
AesKeys.ItemPropertyChanged += AesKeysOnItemPropertyChanged;
AesKeysView = new ListCollectionView(AesKeys) { SortDescriptions = { new SortDescription("Name", ListSortDirection.Ascending) } };
Expand All @@ -63,11 +63,11 @@ private void AesKeysOnItemPropertyChanged(object sender, ItemPropertyChangedEven
if (e.PropertyName != "Key" || sender is not FullyObservableCollection<FileItem> collection)
return;

var key = FixKey(collection[e.CollectionIndex].Key);
var key = Helper.FixKey(collection[e.CollectionIndex].Key);
if (e.CollectionIndex == 0)
{
if (!HasChange)
HasChange = FixKey(_keysFromSettings.MainKey) != key;
HasChange = Helper.FixKey(_keysFromSettings.MainKey) != key;

_keysFromSettings.MainKey = key;
}
Expand All @@ -87,7 +87,7 @@ private void AesKeysOnItemPropertyChanged(object sender, ItemPropertyChangedEven
else if (_keysFromSettings.DynamicKeys.FirstOrDefault(x => x.Guid == collection[e.CollectionIndex].Guid.ToString()) is { } d)
{
if (!HasChange)
HasChange = FixKey(d.Key) != key;
HasChange = Helper.FixKey(d.Key) != key;

d.Key = key;
}
Expand Down Expand Up @@ -117,17 +117,6 @@ public async Task UpdateProvider(bool isLaunch)
Log.Information("{@Json}", UserSettings.Default);
}

private string FixKey(string key)
{
if (string.IsNullOrEmpty(key))
return string.Empty;

if (key.StartsWith("0x"))
key = key[2..];

return "0x" + key.ToUpper().Trim();
}

private IEnumerable<FileItem> EnumerateAesKeys()
{
yield return _mainKey;
Expand All @@ -145,7 +134,7 @@ private IEnumerable<FileItem> EnumerateAesKeys()
k = dynamicKey.Key;
}

file.Key = FixKey(k);
file.Key = Helper.FixKey(k);
yield return file;
}
}
Expand Down
44 changes: 33 additions & 11 deletions FModel/ViewModels/ApiEndpoints/DynamicApiEndpoint.cs
@@ -1,7 +1,9 @@
using System.Threading;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using FModel.Framework;
using FModel.ViewModels.ApiEndpoints.Models;
using Newtonsoft.Json.Linq;
using RestSharp;
using Serilog;

Expand All @@ -13,35 +15,55 @@ public DynamicApiEndpoint(RestClient client) : base(client)
{
}

public async Task<AesResponse> GetAesKeysAsync(CancellationToken token, string url)
public async Task<AesResponse> GetAesKeysAsync(CancellationToken token, string url, string path)
{
var request = new FRestRequest(url)
{
OnBeforeDeserialization = resp => { resp.ContentType = "application/json; charset=utf-8"; }
};
var response = await _client.ExecuteAsync<AesResponse>(request, token).ConfigureAwait(false);
var response = await _client.ExecuteAsync(request, token).ConfigureAwait(false);
var body = JToken.Parse(response.Content!);
Log.Information("[{Method}] [{Status}({StatusCode})] '{Resource}'", request.Method, response.StatusDescription, (int) response.StatusCode, response.ResponseUri?.OriginalString);
return response.Data;

var tokens = body.SelectTokens(path);
var ret = new AesResponse { MainKey = Helper.FixKey(tokens.ElementAtOrDefault(0).ToString()) };
if (tokens.ElementAtOrDefault(1) is JArray dynamicKeys)
{
foreach (var dynamicKey in dynamicKeys)
{
if (dynamicKey["guid"] is not { } guid || dynamicKey["key"] is not { } key)
continue;

ret.DynamicKeys.Add(new DynamicKey{Guid = guid.ToString(), Key = Helper.FixKey(key.ToString())});
}
}
return ret;
}

public AesResponse GetAesKeys(CancellationToken token, string url)
public AesResponse GetAesKeys(CancellationToken token, string url, string path)
{
return GetAesKeysAsync(token, url).GetAwaiter().GetResult();
return GetAesKeysAsync(token, url, path).GetAwaiter().GetResult();
}

public async Task<MappingsResponse[]> GetMappingsAsync(CancellationToken token, string url)
public async Task<MappingsResponse[]> GetMappingsAsync(CancellationToken token, string url, string path)
{
var request = new FRestRequest(url)
{
OnBeforeDeserialization = resp => { resp.ContentType = "application/json; charset=utf-8"; }
};
var response = await _client.ExecuteAsync<MappingsResponse[]>(request, token).ConfigureAwait(false);
var response = await _client.ExecuteAsync(request, token).ConfigureAwait(false);
var body = JToken.Parse(response.Content!);
Log.Information("[{Method}] [{Status}({StatusCode})] '{Resource}'", request.Method, response.StatusDescription, (int) response.StatusCode, response.ResponseUri?.OriginalString);
return response.Data;

var tokens = body.SelectTokens(path);
var ret = new MappingsResponse[] {new()};
ret[0].Url = tokens.ElementAtOrDefault(0).ToString();
ret[0].FileName = tokens.ElementAtOrDefault(1).ToString();
return ret;
}

public MappingsResponse[] GetMappings(CancellationToken token, string url)
public MappingsResponse[] GetMappings(CancellationToken token, string url, string path)
{
return GetMappingsAsync(token, url).GetAwaiter().GetResult();
return GetMappingsAsync(token, url, path).GetAwaiter().GetResult();
}
}
5 changes: 2 additions & 3 deletions FModel/ViewModels/ApiEndpoints/Models/AesResponse.cs
Expand Up @@ -19,7 +19,7 @@ public AesResponse()
}

[I] public bool HasDynamicKeys => DynamicKeys is { Count: > 0 };
[I] public bool IsValid => !string.IsNullOrEmpty(MainKey);
[I] public bool IsValid => MainKey.Length == 66;
}

[DebuggerDisplay("{" + nameof(Key) + "}")]
Expand All @@ -29,6 +29,5 @@ public class DynamicKey
[J("guid")] public string Guid { get; set; }
[J("key")] public string Key { get; set; }

[I] public bool IsValid => !string.IsNullOrEmpty(Guid) &&
!string.IsNullOrEmpty(Key);
[I] public bool IsValid => Guid.Length == 32 && Key.Length == 66;
}
10 changes: 1 addition & 9 deletions FModel/ViewModels/ApiEndpoints/Models/MappingsResponse.cs
Expand Up @@ -22,20 +22,12 @@ public MappingsResponse()
}

[I] public bool IsValid => !string.IsNullOrEmpty(Url) &&
!string.IsNullOrEmpty(FileName) &&
Meta != null;
!string.IsNullOrEmpty(FileName);
}

[DebuggerDisplay("{" + nameof(CompressionMethod) + "}")]
public class Meta
{
[I][J] public string Version { get; private set; }
[J] public string CompressionMethod { get; set; }

public Meta()
{
CompressionMethod = "Oodle";
}

[I] public bool IsValid => CompressionMethod == "Oodle";
}
16 changes: 8 additions & 8 deletions FModel/ViewModels/CUE4ParseViewModel.cs
Expand Up @@ -295,12 +295,12 @@ public async Task RefreshAes()
{
// game directory dependent, we don't have the provider game name yet since we don't have aes keys
// except when this comes from the AES Manager
if (!UserSettings.IsEndpointEnabled(Game, EEndpointType.Aes, out var endpoint))
if (!UserSettings.IsEndpointValid(Game, EEndpointType.Aes, out var endpoint))
return;

await _threadWorkerView.Begin(cancellationToken =>
{
var aes = _apiEndpointView.DynamicApi.GetAesKeys(cancellationToken, endpoint.Url);
var aes = _apiEndpointView.DynamicApi.GetAesKeys(cancellationToken, endpoint.Url, endpoint.Path);
if (aes is not { IsValid: true }) return;
UserSettings.Default.AesKeys[Game] = aes;
Expand All @@ -323,26 +323,26 @@ public async Task InitInformation()

public async Task InitBenMappings()
{
if (!UserSettings.IsEndpointEnabled(Game, EEndpointType.Mapping, out var endpoint))
if (!UserSettings.IsEndpointValid(Game, EEndpointType.Mapping, out var endpoint))
return;

await _threadWorkerView.Begin(cancellationToken =>
{
if (endpoint.Overwrite && File.Exists(endpoint.Path))
if (endpoint.Overwrite && File.Exists(endpoint.FilePath))
{
Provider.MappingsContainer = new FileUsmapTypeMappingsProvider(endpoint.Path);
Provider.MappingsContainer = new FileUsmapTypeMappingsProvider(endpoint.FilePath);
FLogger.AppendInformation();
FLogger.AppendText($"Mappings pulled from '{endpoint.Path.SubstringAfterLast("\\")}'", Constants.WHITE, true);
FLogger.AppendText($"Mappings pulled from '{endpoint.FilePath.SubstringAfterLast("\\")}'", Constants.WHITE, true);
}
else
{
var mappingsFolder = Path.Combine(UserSettings.Default.OutputDirectory, ".data");
var mappings = _apiEndpointView.DynamicApi.GetMappings(cancellationToken, endpoint.Url);
var mappings = _apiEndpointView.DynamicApi.GetMappings(cancellationToken, endpoint.Url, endpoint.Path);
if (mappings is { Length: > 0 })
{
foreach (var mapping in mappings)
{
if (!mapping.IsValid || !mapping.Meta.IsValid) continue;
if (!mapping.IsValid) continue;
var mappingPath = Path.Combine(mappingsFolder, mapping.FileName);
if (!File.Exists(mappingPath))
Expand Down
6 changes: 0 additions & 6 deletions FModel/ViewModels/SettingsViewModel.cs
Expand Up @@ -324,12 +324,6 @@ public SettingsOut Save()
UserSettings.Default.OverridedOptions[_game] = SelectedOptions;
}

if (UserSettings.Default.CustomEndpoints.TryGetValue(_game, out var endpoints))
{
endpoints[0] = AesEndpoint;
endpoints[1] = MappingEndpoint;
}

UserSettings.Default.AssetLanguage = SelectedAssetLanguage;
UserSettings.Default.CompressedAudioMode = SelectedCompressedAudio;
UserSettings.Default.CosmeticStyle = SelectedCosmeticStyle;
Expand Down

0 comments on commit 947d501

Please sign in to comment.