mirror of
https://github.com/ezhevita/YandexKeyExtractor
synced 2025-08-16 19:40:48 +07:00
update to .net 8
This commit is contained in:
6
.editorconfig
Normal file
6
.editorconfig
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[*.cs]
|
||||||
|
max_line_length = 130
|
||||||
|
charset = utf-8
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_style = tab
|
||||||
|
trim_trailing_whitespace = true
|
||||||
8
.github/workflows/dotnet.yml
vendored
8
.github/workflows/dotnet.yml
vendored
@@ -15,17 +15,17 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
dotnet-version: ${{ env.DOTNET_SDK_VERSION }}
|
dotnet-version: ${{ env.DOTNET_SDK_VERSION }}
|
||||||
- name: Publish generic
|
- name: Publish generic
|
||||||
run: dotnet publish -c Release -o out/generic -p:UseAppHost=false
|
run: dotnet publish YandexKeyExtractor/YandexKeyExtractor.csproj -c Release -o out/generic -p:UseAppHost=false
|
||||||
- name: Upload generic artifacts
|
- name: Upload generic artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ github.event.repository.name }}
|
name: ${{ github.event.repository.name }}
|
||||||
path: out/generic
|
path: out/generic
|
||||||
- name: Publish Windows version
|
- name: Publish Windows version
|
||||||
run: dotnet publish -c Release -o out/win -p:PublishSingleFile=true -p:PublishTrimmed=true -r win-x64
|
run: dotnet publish YandexKeyExtractor/YandexKeyExtractor.csproj -c Release -o out/win -p:PublishSingleFile=true -p:PublishTrimmed=true -r win-x64
|
||||||
- name: Upload Windows artifacts
|
- name: Upload Windows artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ github.event.repository.name }}-Windows
|
name: ${{ github.event.repository.name }}-Windows
|
||||||
path: out/win
|
path: out/win
|
||||||
|
|
||||||
|
|||||||
@@ -3,41 +3,49 @@ using System.Text;
|
|||||||
using CryptSharp.Utility;
|
using CryptSharp.Utility;
|
||||||
using NaCl;
|
using NaCl;
|
||||||
|
|
||||||
namespace YandexKeyExtractor {
|
namespace YandexKeyExtractor;
|
||||||
public static class Decryptor {
|
|
||||||
public static string? Decrypt(string encryptedText, string password) {
|
|
||||||
string base64Text = NormalizeBase64(encryptedText);
|
|
||||||
|
|
||||||
ReadOnlySpan<byte> textBytes = Convert.FromBase64String(base64Text).AsSpan();
|
public static class Decryptor
|
||||||
|
{
|
||||||
|
public static string? Decrypt(string encryptedText, string password)
|
||||||
|
{
|
||||||
|
var base64Text = NormalizeBase64(encryptedText);
|
||||||
|
|
||||||
const byte saltLength = 16;
|
ReadOnlySpan<byte> textBytes = Convert.FromBase64String(base64Text).AsSpan();
|
||||||
ReadOnlySpan<byte> textData = textBytes[..^saltLength];
|
|
||||||
ReadOnlySpan<byte> textSalt = textBytes[^saltLength..];
|
|
||||||
|
|
||||||
byte[]? generatedPassword = SCrypt.ComputeDerivedKey(Encoding.UTF8.GetBytes(password), textSalt.ToArray(), 32768, 20, 1, null, 32);
|
const byte SaltLength = 16;
|
||||||
|
var textData = textBytes[..^SaltLength];
|
||||||
|
var textSalt = textBytes[^SaltLength..];
|
||||||
|
|
||||||
using XSalsa20Poly1305 secureBox = new(generatedPassword);
|
var generatedPassword = SCrypt.ComputeDerivedKey(
|
||||||
|
Encoding.UTF8.GetBytes(password), textSalt.ToArray(), 32768, 20, 1, null, 32
|
||||||
|
);
|
||||||
|
|
||||||
const byte nonceLength = 24;
|
using XSalsa20Poly1305 secureBox = new(generatedPassword);
|
||||||
ReadOnlySpan<byte> nonce = textData[..nonceLength];
|
|
||||||
ReadOnlySpan<byte> dataWithMac = textData[nonceLength..];
|
|
||||||
|
|
||||||
|
const byte NonceLength = 24;
|
||||||
Span<byte> message = dataWithMac.Length <= 4096 ? stackalloc byte[dataWithMac.Length] : new byte[dataWithMac.Length];
|
var nonce = textData[..NonceLength];
|
||||||
|
var dataWithMac = textData[NonceLength..];
|
||||||
|
|
||||||
const byte macLength = 16;
|
|
||||||
ReadOnlySpan<byte> data = dataWithMac[macLength..];
|
|
||||||
ReadOnlySpan<byte> mac = dataWithMac[..macLength];
|
|
||||||
|
|
||||||
return secureBox.TryDecrypt(message, data, mac, nonce) ? new string(Encoding.UTF8.GetString(message).TrimEnd('\0')) : null;
|
var message = dataWithMac.Length <= 4096 ? stackalloc byte[dataWithMac.Length] : new byte[dataWithMac.Length];
|
||||||
}
|
|
||||||
|
|
||||||
private static string NormalizeBase64(string encryptedText) {
|
const byte MacLength = 16;
|
||||||
return encryptedText.Replace('-', '+').Replace('_', '/') + (encryptedText.Length % 4) switch {
|
var data = dataWithMac[MacLength..];
|
||||||
2 => "==",
|
var mac = dataWithMac[..MacLength];
|
||||||
3 => "=",
|
|
||||||
_ => ""
|
return secureBox.TryDecrypt(message, data, mac, nonce)
|
||||||
};
|
? new string(Encoding.UTF8.GetString(message).TrimEnd('\0'))
|
||||||
}
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string NormalizeBase64(string encryptedText)
|
||||||
|
{
|
||||||
|
return encryptedText.Replace('-', '+').Replace('_', '/') + (encryptedText.Length % 4) switch
|
||||||
|
{
|
||||||
|
2 => "==",
|
||||||
|
3 => "=",
|
||||||
|
_ => ""
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,65 +1,61 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading.Tasks;
|
using YandexKeyExtractor;
|
||||||
|
|
||||||
namespace YandexKeyExtractor {
|
Console.WriteLine("Initializing...");
|
||||||
internal static class Program {
|
using var handler = WebHandler.Create();
|
||||||
private static async Task Main() {
|
|
||||||
Console.WriteLine("Initializing...");
|
|
||||||
using WebHandler handler = WebHandler.Create();
|
|
||||||
|
|
||||||
string country = await handler.TryGetCountry().ConfigureAwait(false);
|
var country = await handler.TryGetCountry();
|
||||||
|
|
||||||
PromptInput(out string phoneNumber, nameof(phoneNumber));
|
PromptInput(out var phoneNumber);
|
||||||
|
|
||||||
phoneNumber = phoneNumber.TrimStart('+');
|
phoneNumber = phoneNumber.TrimStart('+');
|
||||||
string phone = await handler.GetPhoneNumberInfo(phoneNumber, country).ConfigureAwait(false);
|
var phone = await handler.GetPhoneNumberInfo(phoneNumber, country);
|
||||||
|
|
||||||
string? trackID = await handler.SendSMSCodeAndGetTrackID(phone, country).ConfigureAwait(false);
|
var trackID = await handler.SendSMSCodeAndGetTrackID(phone, country);
|
||||||
if (string.IsNullOrEmpty(trackID)) {
|
if (string.IsNullOrEmpty(trackID)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PromptInput(out string smsCode, nameof(smsCode));
|
PromptInput(out var smsCode);
|
||||||
|
|
||||||
if (!await handler.CheckCode(smsCode, trackID).ConfigureAwait(false)) {
|
if (!await handler.CheckCode(smsCode, trackID)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!await handler.ValidateBackupInfo(phone, trackID, country).ConfigureAwait(false)) {
|
if (!await handler.ValidateBackupInfo(phone, trackID, country)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string? backup = await handler.GetBackupData(phone, trackID).ConfigureAwait(false);
|
var backup = await handler.GetBackupData(phone, trackID);
|
||||||
if (string.IsNullOrEmpty(backup)) {
|
if (string.IsNullOrEmpty(backup)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PromptInput(out string backupPassword, nameof(backupPassword));
|
PromptInput(out var backupPassword);
|
||||||
|
|
||||||
Console.WriteLine("Decrypting...");
|
Console.WriteLine("Decrypting...");
|
||||||
string? message = Decryptor.Decrypt(backup, backupPassword);
|
var message = Decryptor.Decrypt(backup, backupPassword);
|
||||||
if (string.IsNullOrEmpty(message)) {
|
if (string.IsNullOrEmpty(message)) {
|
||||||
Console.WriteLine("Decryption failed!");
|
Console.WriteLine("Decryption failed!");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("Successfully decrypted!");
|
Console.WriteLine("Successfully decrypted!");
|
||||||
await File.WriteAllTextAsync("result.txt", message).ConfigureAwait(false);
|
await File.WriteAllTextAsync("result.txt", message);
|
||||||
Console.WriteLine($"Written {message.Split('\n').Length} authenticators to result file");
|
Console.WriteLine($"Written {message.Split('\n').Length} authenticators to result file");
|
||||||
}
|
|
||||||
|
return;
|
||||||
private static void PromptInput(out string result, [CallerArgumentExpression("result")] string argumentName = "") {
|
|
||||||
Console.WriteLine($"Enter {argumentName}:");
|
static void PromptInput(out string result, [CallerArgumentExpression("result")] string argumentName = "") {
|
||||||
string? input = Console.ReadLine();
|
Console.WriteLine($"Enter {argumentName}:");
|
||||||
while (string.IsNullOrEmpty(input)) {
|
var input = Console.ReadLine();
|
||||||
Console.WriteLine($"{argumentName} is invalid, try again:");
|
while (string.IsNullOrEmpty(input)) {
|
||||||
input = Console.ReadLine();
|
Console.WriteLine($"{argumentName} is invalid, try again:");
|
||||||
}
|
input = Console.ReadLine();
|
||||||
|
}
|
||||||
result = input;
|
|
||||||
}
|
result = input;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,167 +11,188 @@ using Flurl.Http;
|
|||||||
using Flurl.Serialization.TextJson;
|
using Flurl.Serialization.TextJson;
|
||||||
using YandexKeyExtractor.Models;
|
using YandexKeyExtractor.Models;
|
||||||
|
|
||||||
namespace YandexKeyExtractor {
|
namespace YandexKeyExtractor;
|
||||||
public sealed class WebHandler : IDisposable {
|
|
||||||
private WebHandler(IFlurlClient client) => Client = client;
|
|
||||||
private IFlurlClient Client { get; }
|
|
||||||
|
|
||||||
public void Dispose() {
|
public sealed class WebHandler : IDisposable
|
||||||
Client.Dispose();
|
{
|
||||||
}
|
private WebHandler(IFlurlClient client) => Client = client;
|
||||||
|
private IFlurlClient Client { get; }
|
||||||
|
|
||||||
public async Task<bool> CheckCode(string? smsCode, string? trackID) {
|
public void Dispose()
|
||||||
StatusResponse? checkCodeResponse = await Client.Request("/bundle/yakey_backup/check_code/")
|
{
|
||||||
.PostUrlEncodedAsync(
|
Client.Dispose();
|
||||||
new {
|
}
|
||||||
code = smsCode,
|
|
||||||
track_id = trackID
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.ReceiveJson<StatusResponse?>()
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
return ValidateResponse(checkCodeResponse, nameof(checkCodeResponse));
|
public async Task<bool> CheckCode(string? smsCode, string? trackID)
|
||||||
}
|
{
|
||||||
|
var checkCodeResponse = await Client.Request("/bundle/yakey_backup/check_code/")
|
||||||
public static WebHandler Create() {
|
.PostUrlEncodedAsync(
|
||||||
JsonSerializerOptions jsonSettings = new() {
|
new
|
||||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
{
|
||||||
};
|
code = smsCode,
|
||||||
|
track_id = trackID
|
||||||
IFlurlClient? client = new FlurlClient(
|
|
||||||
new HttpClient {
|
|
||||||
DefaultRequestHeaders = { UserAgent = { new ProductInfoHeaderValue("okhttp", "2.7.5") } },
|
|
||||||
BaseAddress = new Uri("https://registrator.mobile.yandex.net/1/")
|
|
||||||
}
|
}
|
||||||
).Configure(settings => settings.WithTextJsonSerializer(jsonSettings));
|
)
|
||||||
|
.ReceiveJson<StatusResponse?>();
|
||||||
|
|
||||||
return new WebHandler(client);
|
return ValidateResponse(checkCodeResponse, nameof(checkCodeResponse));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string?> GetBackupData(string phone, string? trackID) {
|
public static WebHandler Create()
|
||||||
BackupResponse? backupResponse = await Client.Request("/bundle/yakey_backup/download")
|
{
|
||||||
.PostUrlEncodedAsync(
|
JsonSerializerOptions jsonSettings = new()
|
||||||
new {
|
{
|
||||||
number = phone,
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
||||||
track_id = trackID
|
};
|
||||||
}
|
|
||||||
)
|
|
||||||
.ReceiveJson<BackupResponse?>()
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (!ValidateResponse(backupResponse, nameof(backupResponse))) {
|
var client = new FlurlClient(
|
||||||
return null;
|
new HttpClient
|
||||||
|
{
|
||||||
|
DefaultRequestHeaders = {UserAgent = {new ProductInfoHeaderValue("okhttp", "2.7.5")}},
|
||||||
|
BaseAddress = new Uri("https://registrator.mobile.yandex.net/1/")
|
||||||
}
|
}
|
||||||
|
).Configure(settings => settings.WithTextJsonSerializer(jsonSettings));
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(backupResponse.Backup)) {
|
return new WebHandler(client);
|
||||||
Console.WriteLine("Fatal error - Couldn't find valid backup!");
|
}
|
||||||
|
|
||||||
return null;
|
public async Task<string?> GetBackupData(string phone, string? trackID)
|
||||||
}
|
{
|
||||||
|
var backupResponse = await Client.Request("/bundle/yakey_backup/download")
|
||||||
return backupResponse.Backup;
|
.PostUrlEncodedAsync(
|
||||||
}
|
new
|
||||||
|
{
|
||||||
public async Task<string> GetPhoneNumberInfo(string? phoneNumber, string country) {
|
number = phone,
|
||||||
PhoneNumberResponse? phoneNumberResponse = await Client.Request("/bundle/validate/phone_number/")
|
track_id = trackID
|
||||||
.PostUrlEncodedAsync(
|
|
||||||
new {
|
|
||||||
phone_number = phoneNumber,
|
|
||||||
country
|
|
||||||
}
|
|
||||||
).ReceiveJson<PhoneNumberResponse?>()
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
ValidateResponse(phoneNumberResponse, nameof(phoneNumberResponse));
|
|
||||||
|
|
||||||
string phone = phoneNumberResponse?.PhoneNumber?.StandardizedNumber ?? '+' + phoneNumber;
|
|
||||||
|
|
||||||
return phone;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<string?> SendSMSCodeAndGetTrackID(string phone, string country) {
|
|
||||||
TrackResponse? trackResponse = await Client.Request("/bundle/yakey_backup/send_code/")
|
|
||||||
.PostUrlEncodedAsync(
|
|
||||||
new {
|
|
||||||
display_language = "en",
|
|
||||||
number = phone,
|
|
||||||
country
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.ReceiveJson<TrackResponse?>()
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (!ValidateResponse(trackResponse, nameof(trackResponse))) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
string? trackID = trackResponse.TrackID;
|
|
||||||
if (string.IsNullOrEmpty(trackID)) {
|
|
||||||
Console.WriteLine("Track ID is empty!");
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return trackID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<string> TryGetCountry() {
|
|
||||||
CountryResponse? countryResponse = await Client.Request("/suggest/country")
|
|
||||||
.GetAsync()
|
|
||||||
.ReceiveJson<CountryResponse?>()
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
ValidateResponse(countryResponse, nameof(countryResponse));
|
|
||||||
|
|
||||||
string country = countryResponse?.Country?.FirstOrDefault() ?? "ru";
|
|
||||||
|
|
||||||
return country;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> ValidateBackupInfo(string phone, string? trackID, string country) {
|
|
||||||
BackupInfoResponse? backupInfoResponse = await Client.Request("/bundle/yakey_backup/info/")
|
|
||||||
.PostUrlEncodedAsync(
|
|
||||||
new {
|
|
||||||
number = phone,
|
|
||||||
track_id = trackID,
|
|
||||||
country
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.ReceiveJson<BackupInfoResponse?>()
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (!ValidateResponse(backupInfoResponse, nameof(backupInfoResponse))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (backupInfoResponse.Info?.Updated == null) {
|
|
||||||
Console.WriteLine("Fatal error - Couldn't find valid backup!");
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static bool ValidateResponse<T>([NotNullWhen(true)] T? response, [CallerArgumentExpression("response")] string responseName = "") where T : StatusResponse {
|
|
||||||
if (response == null) {
|
|
||||||
Console.WriteLine(responseName + " failed!");
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!response.IsSuccess) {
|
|
||||||
Console.WriteLine(responseName + $" failed with error {response.Status}!");
|
|
||||||
if (response.Errors != null) {
|
|
||||||
Console.WriteLine("Errors: " + string.Join(',', response.Errors));
|
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
.ReceiveJson<BackupResponse?>();
|
||||||
|
|
||||||
return false;
|
if (!ValidateResponse(backupResponse, nameof(backupResponse)))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(backupResponse.Backup))
|
||||||
|
{
|
||||||
|
Console.WriteLine("Fatal error - Couldn't find valid backup!");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return backupResponse.Backup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> GetPhoneNumberInfo(string? phoneNumber, string country)
|
||||||
|
{
|
||||||
|
var phoneNumberResponse = await Client.Request("/bundle/validate/phone_number/")
|
||||||
|
.PostUrlEncodedAsync(
|
||||||
|
new
|
||||||
|
{
|
||||||
|
phone_number = phoneNumber,
|
||||||
|
country
|
||||||
|
}
|
||||||
|
).ReceiveJson<PhoneNumberResponse?>();
|
||||||
|
|
||||||
|
ValidateResponse(phoneNumberResponse, nameof(phoneNumberResponse));
|
||||||
|
|
||||||
|
var phone = phoneNumberResponse?.PhoneNumber?.StandardizedNumber ?? '+' + phoneNumber;
|
||||||
|
|
||||||
|
return phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string?> SendSMSCodeAndGetTrackID(string phone, string country)
|
||||||
|
{
|
||||||
|
var trackResponse = await Client.Request("/bundle/yakey_backup/send_code/")
|
||||||
|
.PostUrlEncodedAsync(
|
||||||
|
new
|
||||||
|
{
|
||||||
|
display_language = "en",
|
||||||
|
number = phone,
|
||||||
|
country
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.ReceiveJson<TrackResponse?>();
|
||||||
|
|
||||||
|
if (!ValidateResponse(trackResponse, nameof(trackResponse)))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var trackID = trackResponse.TrackID;
|
||||||
|
if (string.IsNullOrEmpty(trackID))
|
||||||
|
{
|
||||||
|
Console.WriteLine("Track ID is empty!");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return trackID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> TryGetCountry()
|
||||||
|
{
|
||||||
|
var countryResponse = await Client.Request("/suggest/country")
|
||||||
|
.GetAsync()
|
||||||
|
.ReceiveJson<CountryResponse?>();
|
||||||
|
|
||||||
|
ValidateResponse(countryResponse, nameof(countryResponse));
|
||||||
|
|
||||||
|
var country = countryResponse?.Country?.FirstOrDefault() ?? "ru";
|
||||||
|
|
||||||
|
return country;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> ValidateBackupInfo(string phone, string? trackID, string country)
|
||||||
|
{
|
||||||
|
var backupInfoResponse = await Client.Request("/bundle/yakey_backup/info/")
|
||||||
|
.PostUrlEncodedAsync(
|
||||||
|
new
|
||||||
|
{
|
||||||
|
number = phone,
|
||||||
|
track_id = trackID,
|
||||||
|
country
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.ReceiveJson<BackupInfoResponse?>();
|
||||||
|
|
||||||
|
if (!ValidateResponse(backupInfoResponse, nameof(backupInfoResponse)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backupInfoResponse.Info?.Updated == null)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Fatal error - Couldn't find valid backup!");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static bool ValidateResponse<T>([NotNullWhen(true)] T? response,
|
||||||
|
[CallerArgumentExpression("response")] string responseName = "") where T : StatusResponse
|
||||||
|
{
|
||||||
|
if (response == null)
|
||||||
|
{
|
||||||
|
Console.WriteLine(responseName + " failed!");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.IsSuccess)
|
||||||
|
{
|
||||||
|
Console.WriteLine(responseName + $" failed with error {response.Status}!");
|
||||||
|
if (response.Errors != null)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Errors: " + string.Join(',', response.Errors));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
<FileVersion>1.0.0.0</FileVersion>
|
<FileVersion>1.0.0.0</FileVersion>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<!-- Trimming features -->
|
<!-- Trimming features -->
|
||||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||||
<DebuggerSupport>false</DebuggerSupport>
|
<DebuggerSupport>false</DebuggerSupport>
|
||||||
@@ -19,10 +19,6 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" Version="5.0.0.1">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="CryptSharpStandard" Version="1.0.0" />
|
<PackageReference Include="CryptSharpStandard" Version="1.0.0" />
|
||||||
<PackageReference Include="Flurl.Http" Version="3.2.4" />
|
<PackageReference Include="Flurl.Http" Version="3.2.4" />
|
||||||
<PackageReference Include="Flurl.Serialization.TextJson" Version="3.1.0" />
|
<PackageReference Include="Flurl.Serialization.TextJson" Version="3.1.0" />
|
||||||
|
|||||||
Reference in New Issue
Block a user