login to the app

This commit is contained in:
kawaiizenbo 2023-02-04 23:45:16 -07:00
parent 35f6d47a5f
commit 204cef09aa
12 changed files with 404 additions and 7 deletions

View file

@ -66,7 +66,7 @@ namespace WMstodon
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
rootFrame.Navigate(typeof(MainPage), e.Arguments);
rootFrame.Navigate(typeof(SelectInstancePage), e.Arguments);
}
// Ensure the current window is active
Window.Current.Activate();

54
WMstodon/HTTPUtils.cs Normal file
View file

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Windows.Storage;
namespace WMstodon
{
class HTTPUtils
{
static ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
// still usin em
public static async Task<KeyValuePair<HttpStatusCode, string>> GETAsync(string URL)
{
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri((string)localSettings.Values["instanceURL"]);
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", (string)localSettings.Values["accessToken"]);
HttpResponseMessage response = await httpClient.GetAsync(URL);
httpClient.Dispose();
return new KeyValuePair<HttpStatusCode, string>(response.StatusCode, await response.Content.ReadAsStringAsync());
}
public static async Task<KeyValuePair<HttpStatusCode, string>> GETGenericAsync(string URL)
{
HttpClient generic = new HttpClient();
generic.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", (string)localSettings.Values["accessToken"]);
HttpResponseMessage response = await generic.GetAsync(URL);
generic.Dispose();
return new KeyValuePair<HttpStatusCode, string>(response.StatusCode, await response.Content.ReadAsStringAsync());
}
public static async Task<KeyValuePair<HttpStatusCode, string>> POSTAsync(string URL, HttpContent data)
{
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri((string)localSettings.Values["instanceURL"]);
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", (string)localSettings.Values["accessToken"]);
HttpResponseMessage response = await httpClient.PostAsync(URL, data);
httpClient.Dispose();
return new KeyValuePair<HttpStatusCode, string>(response.StatusCode, await response.Content.ReadAsStringAsync());
}
public static async Task<KeyValuePair<HttpStatusCode, string>> POSTGenericAsync(string URL, HttpContent data)
{
HttpClient generic = new HttpClient();
generic.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", (string)localSettings.Values["accessToken"]);
HttpResponseMessage response = await generic.PostAsync(URL, data);
generic.Dispose();
return new KeyValuePair<HttpStatusCode, string>(response.StatusCode, await response.Content.ReadAsStringAsync());
}
}
}

111
WMstodon/JSONClasses.cs Normal file
View file

@ -0,0 +1,111 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WMstodon
{
public class Account
{
public string id { get; set; }
public string username { get; set; }
public string acct { get; set; }
public string display_name { get; set; }
public bool locked { get; set; }
public bool bot { get; set; }
public bool discoverable { get; set; }
public bool group { get; set; }
public DateTime created_at { get; set; }
public string note { get; set; }
public string url { get; set; }
public string avatar { get; set; }
public string avatar_static { get; set; }
public string header { get; set; }
public string header_static { get; set; }
public int followers_count { get; set; }
public int following_count { get; set; }
public int statuses_count { get; set; }
public object last_status_at { get; set; }
public object source { get; set; }
public object[] emojis { get; set; }
public object[] fields { get; set; }
}
public class Attachment
{
public string id { get; set; }
public string type { get; set; }
public string url { get; set; }
public string preview_url { get; set; }
public string remote_url { get; set; }
public string text_url { get; set; }
public AttachmentMeta meta { get; set; }
public string description { get; set; }
public string blurhash { get; set; }
}
public class AttachmentMeta
{
public AttachmentFocus focus { get; set; }
public AttachmentSizing original { get; set; }
public AttachmentSizing small { get; set; }
}
public class AttachmentFocus
{
public float x { get; set; }
public float y { get; set; }
}
public class AttachmentSizing
{
public int width { get; set; }
public int height { get; set; }
public string size { get; set; }
public float aspect { get; set; }
}
public class Status
{
public string id { get; set; }
public DateTime created_at { get; set; }
public object in_reply_to_id { get; set; }
public object in_reply_to_account_id { get; set; }
public bool sensitive { get; set; }
public string spoiler_text { get; set; }
public string visibility { get; set; }
public string language { get; set; }
public string uri { get; set; }
public string url { get; set; }
public int replies_count { get; set; }
public int reblogs_count { get; set; }
public int favourites_count { get; set; }
public bool favourited { get; set; }
public bool reblogged { get; set; }
public bool muted { get; set; }
public bool bookmarked { get; set; }
public string content { get; set; }
public object reblog { get; set; }
public MApplication application { get; set; }
public Account account { get; set; }
public Attachment[] media_attachments { get; set; }
public object[] mentions { get; set; }
public object[] tags { get; set; }
public object[] emojis { get; set; }
public object card { get; set; }
public object poll { get; set; }
}
public class Feed
{
public Status[] statuses { get; set; }
}
public class MApplication
{
public string name { get; set; }
public string website { get; set; }
}
}

