WIP probably going to go with WebView2 instead

This commit is contained in:
Timothy Baldridge 2022-01-27 22:35:17 -07:00
parent f2c6241742
commit 95feacc209
6 changed files with 155 additions and 55 deletions

View File

@ -11,57 +11,6 @@ namespace Wabbajack.CLI.Browser;
public static class BrowserExtensions public static class BrowserExtensions
{ {
public static async Task WaitForReady(this WebView browser)
{
while (!browser.IsInitialized)
{
await Task.Delay(250);
}
while (browser.BrowserObject == null)
{
await Task.Delay(250);
}
}
public static async Task NavigateTo(this WebView browser, Uri location)
{
browser.Navigate(location.ToString());
await browser.WaitForIdle();
}
public static async Task WaitForIdle(this WebView browser)
{
while (browser.IsBusy)
{
await Task.Delay(250);
}
}
public static async Task<Cookie[]> Cookies(this WebView view, string domainEnding, CancellationToken token)
{
var results = CefCookieManager.GetGlobalManager(null)!;
var cookies = await results.GetCookiesAsync(c => c.Domain.EndsWith(domainEnding), token)!;
return cookies.Select(c => new Cookie
{
Domain = c.Domain,
Name = c.Name,
Path = c.Path,
Value = c.Value
}).ToArray();
}
public static async Task EvaluateJavaScript(this WebView view, string js)
{
view.GetMainFrame().ExecuteJavaScript(js, "", 0);
}
public static async Task<HtmlDocument> GetDom(this WebView view, CancellationToken token)
{
var source = await view.GetMainFrame().GetSourceAsync(token);
var doc = new HtmlDocument();
doc.LoadHtml(source);
return doc;
}
} }

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia; using Avalonia;
@ -7,7 +8,9 @@ using Avalonia.ReactiveUI;
using Avalonia.Threading; using Avalonia.Threading;
using CefNet; using CefNet;
using CefNet.Avalonia; using CefNet.Avalonia;
using HtmlAgilityPack;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Wabbajack.DTOs.Logins;
namespace Wabbajack.CLI.Browser namespace Wabbajack.CLI.Browser
{ {
@ -66,5 +69,72 @@ namespace Wabbajack.CLI.Browser
_mainWindowViewModel = vm; _mainWindowViewModel = vm;
_browser = browser; _browser = browser;
} }
public string Instructions
{
set
{
Dispatcher.UIThread.Post(() =>
{
_mainWindowViewModel.Instructions = value;
});
}
}
public async Task WaitForReady()
{
while (!_browser.IsInitialized)
{
await Task.Delay(250);
}
while (_browser.BrowserObject == null)
{
await Task.Delay(250);
}
}
public async Task NavigateTo(Uri location)
{
await Dispatcher.UIThread.InvokeAsync(() =>
{
_browser.Navigate(location.ToString());
});
await WaitForIdle();
}
public async Task WaitForIdle()
{
while (_browser.IsBusy)
{
await Task.Delay(250);
}
}
public async Task<Cookie[]> Cookies(string domainEnding, CancellationToken token)
{
var results = CefCookieManager.GetGlobalManager(null)!;
var cookies = await results.GetCookiesAsync(c => c.Domain.EndsWith(domainEnding), token)!;
return cookies.Select(c => new Cookie
{
Domain = c.Domain,
Name = c.Name,
Path = c.Path,
Value = c.Value
}).ToArray();
}
public async Task EvaluateJavaScript(string js)
{
_browser.GetMainFrame().ExecuteJavaScript(js, "", 0);
}
public async Task<HtmlDocument> GetDom(CancellationToken token)
{
var source = await _browser.GetMainFrame().GetSourceAsync(token);
var doc = new HtmlDocument();
doc.LoadHtml(source);
return doc;
}
} }
} }

View File

@ -97,6 +97,6 @@ internal class Program
reg.Register<VfsIndexFolder>(VfsIndexFolder.MakeCommand); reg.Register<VfsIndexFolder>(VfsIndexFolder.MakeCommand);
reg.Register<NexusLogin>(NexusLogin.MakeCommand); reg.Register<NexusLogin>(NexusLogin.MakeCommand);
return await service!.Run(args); return await service.Run(args);
} }
} }

View File

