Files
PlaylistShared/PlaylistShared.Api/Services/Yandex/YandexAuthService.cs

151 lines
4.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Microsoft.EntityFrameworkCore;
using PlaylistShared.Api.Data;
using PlaylistShared.Api.Entities;
using PlaylistShared.Shared.Yandex;
using System.Net;
using System.Text.Json;
namespace PlaylistShared.Api.Services;
public class YandexAuthService
{
private readonly YandexApiService _apiService;
private readonly ApplicationDbContext _dbContext;
public YandexApiService Service => _apiService;
public YandexAuthService(YandexApiService apiService, ApplicationDbContext dbContext)
{
_apiService = apiService;
_dbContext = dbContext;
}
internal async Task<YandexAuthQr> GetQrOrGenerate(ApplicationUser user)
{
var existingSession = _dbContext.YandexAuthSessions
.Where(s => s.UserId == user.Id && !s.IsConfirmed && s.CreatedAt > DateTime.UtcNow.AddMinutes(-5))
.OrderByDescending(s => s.CreatedAt)
.FirstOrDefault();
if (existingSession != null)
{
return new YandexAuthQr
{
QrLink = existingSession.QrCodeUrl,
SessionId = existingSession.Id.ToString()
};
}
return await GenerateQrAsync(user);
}
internal async Task<YandexAuthQr> GenerateQrAsync(ApplicationUser user)
{
var client = _apiService.Client;
var qr = await client.GetAuthQRLink();
var trackId = client.AuthStorage.AuthToken.TrackId;
var csfrToken = client.AuthStorage.AuthToken.CsfrToken;
var headerProcessUuid = client.AuthStorage.HeaderToken.ProcessUuid;
var headerCsfrToken = client.AuthStorage.HeaderToken.CsfrToken;
if (string.IsNullOrEmpty(qr))
throw new Exception("Не удалось получить QR-ссылку");
var cookiesJson = SerializeCookies(_apiService.CookieContainer);
var session = new YandexAuthSession
{
UserId = user.Id,
QrCodeUrl = qr,
SerializedCookies = cookiesJson,
CreatedAt = DateTime.UtcNow,
IsConfirmed = false,
TrackId = trackId,
CsfrToken = csfrToken,
HeaderCsfrToken = headerCsfrToken,
HeaderProcessId = headerProcessUuid,
};
_dbContext.YandexAuthSessions.Add(session);
await _dbContext.SaveChangesAsync();
return new YandexAuthQr
{
QrLink = qr,
SessionId = session.Id.ToString()
};
}
internal async Task<YandexAuthQrCheck?> CheckQrAsync(int sessionId)
{
var session = await _dbContext.YandexAuthSessions.FindAsync(sessionId);
if (session == null) return null;
RestoreCookies(_apiService.CookieContainer, session.SerializedCookies);
if (_apiService.Client.AuthStorage.AuthToken is null)
{
_apiService.Client.AuthStorage.AuthToken = new();
}
_apiService.Client.AuthStorage.AuthToken.CsfrToken = session?.CsfrToken ?? "";
_apiService.Client.AuthStorage.AuthToken.TrackId = session?.TrackId ?? "";
_apiService.Client.AuthStorage.HeaderToken.CsfrToken = session?.HeaderCsfrToken ?? "";
_apiService.Client.AuthStorage.HeaderToken.ProcessUuid = session?.HeaderProcessId ?? "";
var status = await _apiService.Client.CheckQRStatusAsync();
if (status?.State == "otp_auth_finished")
{
try
{
var auth = await _apiService.Client.AuthorizeByQR();
}
catch (Exception ex)
{
return new() { Status = Shared.Enums.YandexAuthQrStatus.Error, };
}
_dbContext.YandexAuthSessions.Where(t => t.UserId == session.UserId).ExecuteDelete();
_dbContext.SaveChanges();
return new() { Status = Shared.Enums.YandexAuthQrStatus.Authorized, };
}
return new()
{
Status = Shared.Enums.YandexAuthQrStatus.Pending,
};
}
private string SerializeCookies(CookieContainer container)
{
var allCookies = new List<object>();
var cookies = container.GetAllCookies();
foreach (Cookie cookie in cookies)
{
allCookies.Add(new { cookie.Name, cookie.Value, cookie.Domain, cookie.Path });
}
return JsonSerializer.Serialize(allCookies);
}
private void RestoreCookies(CookieContainer container, string serializedCookies)
{
var cookies = JsonSerializer.Deserialize<List<CookieData>>(serializedCookies);
foreach (var c in cookies)
{
container.Add(new Cookie(c.Name, c.Value, c.Path, c.Domain));
}
}
private class CookieData
{
public string Name { get; set; }
public string Value { get; set; }
public string Domain { get; set; }
public string Path { get; set; }
}
}