using Microsoft.EntityFrameworkCore; using PlaylistShared.Api.Data; using PlaylistShared.Api.Entities; using PlaylistShared.Shared.Yandex; using System.Net; using System.Text.Json; using YandexMusic.API; namespace PlaylistShared.Api.Services; public class YandexAuthService { private readonly YandexApiService _apiService; private readonly ApplicationDbContext _dbContext; public YandexApiService Service => _apiService; public YandexMusicApi Api => _apiService.Client.Api; public YandexAuthService(YandexApiService apiService, ApplicationDbContext dbContext) { _apiService = apiService; _dbContext = dbContext; } internal async Task 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 GenerateQrAsync(ApplicationUser user) { var qr = await Api.Passport.GetAuthQRLinkAsync(); var trackId = Service.Client.AuthStorage.AuthToken.TrackId; var csfrToken = Service.Client.AuthStorage.AuthToken.CsfrToken; var headerProcessUuid = Service.Client.AuthStorage.HeaderToken.ProcessUuid; var headerCsfrToken = Service.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 CheckQrAsync(int sessionId) { var session = await _dbContext.YandexAuthSessions.FindAsync(sessionId); if (session == null) return null; RestoreCookies(Service.CookieContainer, session.SerializedCookies); if (Service.Client.AuthStorage.AuthToken is null) { Service.Client.AuthStorage.AuthToken = new(); } Service.Client.AuthStorage.AuthToken.CsfrToken = session?.CsfrToken ?? ""; Service.Client.AuthStorage.AuthToken.TrackId = session?.TrackId ?? ""; Service.Client.AuthStorage.HeaderToken.CsfrToken = session?.HeaderCsfrToken ?? ""; Service.Client.AuthStorage.HeaderToken.ProcessUuid = session?.HeaderProcessId ?? ""; var status = await Api.Passport.CheckQRStatusAsync(); if (status?.State == "otp_auth_finished") { try { var auth = await Api.Passport.AuthorizeByQRAsync(); } 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(); 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>(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; } } }