using System.Security.Authentication; using System.Text.RegularExpressions; using YandexMusic.API.Models.Account; using YandexMusic.API.Requests.Account; namespace YandexMusic.API; /// API для работы с пользователем и авторизации. public class YUserAPI : YCommonAPI { public YUserAPI(YandexMusicApi api) : base(api) { } private async Task GetCsrfTokenAsync() { using var response = await new YGetAuthMethodsBuilder(Api).ExecuteRawAsync(null!); if (response == null || !response.IsSuccessStatusCode) throw new HttpRequestException("Не удалось получить CSRF-токен"); var content = await response.Content.ReadAsStringAsync(); var csrfMatch = Regex.Match(content, @"window\.__CSRF__\s*=\s*""([^""]+)"""); var processMatch = Regex.Match(content, @"'process_uuid'\s*:\s*'([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})'"); if (!csrfMatch.Success || !processMatch.Success) return false; Api.Storage.AuthToken = new YAuthToken { CsfrToken = csrfMatch.Groups[1].Value, ProcessUuid = processMatch.Groups[1].Value }; await new YPostAuthStats(Api).ExecuteAsync(null!); return true; } private async Task LoginByCookiesAsync() { if (Api.Storage.AuthToken == null) throw new AuthenticationException("Сессия входа не инициализирована"); var accessToken = await new YGetAuthCookiesBuilder(Api).ExecuteAsync(null!); if (accessToken == null || string.IsNullOrEmpty(accessToken.AccessToken)) return false; Api.Storage.AccessToken = accessToken; Api.Storage.Token = accessToken.AccessToken; var shortInfo = await new YGetShortAccountInfoBuilder(Api).ExecuteAsync(null!); if (shortInfo?.Status != YAuthStatus.Ok || string.IsNullOrWhiteSpace(shortInfo.Uid)) throw new Exception("Не удалось подтвердить авторизацию"); return true; } public async Task AuthorizeAsync(string token) { if (string.IsNullOrEmpty(token)) throw new Exception("Токен не может быть пустым"); Api.Storage.Token = token; var authInfo = await new YGetAuthInfoBuilder(Api).ExecuteAsync(null!); if (authInfo?.Account?.Uid == null) throw new Exception("Пользователь не авторизован"); Api.Storage.SetAuthorized(authInfo.Account, token); } public Task GetUserAuthAsync() => new YGetAuthInfoBuilder(Api).ExecuteAsync(null!); public async Task CreateAuthSessionAsync(string userName) { if (!await GetCsrfTokenAsync()) throw new Exception("Не удалось инициализировать сессию"); var result = await new YGetAuthLoginUserBuilder(Api).ExecuteAsync((Api.Storage.AuthToken.CsfrToken, userName)); if (result?.TrackId != null) Api.Storage.AuthToken.TrackId = result.TrackId; return result; } public async Task GetAuthQRLinkAsync() { if (!await GetCsrfTokenAsync()) throw new Exception("Не удалось инициализировать сессию"); var qr = await new YGetAuthQRBuilder(Api).ExecuteAsync(null!); if (qr?.Status != YAuthStatus.Ok || string.IsNullOrEmpty(qr.TrackId)) return null; Api.Storage.AuthToken = new YAuthToken { TrackId = qr.TrackId, CsfrToken = qr.CsrfToken }; return $"https://passport.yandex.ru/auth/magic/code/?track_id={qr.TrackId}"; } public async Task AuthorizeByQRAsync() { if (Api.Storage.AuthToken == null) throw new Exception("Сессия не инициализирована"); var status = await new YGetAuthLoginQRBuilder(Api).ExecuteAsync(null!); if (status?.Status == YAuthStatus.Ok && await LoginByCookiesAsync()) return status; throw new AuthenticationException("Ошибка авторизации по QR"); } public Task GetCaptchaAsync() { if (Api.Storage.AuthToken == null) throw new AuthenticationException("Выполните CreateAuthSessionAsync перед использованием"); return new YGetAuthCaptchaBuilder(Api).ExecuteAsync(null!); } public Task AuthorizeByCaptchaAsync(string captchaValue) { if (Api.Storage.AuthToken == null) throw new AuthenticationException("Выполните CreateAuthSessionAsync перед использованием"); return new YGetAuthLoginCaptchaBuilder(Api).ExecuteAsync(captchaValue); } public Task GetAuthLetterAsync() => new YGetAuthLetterBuilder(Api).ExecuteAsync(null!); public async Task AuthorizeByLetterAsync() { var status = await new YGetAuthLoginLetterBuilder(Api).ExecuteAsync(null!); if (status?.Status != YAuthStatus.Ok || !status.MagicLinkConfirmed) throw new Exception("Письмо не подтверждено"); return await LoginByCookiesAsync(); } public async Task AuthorizeByAppPasswordAsync(string password) { if (Api.Storage.AuthToken == null) throw new AuthenticationException("Выполните CreateAuthSessionAsync перед использованием"); var result = await new YGetAuthAppPasswordBuilder(Api).ExecuteAsync(password); if (result?.Status == YAuthStatus.Ok && await LoginByCookiesAsync()) return result; throw new AuthenticationException("Ошибка авторизации по паролю"); } public async Task GetAccessTokenAsync() { if (Api.Storage.AuthToken == null) throw new Exception("Сессия не инициализована"); var token = await new YGetMusicTokenBuilder(Api).ExecuteAsync(null!); if (token?.AccessToken != null) Api.Storage.Token = token.AccessToken; return token; } public Task GetLoginInfoAsync() => new YGetLoginInfoBuilder(Api).ExecuteAsync(null!); }