@ -1,9 +1,14 @@
using System;
using System.CommandLine; using System.CommandLine;
using System.CommandLine.Invocation; using System.CommandLine.Invocation;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Fizzler.Systems.HtmlAgilityPack;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Wabbajack.CLI.Browser; using Wabbajack.CLI.Browser;
using Wabbajack.DTOs.Logins;
using Wabbajack.Services.OSIntegrated;
namespace Wabbajack.CLI.Verbs; namespace Wabbajack.CLI.Verbs;
@ -11,11 +16,13 @@ public class NexusLogin : AVerb
{ {
private readonly ILogger<NexusLogin> _logger; private readonly ILogger<NexusLogin> _logger;
private readonly BrowserHost _host; private readonly BrowserHost _host;
private readonly EncryptedJsonTokenProvider<NexusApiState> _tokenProvider;
public NexusLogin(ILogger<NexusLogin> logger, BrowserHost host) public NexusLogin(ILogger<NexusLogin> logger, BrowserHost host, EncryptedJsonTokenProvider<NexusApiState> tokenProvider)
{ {
_logger = logger; _logger = logger;
_host = host; _host = host;
_tokenProvider = tokenProvider;
} }
public static Command MakeCommand() public static Command MakeCommand()
@ -29,6 +36,79 @@ public class NexusLogin : AVerb
{ {
var browser = await _host.CreateBrowser(); var browser = await _host.CreateBrowser();
token.ThrowIfCancellationRequested();
browser.Instructions = "Please log into the Nexus";
await browser.WaitForReady();
await browser.NavigateTo(new Uri(
"https://users.nexusmods.com/auth/continue?client_id=nexus&redirect_uri=https://www.nexusmods.com/oauth/callback&response_type=code&referrer=//www.nexusmods.com"));
Cookie[] cookies = { };
while (true)
{
cookies = await browser.Cookies("nexusmods.com", token);
if (cookies.Any(c => c.Name == "member_id"))
break;
token.ThrowIfCancellationRequested();
await Task.Delay(500, token);
}
browser.Instructions = "Getting API Key...";
await browser.NavigateTo(new Uri("https://www.nexusmods.com/users/myaccount?tab=api"));
var key = "";
while (true)
{
try
{
key = (await browser.GetDom(token))
.DocumentNode
.QuerySelectorAll("input[value=wabbajack]")
.SelectMany(p => p.ParentNode.ParentNode.QuerySelectorAll("textarea.application-key"))
.Select(node => node.InnerHtml)
.FirstOrDefault() ?? "";
}
catch (Exception)
{
// ignored
}
if (!string.IsNullOrEmpty(key))
break;
try
{
await browser.EvaluateJavaScript(
"var found = document.querySelector(\"input[value=wabbajack]\").parentElement.parentElement.querySelector(\"form button[type=submit]\");" +
"found.onclick= function() {return true;};" +
"found.class = \" \"; " +
"found.click();" +
"found.remove(); found = undefined;"
);
browser.Instructions = "Generating API Key, Please Wait...";
}
catch (Exception)
{
// ignored
}
token.ThrowIfCancellationRequested();
await Task.Delay(500, token);
}
browser.Instructions = "Success, saving information...";
await _tokenProvider.SetToken(new NexusApiState
{
Cookies = cookies,
ApiKey = key
});
return 0; return 0;
} }

View File

@ -14,6 +14,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="HtmlAgilityPack" Version="1.11.40" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.2-mauipre.1.22054.8" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.2-mauipre.1.22054.8" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.2-mauipre.1.22054.8" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.2-mauipre.1.22054.8" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.2-mauipre.1.22054.8" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.2-mauipre.1.22054.8" />

View File

@ -113,7 +113,7 @@ public static class ServiceExtensions
service.AddSingleton<WriteOnlyClient>(); service.AddSingleton<WriteOnlyClient>();
// Token Providers // Token Providers
service.AddAllSingleton<ITokenProvider<NexusApiState>, NexusApiTokenProvider>(); service.AddAllSingleton<ITokenProvider<NexusApiState>, EncryptedJsonTokenProvider<NexusApiState>, NexusApiTokenProvider>();
service service
.AddAllSingleton<ITokenProvider<LoversLabLoginState>, EncryptedJsonTokenProvider<LoversLabLoginState>, .AddAllSingleton<ITokenProvider<LoversLabLoginState>, EncryptedJsonTokenProvider<LoversLabLoginState>,
LoversLabTokenProvider>(); LoversLabTokenProvider>();