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

149 lines
5.1 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;
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<YandexAuthQr> GetQrOrGenerate(ApplicationUser user)
{
var existingSession = await _dbContext.YandexAuthSessions
.Where(s => s.UserId == user.Id && !s.IsConfirmed && s.CreatedAt > DateTime.UtcNow.AddMinutes(-5))
.OrderByDescending(s => s.CreatedAt)
.FirstOrDefaultAsync();
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 qr = await Api.Passport.GetAuthQRLinkAsync();
var trackId = Service.Client.AuthStorage.AuthToken?.TrackId;
var csrfToken = Service.Client.AuthStorage.AuthToken?.CsfrToken;
var headerProcessUuid = Service.Client.AuthStorage.HeaderToken?.ProcessUuid;
var headerCsrfToken = Service.Client.AuthStorage.HeaderToken?.CsfrToken;
if (string.IsNullOrEmpty(qr))
throw new Exception("Не удалось получить QR-ссылку");
var cookiesJson = _apiService.EncryptToken(SerializeCookies(_apiService.CookieContainer));
var session = new YandexAuthSession
{
UserId = user.Id,
QrCodeUrl = qr,
SerializedCookies = cookiesJson,
CreatedAt = DateTime.UtcNow,
IsConfirmed = false,
TrackId = trackId,
CsrfToken = csrfToken,
HeaderCsrfToken = headerCsrfToken,
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;
var decryptedCookies = _apiService.DecryptToken(session.SerializedCookies);
if (decryptedCookies == null) return null;
RestoreCookies(Service.CookieContainer, decryptedCookies);
if (Service.Client.AuthStorage.AuthToken is null)
{
Service.Client.AuthStorage.AuthToken = new();
}
Service.Client.AuthStorage.AuthToken.CsfrToken = session.CsrfToken ?? "";
Service.Client.AuthStorage.AuthToken.TrackId = session.TrackId ?? "";
if (Service.Client.AuthStorage.HeaderToken is null)
Service.Client.AuthStorage.HeaderToken = new();
Service.Client.AuthStorage.HeaderToken.CsfrToken = session.HeaderCsrfToken ?? "";
Service.Client.AuthStorage.HeaderToken.ProcessUuid = session.HeaderProcessId ?? "";
var status = await Api.Passport.CheckQRStatusAsync();
if (status?.State == "otp_auth_finished")
{
try
{
await Api.Passport.AuthorizeByQRAsync();
}
catch
{
return new() { Status = Shared.Enums.YandexAuthQrStatus.Error };
}
await _dbContext.YandexAuthSessions
.Where(t => t.UserId == session.UserId)
.ExecuteDeleteAsync();
await _dbContext.SaveChangesAsync();
return new() { Status = Shared.Enums.YandexAuthQrStatus.Authorized };
}
return new() { Status = Shared.Enums.YandexAuthQrStatus.Pending };
}
private string SerializeCookies(CookieContainer container)
{
var allCookies = new List<object>();
foreach (Cookie cookie in container.GetAllCookies())
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);
if (cookies == null) return;
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; } = string.Empty;
public string Value { get; set; } = string.Empty;
public string Domain { get; set; } = string.Empty;
public string Path { get; set; } = string.Empty;
}
}