分离玩家信息插件,以及更新检测

This commit is contained in:
2021-10-22 08:54:04 +02:00
parent 2a96f8efac
commit 08700abd4f
25 changed files with 860 additions and 234 deletions

27
Utils/Network.cs Normal file
View File

@@ -0,0 +1,27 @@
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
namespace AnotherReplayReader.Utils
{
public static class Network
{
public static readonly JsonSerializerOptions CommonJsonOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
public static string UrlEncode(string text) => HttpUtility.UrlEncode(text);
public static async Task<T?> HttpGetJson<T>(string url,
CancellationToken cancelToken = default)
{
using var client = new HttpClient();
using var response = await client.GetAsync(url, cancelToken).ConfigureAwait(false);
using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
return await JsonSerializer.DeserializeAsync<T>(stream, CommonJsonOptions, cancelToken).ConfigureAwait(false);
}
}
}

View File

@@ -3,15 +3,15 @@ using System;
namespace AnotherReplayReader.Utils
{
internal static class RegistryUtils
public static class RegistryUtils
{
public static string? Retrieve(RegistryHive hive, string path, string value)
public static string? Retrieve32(RegistryHive hive, string path, string value)
{
try
{
using var view32 = RegistryKey.OpenBaseKey(hive, RegistryView.Registry32);
using var ra3Key = view32.OpenSubKey(path, false);
return ra3Key?.GetValue(value) as string;
using var key = view32.OpenSubKey(path, false);
return key?.GetValue(value) as string;
}
catch (Exception e)
{
@@ -20,9 +20,24 @@ namespace AnotherReplayReader.Utils
}
}
public static string? RetrieveInHklm64(string path, string value)
{
try
{
using var view64 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
using var key = view64?.OpenSubKey(path, false);
return key?.GetValue(value) as string;
}
catch (Exception e)
{
Debug.Instance.DebugMessage += $"Failed to retrieve registy HKLM64:{path}:{value}: {e}";
return null;
}
}
public static string? RetrieveInRa3(RegistryHive hive, string value)
{
return Retrieve(hive, @"Software\Electronic Arts\Electronic Arts\Red Alert 3", value);
return Retrieve32(hive, @"Software\Electronic Arts\Electronic Arts\Red Alert 3", value);
}
}
}

View File

@@ -21,8 +21,9 @@ namespace AnotherReplayReader.Utils
using var locker = new Lock(_lock);
_current = _current.ContinueWith(async t =>
{
await _dispatcher.InvokeAsync(getTask, DispatcherPriority.Background, cancelToken);
}, cancelToken);
var task = await _dispatcher.InvokeAsync(getTask, DispatcherPriority.Background, cancelToken);
await task.ConfigureAwait(false);
}, cancelToken).Unwrap();
return _current.IgnoreCancel();
}

115
Utils/Verifier.cs Normal file
View File

@@ -0,0 +1,115 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Windows;
namespace AnotherReplayReader.Utils
{
internal class VerifierPayload
{
public string Data { get; }
public string Signature { get; }
[JsonIgnore]
public Lazy<byte[]> ByteData { get; }
[JsonIgnore]
public Lazy<byte[]> ByteSignature { get; }
public VerifierPayload(string data, string signature)
{
Data = data;
Signature = signature;
ByteData = new(() => Convert.FromBase64String(Data),
LazyThreadSafetyMode.PublicationOnly);
ByteSignature = new(() => Convert.FromBase64String(Signature),
LazyThreadSafetyMode.PublicationOnly);
}
public static VerifierPayload FromBytes(byte[] data, byte[] signature)
{
return new(Convert.ToBase64String(data), Convert.ToBase64String(signature));
}
}
internal class Verifier
{
private const string _publicKey = @"<RSAKeyValue><Modulus>3vw5CoFRDFt2ri4jLDTu75cw1U/tCRjya7q8X/IdULaOJOYG8C+uqrF2Atb4ou+4SrmF+bvJM9cFsf3yO7XpeIDpkxD3KGbIEw+0JixTIIm+y5xlLKDDwbZHnYjJOBTt6JBn0yqwx7vY2UEZIcRU6wlOmUapnkpiaC2anNhSPqk=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
public static bool Verify(VerifierPayload payload)
{
using var rsa = new RSACng();
rsa.FromXmlString(_publicKey);
return rsa.VerifyData(payload.ByteData.Value, payload.ByteSignature.Value, HashAlgorithmName.SHA256, RSASignaturePadding.Pss);
}
public static void Sign(object sample)
{
var fileName = Path.GetTempFileName();
try
{
var ea = Enumerable.Repeat<byte>(0xEA, 1024).ToArray();
const string splitter = "|DuplexBarrier|";
var isByteArray = false;
if (sample is string sampleText)
{
File.WriteAllText(fileName, $"输入私钥信息以及需要签名的数据,用 `{splitter}` 分开\r\n\r\n{sampleText}");
}
else if (sample is byte[] readyArray)
{
isByteArray = true;
File.WriteAllText(fileName, $"输入私钥信息以及需要签名的数据{splitter}{Convert.ToBase64String(readyArray)}{splitter}");
}
using (var process = Process.Start("notepad.exe", fileName))
{
process.WaitForExit();
}
var splitted = File.ReadAllText(fileName).Split(new[] { splitter }, StringSplitOptions.RemoveEmptyEntries);
File.WriteAllBytes(fileName, ea);
byte[] bytes;
byte[] signature;
using (var rsa = new RSACng())
{
rsa.FromXmlString(splitted[0]);
var text = splitted[1];
splitted = null;
GC.Collect();
MessageBox.Show(text, $"快来确认一下~");
bytes = isByteArray
? Convert.FromBase64String(text)
: Encoding.UTF8.GetBytes(text);
signature = rsa.SignData(bytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pss);
}
GC.Collect();
var payload = VerifierPayload.FromBytes(bytes, signature);
var serialized = JsonSerializer.Serialize(payload, Network.CommonJsonOptions);
var choice = MessageBox.Show(serialized, "嗯哼", MessageBoxButton.YesNo);
while (choice == MessageBoxResult.Yes)
{
File.WriteAllText(fileName, serialized);
using (var process = Process.Start("notepad.exe", fileName))
{
process.WaitForExit();
}
using var rsa = new RSACng();
rsa.FromXmlString(_publicKey);
var checkContent = File.ReadAllText(fileName);
var check = JsonSerializer.Deserialize<VerifierPayload>(checkContent, Network.CommonJsonOptions) ?? new("", "");
var checkData = Convert.FromBase64String(check.Data);
var checkSignature = Convert.FromBase64String(check.Signature);
var verified = rsa.VerifyData(checkData, checkSignature, HashAlgorithmName.SHA256, RSASignaturePadding.Pss);
choice = MessageBox.Show($"结果:{verified}", "嗯哼", MessageBoxButton.YesNo);
}
}
finally
{
File.Delete(fileName);
}
}
}
}

29
Utils/WpfExtensions.cs Normal file
View File

@@ -0,0 +1,29 @@
using System.Collections.Generic;
using System.Windows;
namespace AnotherReplayReader.Utils
{
internal static class WpfExtensions
{
public static IEnumerable<T> FindVisualChildren<T>(this DependencyObject depObj) where T : DependencyObject
{
foreach (var x in LogicalTreeHelper.GetChildren(depObj))
{
if (x is not DependencyObject child)
{
continue;
}
if (child is T tchild)
{
yield return tchild;
}
foreach (var childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
}