Archived
1
0
This repository has been archived on 2026-04-22. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
FoxTube/FoxTube.Core/UserManagement.cs
T
2020-05-11 02:21:16 +03:00

205 lines
6.7 KiB
C#

using Google.Apis.Auth.OAuth2;
using Google.Apis.Oauth2.v2;
using System;
using System.Threading.Tasks;
using Windows.Security.Authentication.Web;
using YouTube.Authorization;
using Windows.Security.Credentials;
using FoxTube.Models;
using YouTube;
using System.Threading;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;
using Windows.UI.Xaml.Controls;
using FoxTube.Utils;
using YoutubeExplode;
using System.Linq;
using Newtonsoft.Json;
using Windows.Storage;
using Google.Apis.Oauth2.v2.Data;
namespace FoxTube
{
public static class UserManagement
{
public const int MaxUsersCount = 2;
#region Private members
private static readonly ApplicationDataContainer storage = ApplicationData.Current.LocalSettings;
private static ExtendedYouTubeService _defaultService = new ExtendedYouTubeService(new Google.Apis.Services.BaseClientService.Initializer
{
ApplicationName = "FoxTube",
ApiKey = "AIzaSyBgHrCnrlzlVmk0cJKL8RqP9Y8x6XSuk_0",
//ApiKey = "AIzaSyD7tpbuvmYDv9h4udo9L_g3r0sLPFAnN00"
});
private static YoutubeClient _defaultYteClient = new YoutubeClient();
private static string[] Scopes { get; } = new string[]
{
Oauth2Service.Scope.UserinfoProfile,
Oauth2Service.Scope.UserinfoEmail,
YouTubeService.Scope.YoutubeForceSsl
};
private static ClientSecrets[] ClientSecrets { get; } = new ClientSecrets[MaxUsersCount]
{
new ClientSecrets
{
ClientId = "349735264870-2ekqlm0a4mkg3mmrfcv90s3qp3o15dq0.apps.googleusercontent.com",
ClientSecret = "BkVZOAaCU2Zclf0Zlicg6y2_"
},
new ClientSecrets // DISABLED
{
ClientId = "1096685398208-u95rcpkqb4e1ijfmb8jdq3jsg37l8igv.apps.googleusercontent.com",
ClientSecret = "IU5bbdjwvmx8ttJoXQ7e6JWd"
}
};
#endregion
public static Userinfoplus[] Users { get; private set; } = new Userinfoplus[MaxUsersCount];
public static User CurrentUser { get; set; }
public static bool Authorized => CurrentUser != null;
public static ExtendedYouTubeService Service => CurrentUser?.Service ?? _defaultService;
public static YoutubeClient YoutubeClient => CurrentUser?.Client ?? _defaultYteClient;
public static event EventHandler<bool> UserStateUpdated;
public static event EventHandler<Subscription> SubscriptionsChanged;
public static async Task<bool> AddUser()
{
int queueIndex = Users.ToList().FindIndex(i => i == null);
if (queueIndex < 0)
throw new StackOverflowException("The maximum accounts limit is reached");
ClientSecrets secrets = ClientSecrets[queueIndex];
Uri requestString = AuthorizationHelpers.FormQueryString(secrets, Scopes);
WebAuthenticationResult result = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.UseTitle, requestString, AuthorizationHelpers.Endpoint);
switch (result.ResponseStatus)
{
case WebAuthenticationStatus.Success:
string successCode = AuthorizationHelpers.ParseSuccessCode(result.ResponseData);
YouTube.Authorization.UserCredential credential = await AuthorizationHelpers.ExchangeToken(secrets, successCode);
await LoadUser(credential, queueIndex);
return true;
case WebAuthenticationStatus.UserCancel:
break;
case WebAuthenticationStatus.ErrorHttp:
await new ContentDialog
{
Title = "Something went wrong...",
Content = "It may be a bug or temporary server issues. Please, try again later"
}.ShowAsync();
Metrics.SendReport(new Exception("Authorization failed (HTTP Error)"), null,
("Response status", result.ResponseStatus.ToString()),
("Response data", result.ResponseData),
("Error details", result.ResponseErrorDetail.ToString()));
break;
}
return false;
}
public static async Task Initialize()
{
Users = JsonConvert.DeserializeObject<Userinfoplus[]>(storage.Values["UserManagement.Users"] as string);
int? lastUserIndex = storage.Values["UserManagement.LastUser"] as int?;
if (lastUserIndex.HasValue && Users[lastUserIndex.Value] != null ||
(lastUserIndex = Users.ToList().FindIndex(i => i != null)) > -1)
await SwitchUser(lastUserIndex.Value);
}
public static async Task<bool> Logout()
{
if (CurrentUser?.UserInfo?.Id == null)
return false;
try
{
string userId = CurrentUser.UserInfo.Id;
PasswordVault passwordVault = new PasswordVault();
PasswordCredential credential = passwordVault.Retrieve("foxtube", userId);
passwordVault.Remove(credential);
await CurrentUser.Credential.RevokeTokenAsync(CancellationToken.None);
CurrentUser = null;
Users[Users.ToList().FindIndex(i => i.Id == userId)] = null;
storage.Values["UserManagement.Users"] = JsonConvert.SerializeObject(Users);
storage.Values["UserManagement.LastUser"] = null;
if (Users.Any(i => i != null))
await SwitchUser(Users.ToList().FindIndex(i => i != null));
else
UserStateUpdated?.Invoke(Users, false);
return true;
}
catch (Exception e)
{
Metrics.SendReport(new Exception("Failed to logout", e));
await new ContentDialog
{
Title = "Something went wrong...",
Content = "It may be a bug or temporary server issues. Please, try again later"
}.ShowAsync();
return false;
}
}
public static async Task SwitchUser(int userIndex)
{
Userinfoplus userInfo = Users[userIndex];
PasswordVault valut = new PasswordVault();
PasswordCredential vaultCredential = valut.Retrieve("foxtube", userInfo.Id);
if (vaultCredential == null)
throw new NullReferenceException("No user found to switch on");
vaultCredential.RetrievePassword();
string token = vaultCredential.Password;
YouTube.Authorization.UserCredential credential = await AuthorizationHelpers.RestoreUser(ClientSecrets[userIndex], token);
await LoadUser(credential, userIndex);
}
private static async Task LoadUser(YouTube.Authorization.UserCredential credential, int userIndex)
{
CurrentUser = await User.GetUser(credential);
Users[userIndex] = CurrentUser.UserInfo;
storage.Values["UserManagement.Users"] = JsonConvert.SerializeObject(Users);
storage.Values["UserManagement.LastUser"] = userIndex;
credential.RefreshTokenUpdated += (s, e) => UpdateToken(CurrentUser.UserInfo.Id, credential.Token.RefreshToken);
UpdateToken(CurrentUser.UserInfo.Id, credential.Token.RefreshToken);
UserStateUpdated?.Invoke(Users, true);
}
private static void UpdateToken(string id, string refreshToken)
{
PasswordVault passwordVault = new PasswordVault();
PasswordCredential vaultCredential = passwordVault.Retrieve("foxtube", id);
if (vaultCredential == null)
{
vaultCredential = new PasswordCredential("foxtube", CurrentUser.UserInfo.Id, refreshToken);
passwordVault.Add(vaultCredential);
}
else
vaultCredential.Password = refreshToken;
}
}
}