From e2b2a7cc8d950b0b3c3020f2eb0b4d831abaed54 Mon Sep 17 00:00:00 2001 From: Michael Gordeev Date: Thu, 5 Dec 2019 00:58:09 +0300 Subject: [PATCH] Added authorization mechanism --- FoxTube.Core/FoxTube.Core.csproj | 14 +++-- .../{UserControl.cs => UsersControl.cs} | 26 +++++++--- FoxTube.Core/Models/User.cs | 52 +++++++++++++++---- FoxTube/App.xaml.cs | 2 +- FoxTube/Controls/AccountManager.xaml | 5 +- FoxTube/Controls/AccountManager.xaml.cs | 34 ++++++++---- FoxTube/FoxTube.csproj | 2 +- FoxTube/MainPage.xaml | 22 ++++++-- FoxTube/MainPage.xaml.cs | 31 +++++++++++ 9 files changed, 148 insertions(+), 40 deletions(-) rename FoxTube.Core/Helpers/{UserControl.cs => UsersControl.cs} (71%) diff --git a/FoxTube.Core/FoxTube.Core.csproj b/FoxTube.Core/FoxTube.Core.csproj index 57f7302..90ee4b8 100644 --- a/FoxTube.Core/FoxTube.Core.csproj +++ b/FoxTube.Core/FoxTube.Core.csproj @@ -136,7 +136,7 @@ - + @@ -153,6 +153,9 @@ 0.13.0 + + 1.0.1 + 1.42.0 @@ -163,10 +166,10 @@ 1.42.0.1758 - 2.6.1 + 2.6.2 - 2.6.1 + 2.6.2 6.2.9 @@ -186,11 +189,6 @@ Visual C++ 2015 Runtime for Universal Windows Platform Apps - - - ..\Src\YouTube.API.dll - - 14.0 diff --git a/FoxTube.Core/Helpers/UserControl.cs b/FoxTube.Core/Helpers/UsersControl.cs similarity index 71% rename from FoxTube.Core/Helpers/UserControl.cs rename to FoxTube.Core/Helpers/UsersControl.cs index 1eecfee..9bdbed1 100644 --- a/FoxTube.Core/Helpers/UserControl.cs +++ b/FoxTube.Core/Helpers/UsersControl.cs @@ -2,21 +2,26 @@ using Google.Apis.Oauth2.v2; using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Windows.Security.Authentication.Web; using YouTube.Authorization; -using YouTube; using System.Text.RegularExpressions; using Windows.Security.Credentials; using FoxTube.Core.Models; +using YouTube; using System.Threading; using Google.Apis.YouTube.v3; namespace FoxTube { - public static class UserControl + public static class UsersControl { + static ExtendedYouTubeService _defaultService = new ExtendedYouTubeService(new Google.Apis.Services.BaseClientService.Initializer + { + ApplicationName = "FoxTube", + ApiKey = "AIzaSyD7tpbuvmYDv9h4udo9L_g3r0sLPFAnN00" + }); + static string[] Scopes { get; } = new string[] { Oauth2Service.Scope.UserinfoProfile, @@ -32,6 +37,7 @@ namespace FoxTube public static User CurrentUser { get; set; } public static bool Authorized => CurrentUser != null; + public static ExtendedYouTubeService Service => CurrentUser?.Service ?? _defaultService; public static async Task AddUser() { @@ -42,8 +48,10 @@ namespace FoxTube switch(result.ResponseStatus) { case WebAuthenticationStatus.Success: - UserCredential credential = await AuthorizationHelpers.ExchangeToken(ClientSecrets, new Regex(@"(?<=code=).?\w+").Match(result.ResponseData).Value); // TODO: Add credential assignment + UserCredential credential = await AuthorizationHelpers.ExchangeToken(ClientSecrets, new Regex(@"(?<=code=).?\w+").Match(result.ResponseData).Value); CurrentUser = new User(credential); + PasswordVault passwordVault = new PasswordVault(); + passwordVault.Add(new PasswordCredential("foxtube", CurrentUser.UserInfo.Id, credential.Token.RefreshToken)); return true; case WebAuthenticationStatus.UserCancel: break; @@ -57,7 +65,8 @@ namespace FoxTube public static async Task Initialize() { PasswordVault passwordVault = new PasswordVault(); - List credentials = passwordVault.FindAllByResource("foxtube").ToList(); + IReadOnlyList credentials; + credentials = passwordVault.RetrieveAll(); if (credentials.Count == 0) return; @@ -67,7 +76,12 @@ namespace FoxTube CurrentUser = new User(credential); } - public static async Task Logout() => + public static async Task Logout() + { + PasswordVault passwordVault = new PasswordVault(); + PasswordCredential credential = passwordVault.Retrieve("foxtube", CurrentUser.UserInfo.Id); + passwordVault.Remove(credential); await CurrentUser.Credential.RevokeTokenAsync(CancellationToken.None); + } } } diff --git a/FoxTube.Core/Models/User.cs b/FoxTube.Core/Models/User.cs index fc117d9..bd4936f 100644 --- a/FoxTube.Core/Models/User.cs +++ b/FoxTube.Core/Models/User.cs @@ -1,24 +1,58 @@ using Google.Apis.Auth.OAuth2; +using Google.Apis.Oauth2.v2; +using Google.Apis.Oauth2.v2.Data; +using Google.Apis.Services; +using Google.Apis.YouTube.v3; using Google.Apis.YouTube.v3.Data; -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using YouTube; namespace FoxTube.Core.Models { public class User { - public string Name { get; set; } - public string Email { get; set; } - internal string RefreshToken { get; set; } - public UserCredential Credential { get; set; } - public Channel Channel { get; set; } + public Userinfoplus UserInfo { get; } + public UserCredential Credential { get; } + public Channel Channel { get; private set; } + public List Subscriptions { get; } = new List(); + public ExtendedYouTubeService Service { get; } public User(UserCredential credential) { + Credential = credential; + BaseClientService.Initializer initializer = new BaseClientService.Initializer + { + ApplicationName = "FoxTube", + HttpClientInitializer = Credential + }; + Service = new ExtendedYouTubeService(initializer); + + UserInfo = new Oauth2Service(initializer).Userinfo.Get().Execute(); + + // TODO: Retrieve history and WL + + SubscriptionsResource.ListRequest subRequest = Service.Subscriptions.List("snippet"); + subRequest.Mine = true; + subRequest.MaxResults = 50; + subRequest.Order = SubscriptionsResource.ListRequest.OrderEnum.Relevance; + SubscriptionListResponse subResponse; + string nextToken = null; + Subscriptions.Clear(); + + do + { + subRequest.PageToken = nextToken; + subResponse = subRequest.Execute(); + foreach (Subscription s in subResponse.Items) + Subscriptions.Add(s); + nextToken = subResponse.NextPageToken; + + } while (!string.IsNullOrWhiteSpace(nextToken)); + + var request = Service.Channels.List("snippet,contentDetails"); + request.Mine = true; + Channel = request.Execute().Items[0]; } } } diff --git a/FoxTube/App.xaml.cs b/FoxTube/App.xaml.cs index 57cafe8..a4c2dc4 100644 --- a/FoxTube/App.xaml.cs +++ b/FoxTube/App.xaml.cs @@ -19,7 +19,7 @@ namespace FoxTube protected override async void OnLaunched(LaunchActivatedEventArgs e) { - await UserControl.Initialize(); + await UsersControl.Initialize(); await StoreInterop.UpdateStoreState(); if (Settings.LastReviewedVersion != Metrics.CurrentVersion) Inbox.PushChangelog(); diff --git a/FoxTube/Controls/AccountManager.xaml b/FoxTube/Controls/AccountManager.xaml index a194d6f..9d22632 100644 --- a/FoxTube/Controls/AccountManager.xaml +++ b/FoxTube/Controls/AccountManager.xaml @@ -5,10 +5,11 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" - Label="Michael 'XFox' Gordeev" + Label="Sign in" xmlns:ui="using:Microsoft.UI.Xaml.Controls" xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls" - Style="{StaticResource AppBarButtonRevealStyle}"> + Style="{StaticResource AppBarButtonRevealStyle}" + Loaded="AppBarButton_Loaded"> diff --git a/FoxTube/Controls/AccountManager.xaml.cs b/FoxTube/Controls/AccountManager.xaml.cs index 427c09c..2a4870f 100644 --- a/FoxTube/Controls/AccountManager.xaml.cs +++ b/FoxTube/Controls/AccountManager.xaml.cs @@ -10,18 +10,34 @@ namespace FoxTube.Controls async void Flyout_Opening(object sender, object e) { - if (UserControl.Authorized) + if (UsersControl.Authorized) return; (sender as Flyout).Hide(); - - if(await UserControl.AddUser()) - { - banner.Source = new BitmapImage(UserControl.CurrentUser.Channel.BrandingSettings.Image.BannerMobileLowImageUrl.ToUri()) { DecodePixelWidth = 300, DecodePixelHeight = 60 }; - avatar.ProfilePicture = new BitmapImage(UserControl.CurrentUser.Channel.Snippet.Thumbnails.Default__.Url.ToUri()) { DecodePixelHeight = 40, DecodePixelWidth = 40 }; - name.Text = UserControl.CurrentUser.Name; - email.Text = UserControl.CurrentUser.Email; - } + + if (await UsersControl.AddUser()) + UpdateData(); + } + + void AppBarButton_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e) + { + if (UsersControl.Authorized) + UpdateData(); + else + MainPage.Current.Update(); + } + + void UpdateData() + { + Label = UsersControl.CurrentUser.UserInfo.Name; + Icon = new SymbolIcon(Symbol.Contact); + + banner.Source = new BitmapImage(UsersControl.CurrentUser.Channel.BrandingSettings.Image.BannerMobileLowImageUrl.ToUri()) { DecodePixelWidth = 300, DecodePixelHeight = 60 }; + avatar.ProfilePicture = new BitmapImage(UsersControl.CurrentUser.Channel.Snippet.Thumbnails.Default__.Url.ToUri()) { DecodePixelHeight = 40, DecodePixelWidth = 40 }; + name.Text = UsersControl.CurrentUser.UserInfo.Name; + email.Text = UsersControl.CurrentUser.UserInfo.Email; + + MainPage.Current.Update(); } } } diff --git a/FoxTube/FoxTube.csproj b/FoxTube/FoxTube.csproj index d0eb8d4..56fdc3e 100644 --- a/FoxTube/FoxTube.csproj +++ b/FoxTube/FoxTube.csproj @@ -292,7 +292,7 @@ 6.0.0 - 2.2.190917002 + 2.3.191129002 diff --git a/FoxTube/MainPage.xaml b/FoxTube/MainPage.xaml index d72f36b..b56294a 100644 --- a/FoxTube/MainPage.xaml +++ b/FoxTube/MainPage.xaml @@ -8,7 +8,8 @@ xmlns:ui="using:Microsoft.UI.Xaml.Controls" xmlns:controls="using:FoxTube.Controls" xmlns:toolkit="using:Microsoft.Toolkit.Uwp.UI.Controls" - xmlns:models="using:FoxTube.Core.Models"> + xmlns:models="using:FoxTube.Core.Models" + xmlns:data="using:Google.Apis.YouTube.v3.Data"> @@ -59,6 +60,19 @@ + + + + + + + + + + + + + @@ -67,7 +81,7 @@ - + @@ -82,11 +96,11 @@ - + - + diff --git a/FoxTube/MainPage.xaml.cs b/FoxTube/MainPage.xaml.cs index ef73388..b661183 100644 --- a/FoxTube/MainPage.xaml.cs +++ b/FoxTube/MainPage.xaml.cs @@ -1,5 +1,6 @@ using FoxTube.Core.Helpers; using FoxTube.Core.Models; +using Google.Apis.YouTube.v3.Data; using System; using System.Collections.Generic; using System.Linq; @@ -235,5 +236,35 @@ namespace FoxTube break; } } + + public void Update() + { + if(UsersControl.Authorized) + { + for (int i = NavigationViewControl.MenuItems.IndexOf(subscriptions); i < NavigationViewControl.MenuItems.IndexOf(categoriesHeader); i++) + (NavigationViewControl.MenuItems[i] as FrameworkElement).Visibility = Visibility.Visible; + + for (int i = NavigationViewControl.MenuItems.IndexOf(categoriesHeader); i < NavigationViewControl.MenuItems.Count; i++) + (NavigationViewControl.MenuItems[i] as FrameworkElement).Visibility = Visibility.Collapsed; + + foreach (Subscription i in UsersControl.CurrentUser.Subscriptions) + NavigationViewControl.MenuItems.Insert(NavigationViewControl.MenuItems.IndexOf(categoriesHeader), i); + } + else + { + IEnumerable subs = from i in NavigationViewControl.MenuItems + where string.IsNullOrWhiteSpace((i as FrameworkElement).Name) + select i; + + foreach (object i in subs) + NavigationViewControl.MenuItems.Remove(i); + + for (int i = NavigationViewControl.MenuItems.IndexOf(subscriptions); i < NavigationViewControl.MenuItems.IndexOf(categoriesHeader); i++) + (NavigationViewControl.MenuItems[i] as FrameworkElement).Visibility = Visibility.Collapsed; + + for (int i = NavigationViewControl.MenuItems.IndexOf(categoriesHeader); i < NavigationViewControl.MenuItems.Count; i++) + (NavigationViewControl.MenuItems[i] as FrameworkElement).Visibility = Visibility.Visible; + } + } } }