21
WMstodon/LoginPage.xaml Normal file
View file

@ -0,0 +1,21 @@
<Page
x:Class="WMstodon.LoginPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:WMstodon"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<TextBox x:Name="AuthCodeTextBox" Margin="10,0" TextWrapping="Wrap" Text="" VerticalAlignment="Center" PlaceholderText="Auth Code"/>
<Button x:Name="OpenAuthPageButton" Content="Open auth page in browser" HorizontalAlignment="Stretch" Margin="10,0,10,75" VerticalAlignment="Center" Click="OpenAuthPageButton_Click"/>
<Button x:Name="LogInButton" Content="Log In" HorizontalAlignment="Right" Margin="0,75,10,0" VerticalAlignment="Center" Width="75" Click="LogInButton_Click"/>
<TextBlock HorizontalAlignment="Center" Margin="0,0,0,300" TextWrapping="Wrap" Text="Placeholder Text" VerticalAlignment="Center"/>
<Button x:Name="BackButton" Content="Back" HorizontalAlignment="Left" Margin="10,75,0,0" VerticalAlignment="Center" Width="75" Click="BackButton_Click"/>
<TextBlock x:Name="ErrorTextBlock" HorizontalAlignment="Left" Margin="10,150,10,0" TextWrapping="Wrap" Text="" VerticalAlignment="Center" FocusVisualPrimaryBrush="Red" Foreground="Red"/>
<TextBlock x:Name="InstanceTextBlock" HorizontalAlignment="Left" Margin="10,0,0,133" TextWrapping="Wrap" Text="Instance:" VerticalAlignment="Center" FontSize="12"/>
</Grid>
</Page>

View file

@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using Newtonsoft.Json.Linq;
using Windows.Storage;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace WMstodon
{
public sealed partial class LoginPage : Page
{
JObject passedArgument;
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
public LoginPage()
{
this.InitializeComponent();
}
private async void OpenAuthPageButton_Click(object sender, RoutedEventArgs e)
{
await Windows.System.Launcher.LaunchUriAsync(new Uri(localSettings.Values["instanceURL"] + "/oauth/authorize" +
"?client_id=" + passedArgument["client_id"] + "" +
"&scope=read+write+push" +
"&redirect_uri=urn:ietf:wg:oauth:2.0:oob" +
"&response_type=code"
));
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
passedArgument = (JObject)e.Parameter;
InstanceTextBlock.Text = (string)localSettings.Values["instanceURL"];
}
private void BackButton_Click(object sender, RoutedEventArgs e)
{
Frame.GoBack();
}
private async void LogInButton_Click(object sender, RoutedEventArgs e)
{
Dictionary<string, string> postopts = new Dictionary<string, string>();
postopts["client_id"] = (string)passedArgument["client_id"];
postopts["client_secret"] = (string)passedArgument["client_secret"];
postopts["redirect_uri"] = "urn:ietf:wg:oauth:2.0:oob";
postopts["grant_type"] = "authorization_code";
postopts["code"] = AuthCodeTextBox.Text;
postopts["scope"] = "read write push";
KeyValuePair<HttpStatusCode, string> response =
await HTTPUtils.POSTAsync("/oauth/token", new FormUrlEncodedContent(postopts));
if (response.Key == HttpStatusCode.OK)
{
JObject appResponseObj = JObject.Parse(response.Value);
localSettings.Values["accessToken"] = (string)appResponseObj["access_token"];
if ((await HTTPUtils.GETAsync("/api/v1/accounts/verify_credentials")).Key != HttpStatusCode.OK)
{
ErrorTextBlock.Text = "Could not log into service";
return;
}
Frame.Navigate(typeof(MainPage), appResponseObj);
}
else
{
ErrorTextBlock.Text = "Could not log into service:\n" + response.Key;
}
}
}
}

View file

