分离玩家信息插件,以及更新检测
This commit is contained in:
27
Utils/Network.cs
Normal file
27
Utils/Network.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
115
Utils/Verifier.cs
Normal 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
29
Utils/WpfExtensions.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user