/* * Copyright (c) 2023 Proton AG * * This file is part of ProtonVPN. * * ProtonVPN is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ProtonVPN is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ProtonVPN. If not, see . */ using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Security; using System.Text; using System.Text.Json; using System.Threading.Tasks; using Newtonsoft.Json.Linq; using ProtonVPN.UI.Tests.ApiClient.Contracts; namespace ProtonVPN.UI.Tests.ApiClient.Prod; public class ProdTestApiClient { public static string? AcessToken; public static string? UID; private readonly HttpClient _client; private readonly Random _random = new(); public ProdTestApiClient() { _client = new HttpClient { BaseAddress = new Uri("https://api.protonvpn.ch") }; } public async Task GetRandomSpecificPaidServerAsync(string username, SecureString password) { JToken? randomServer = null; JArray? logicals = await new ProdTestApiClient().GetLogicalServersLoggedInAsync(username, password); List? filteredServers = logicals? .Where(s => s["Status"] is JToken statusToken && statusToken.Type != JTokenType.Null && (int)statusToken == 1 && s["Tier"] is JToken tierToken && tierToken.Type != JTokenType.Null && (int)tierToken == 2 && s["Name"] != null && !s["Name"]!.ToString().Contains("SE-") && !s["Name"]!.ToString().Contains("IS-") && !s["Name"]!.ToString().Contains("TOR") && !s["Name"]!.ToString().Contains("CH-")) .ToList(); if (filteredServers?.Count > 0) { randomServer = filteredServers.OrderBy(_ => _random.Next()).FirstOrDefault(); } else { throw new Exception("Empty server list was returned."); } return randomServer?["Name"]?.ToString() ?? string.Empty; } public async Task GetLogicalServersLoggedInAsync(string username, SecureString password) { TestUserAuthenticator userAuthenticator = new(); await userAuthenticator.CreateSessionAsync(username, password); HttpRequestMessage request = GetAuthorizedRequestMessage(HttpMethod.Get, "/vpn/logicals?SignServer=Server.EntryIP,Server.Label", AcessToken, UID); HttpResponseMessage response = await _client.SendAsync(request); response.EnsureSuccessStatusCode(); JObject logicals = JObject.Parse(await response.Content.ReadAsStringAsync()); return (JArray?)logicals["LogicalServers"]; } public async Task GetAuthInfoAsync(AuthInfoRequest username) { string content = JsonSerializer.Serialize(username); HttpResponseMessage response = await SendPostUnauthorizedAsync("/auth/v4/info", content); return JsonSerializer.Deserialize(await response.Content.ReadAsStringAsync()); } public async Task GetAuthResponseAsync(AuthRequest body) { string content = JsonSerializer.Serialize(body); HttpResponseMessage response = await SendPostUnauthorizedAsync("/auth", content); return JsonSerializer.Deserialize(await response.Content.ReadAsStringAsync()); } private async Task SendPostUnauthorizedAsync(string endpoint, string content) { HttpRequestMessage request = GetUnauthorizedRequestMessage(HttpMethod.Post, endpoint); StringContent jsonContent = new StringContent( content, Encoding.UTF8, "application/json"); request.Content = jsonContent; HttpResponseMessage response = await _client.SendAsync(request); if (!response.IsSuccessStatusCode) { throw new Exception($"Api call to {_client.BaseAddress}{endpoint} failed. " + $"It returned {response.StatusCode}: " + $"\n" + await response.Content.ReadAsStringAsync()); } return response; } private HttpRequestMessage GetUnauthorizedRequestMessage(HttpMethod method, string requestUri) { HttpRequestMessage request = new(method, requestUri); request.Headers.Add("x-pm-apiversion", "3"); request.Headers.Add("x-pm-appversion", "windows-vpn@2.4.3-dev"); request.Headers.Add("x-pm-locale", "en"); request.Headers.Add("User-Agent", "ProtonVPN/2.4.3 (Microsoft Windows NT 10.0.19045.0)"); return request; } private HttpRequestMessage GetAuthorizedRequestMessage(HttpMethod method, string requestUri, string? accessToken, string? uniqueSessionId) { if (accessToken is null || uniqueSessionId is null) { throw new ArgumentNullException("Access token or unique session id is null."); } HttpRequestMessage request = GetUnauthorizedRequestMessage(method, requestUri); request.Headers.Add("x-pm-uid", uniqueSessionId); request.Headers.Add("Authorization", $"Bearer {accessToken}"); return request; } }