@ -9,6 +9,9 @@
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Image x:Name="myAvatar" HorizontalAlignment="Left" Height="40" Margin="10,0,0,10" VerticalAlignment="Bottom" Width="40"/>
<TextBlock x:Name="DisplayNameTextBlock" HorizontalAlignment="Left" Margin="60,0,0,30" TextWrapping="Wrap" Text="Loading..." VerticalAlignment="Bottom"/>
<TextBlock x:Name="UsernameTextBlock" HorizontalAlignment="Left" Margin="60,0,0,15" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Bottom" FontSize="12" Foreground="#FF777777"/>
</Grid>
</Page>

View file

@ -3,28 +3,46 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Newtonsoft.Json;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Storage;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace WMstodon
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
Account myAccount;
public MainPage()
{
this.InitializeComponent();
}
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
string accountJSON = (await HTTPUtils.GETAsync("/api/v1/accounts/verify_credentials")).Value;
myAccount = JsonConvert.DeserializeObject<Account>(accountJSON);
DisplayNameTextBlock.Text = $"{myAccount.display_name}";
UsernameTextBlock.Text = $"@{myAccount.username}@{new Uri((string)localSettings.Values["instanceURL"]).DnsSafeHost}";
BitmapImage bitmap = new BitmapImage();
bitmap.UriSource = new Uri(myAccount.avatar_static);
myAvatar.Source = bitmap;
//await LoadFeed();
}
}
}

View file

@ -0,0 +1,18 @@
<Page
x:Class="WMstodon.SelectInstancePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:WMstodon"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Loaded="Page_Loaded">
<Grid>
<TextBox x:Name="InstanceURLTextBox" Margin="10,0" TextWrapping="Wrap" Text="" VerticalAlignment="Center" PlaceholderText="Enter your Instance URL"/>
<Button x:Name="NextButton" Content="Next" HorizontalAlignment="Right" Margin="0,75,10,0" VerticalAlignment="Center" Width="75" Click="NextButton_Click"/>
<TextBlock x:Name="GreetingTextBlock" HorizontalAlignment="Center" Margin="0,0,0,200" TextWrapping="Wrap" Text="How do you do?" VerticalAlignment="Center" FontSize="24"/>
<TextBlock x:Name="ErrorTextBlock" HorizontalAlignment="Left" Margin="10,150,10,0" TextWrapping="Wrap" Text="" VerticalAlignment="Center" FocusVisualPrimaryBrush="Red" Foreground="Red"/>
</Grid>
</Page>

View file

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using Newtonsoft.Json.Linq;
using Windows.Storage;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace WMstodon
{
public sealed partial class SelectInstancePage : Page
{
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
public SelectInstancePage()
{
this.InitializeComponent();
}
private async void NextButton_Click(object sender, RoutedEventArgs e)
{
Dictionary<string, string> postopts = new Dictionary<string, string>();
postopts["client_name"] = "WMStodon";
postopts["redirect_uris"] = "urn:ietf:wg:oauth:2.0:oob";
postopts["scopes"] = "read write push";
postopts["website"] = "https://github.com/kawaiizenbo/WMStodon";
KeyValuePair<HttpStatusCode, string> response =
await HTTPUtils.POSTGenericAsync(InstanceURLTextBox.Text + "/api/v1/apps", new FormUrlEncodedContent(postopts));
if (response.Key == HttpStatusCode.OK)
{
JObject appResponseObj = JObject.Parse(response.Value);
localSettings.Values["instanceURL"] = InstanceURLTextBox.Text;
Frame.Navigate(typeof(LoginPage), appResponseObj);
}
else ErrorTextBlock.Text = "Could not create application on instance:\n" + response.Key;
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
if (localSettings.Values["instanceURL"] != null && localSettings.Values["accessToken"] != null) Frame.Navigate(typeof(MainPage), null);
}
}
}

View file

@ -119,10 +119,18 @@
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
</Compile>
<Compile Include="HTTPUtils.cs" />
<Compile Include="JSONClasses.cs" />
<Compile Include="LoginPage.xaml.cs">
<DependentUpon>LoginPage.xaml</DependentUpon>
</Compile>
<Compile Include="MainPage.xaml.cs">
<DependentUpon>MainPage.xaml</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SelectInstancePage.xaml.cs">
<DependentUpon>SelectInstancePage.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
@ -145,14 +153,25 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Page Include="LoginPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="MainPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="SelectInstancePage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>6.2.8</Version>
<Version>6.2.14</Version>
</PackageReference>
<PackageReference Include="Newtonsoft.Json">
<Version>13.0.2</Version>
</PackageReference>
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">