12 Commits
1.1 ... master

Author SHA1 Message Date
renovate[bot]
01b7d30754 chore(deps): update actions/checkout action to v5 (#49)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-12 10:37:04 +04:00
renovate[bot]
40b0f2f582 chore(deps): update actions/checkout digest to 08eba0b (#48)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 16:50:48 +00:00
renovate[bot]
5c3c2a9503 chore(deps): update actions/download-artifact action to v5 (#47)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-07 18:20:42 +04:00
renovate[bot]
fd891dd613 chore(deps): update actions/download-artifact action to v4.3.0 (#46)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-24 22:29:33 +00:00
renovate[bot]
a57d22a993 chore(deps): update actions/download-artifact action to v4.2.1 (#45)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-19 23:05:38 +00:00
renovate[bot]
003c0609e3 chore(deps): update actions/download-artifact action to v4.2.0 (#44)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-18 21:40:37 +00:00
Vita Chumakova
ce705b635c misc: replace flags with language codes 2025-03-17 14:21:11 +04:00
renovate[bot]
b9fa61f7c9 chore(deps): update actions/download-artifact action to v4.1.9 (#43)
* chore(deps): update actions/download-artifact action to v4.1.9

* chore: update SDK in GHA

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Vita Chumakova <me@ezhevita.dev>
2025-02-26 20:50:39 +04:00
Vita Chumakova
84f40a86ac chore: bump version 2024-10-24 16:30:45 +04:00
renovate[bot]
06b7413247 Update actions/checkout digest to 11bd719 2024-10-23 19:48:17 +00:00
renovate[bot]
72b9b1031b Update actions/checkout digest to eef6144 2024-10-07 22:28:53 +00:00
Vita Chumakova
e83a9fbe3d Use JsonTypeInfo 2024-10-03 05:40:28 +04:00
4 changed files with 28 additions and 26 deletions

View File

@@ -3,13 +3,13 @@ name: .NET
on: [push, pull_request]
env:
DOTNET_SDK_VERSION: 6.0.x
DOTNET_SDK_VERSION: 8.0.x
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
@@ -36,13 +36,13 @@ jobs:
steps:
- name: Download generic artifacts
uses: actions/download-artifact@v4.1.8
uses: actions/download-artifact@v5.0.0
with:
name: ${{ github.event.repository.name }}
path: out/${{ github.event.repository.name }}
- name: Download Windows artifacts
uses: actions/download-artifact@v4.1.8
uses: actions/download-artifact@v5.0.0
with:
name: ${{ github.event.repository.name }}-Windows
path: out/${{ github.event.repository.name }}-Windows

View File

@@ -1,5 +1,5 @@
# 🔑 Yandex.Key Extractor
## 🇺🇸 Extracts TOTP authenticators from [Yandex.Key](https://play.google.com/store/apps/details?id=ru.yandex.key&hl=en&gl=US) app
## [EN] Extracts TOTP authenticators from [Yandex.Key](https://play.google.com/store/apps/details?id=ru.yandex.key&hl=en&gl=US) app
### How to use?
1. Create a cloud backup in the app settings using your device.
@@ -9,7 +9,7 @@
4. TOTP links will be saved in `results.txt`.<br>Use QR code generator to import to another TOTP app or just extract secrets (e.g. for [Bitwarden](https://bitwarden.com/) import).
---
## 🇷🇺 Извлечение двухфакторных аутентификаторов из [Яндекс.Ключ](https://play.google.com/store/apps/details?id=ru.yandex.key&hl=ru&gl=RU)
## [RU] Извлечение двухфакторных аутентификаторов из [Яндекс.Ключ](https://play.google.com/store/apps/details?id=ru.yandex.key&hl=ru&gl=RU)
### Как использовать?
1. Создайте облачную резервную копию в настройках приложения с вашего устройства.

View File

@@ -6,7 +6,7 @@ using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;
using System.Threading.Tasks;
using YandexKeyExtractor.Exceptions;
using YandexKeyExtractor.Models;
@@ -21,25 +21,22 @@ public sealed class WebHandler : IDisposable
BaseAddress = new Uri("https://registrator.mobile.yandex.net/1/")
};
private readonly JsonSerializerOptions _jsonSettings = new()
{
TypeInfoResolver = SourceGenerationContext.Default
};
public async Task CheckCode(string smsCode, string trackID)
{
var checkCodeResponse = await PostUrlEncodedAndReceiveJson<StatusResponse>(
var checkCodeResponse = await PostUrlEncodedAndReceiveJson(
new Uri("bundle/yakey_backup/check_code/", UriKind.Relative),
new Dictionary<string, string>(2) {["code"] = smsCode, ["track_id"] = trackID});
new Dictionary<string, string>(2) {["code"] = smsCode, ["track_id"] = trackID},
static context => context.StatusResponse);
ValidateResponse(checkCodeResponse);
}
public async Task<string> GetBackupData(string phone, string trackID)
{
var backupResponse = await PostUrlEncodedAndReceiveJson<BackupResponse>(
var backupResponse = await PostUrlEncodedAndReceiveJson(
new Uri("bundle/yakey_backup/download", UriKind.Relative),
new Dictionary<string, string>(2) {["number"] = phone, ["track_id"] = trackID});
new Dictionary<string, string>(2) {["number"] = phone, ["track_id"] = trackID},
static context => context.BackupResponse);
ValidateResponse(backupResponse);
@@ -55,7 +52,8 @@ public sealed class WebHandler : IDisposable
{
var phoneNumberResponse = await PostUrlEncodedAndReceiveJson<PhoneNumberResponse>(
new Uri("bundle/validate/phone_number/", UriKind.Relative),
new Dictionary<string, string>(2) {["phone_number"] = phoneNumber, ["country"] = country});
new Dictionary<string, string>(2) {["phone_number"] = phoneNumber, ["country"] = country},
static context => context.PhoneNumberResponse);
var phone = phoneNumberResponse?.PhoneNumber?.StandardizedNumber ?? $"+{phoneNumber}";
@@ -64,9 +62,10 @@ public sealed class WebHandler : IDisposable
public async Task<string> SendSMSCodeAndGetTrackID(string phone, string country)
{
var trackResponse = await PostUrlEncodedAndReceiveJson<TrackResponse>(
var trackResponse = await PostUrlEncodedAndReceiveJson(
new Uri("bundle/yakey_backup/send_code/", UriKind.Relative),
new Dictionary<string, string>(3) {["display_language"] = "en", ["number"] = phone, ["country"] = country});
new Dictionary<string, string>(3) {["display_language"] = "en", ["number"] = phone, ["country"] = country},
static context => context.TrackResponse);
ValidateResponse(trackResponse);
@@ -81,16 +80,18 @@ public sealed class WebHandler : IDisposable
public async Task<string?> TryGetCountry()
{
var countryResponse = await _client.GetFromJsonAsync<CountryResponse>(new Uri("suggest/country", UriKind.Relative));
var countryResponse = await _client.GetFromJsonAsync(
new Uri("suggest/country", UriKind.Relative), SourceGenerationContext.Default.CountryResponse);
return countryResponse?.Country?.FirstOrDefault();
}
public async Task ValidateBackupInfo(string phone, string trackID, string country)
{
var backupInfoResponse = await PostUrlEncodedAndReceiveJson<BackupInfoResponse>(
var backupInfoResponse = await PostUrlEncodedAndReceiveJson(
new Uri("bundle/yakey_backup/info/", UriKind.Relative),
new Dictionary<string, string>(3) {["number"] = phone, ["track_id"] = trackID, ["country"] = country});
new Dictionary<string, string>(3) {["number"] = phone, ["track_id"] = trackID, ["country"] = country},
static context => context.BackupInfoResponse);
ValidateResponse(backupInfoResponse);
@@ -100,13 +101,14 @@ public sealed class WebHandler : IDisposable
}
}
private async Task<T?> PostUrlEncodedAndReceiveJson<T>(Uri url, Dictionary<string, string> data)
private async Task<T?> PostUrlEncodedAndReceiveJson<T>(Uri url, Dictionary<string, string> data,
Func<SourceGenerationContext, JsonTypeInfo<T>> typeInfoProvider)
{
using var content = new FormUrlEncodedContent(data);
using var responseMessage = await _client.PostAsync(url, content);
responseMessage.EnsureSuccessStatusCode();
return (await responseMessage.Content.ReadFromJsonAsync<T>(_jsonSettings))!;
return (await responseMessage.Content.ReadFromJsonAsync(typeInfoProvider(SourceGenerationContext.Default)))!;
}
private static void ValidateResponse<T>([NotNull] T? response,

View File

@@ -2,8 +2,8 @@
<PropertyGroup>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<AssemblyVersion>1.1.0</AssemblyVersion>
<FileVersion>1.1.0</FileVersion>
<AssemblyVersion>1.1.1</AssemblyVersion>
<FileVersion>1.1.1</FileVersion>
<NoWarn>$(NoWarn);CA1032;CA2007</NoWarn>
<Nullable>enable</Nullable>
<OutputType>Exe</OutputType>