Can login to IPS4 sites, and can log in via Google

This commit is contained in:
Timothy Baldridge 2022-01-04 14:16:53 -07:00
parent 9f87d91918
commit 764895de49
21 changed files with 451 additions and 137 deletions

View File

@ -66,11 +66,16 @@ namespace Wabbajack
services.AddTransient<InstallerVM>();
services.AddTransient<WebBrowserVM>();
// Login Handlers
services.AddTransient<VectorPlexusLoginHandler>();
services.AddTransient<NexusLoginHandler>();
services.AddTransient<LoversLabLoginHandler>();
// Login Managers
services.AddAllSingleton<INeedsLogin, LoversLabLoginManager>();
services.AddAllSingleton<INeedsLogin, NexusLoginManager>();
services.AddAllSingleton<INeedsLogin, VectorPlexusLoginManager>();
return services;
}

View File

@ -37,12 +37,12 @@ namespace Wabbajack.LibCefHelpers
return container;
}
public static async Task<Cookie[]> GetCookies(string domainEnding = "")
public static async Task<DTOs.Logins.Cookie[]> GetCookies(string domainEnding = "")
{
var manager = Cef.GetGlobalCookieManager();
var visitor = new CookieVisitor();
if (!manager.VisitAllCookies(visitor))
return new Cookie[0];
return Array.Empty<DTOs.Logins.Cookie>();
var cc = await visitor.Task;
return (await visitor.Task).Where(c => c.Domain.EndsWith(domainEnding)).ToArray();
@ -50,10 +50,10 @@ namespace Wabbajack.LibCefHelpers
private class CookieVisitor : ICookieVisitor
{
TaskCompletionSource<List<Cookie>> _source = new TaskCompletionSource<List<Cookie>>();
public Task<List<Cookie>> Task => _source.Task;
TaskCompletionSource<List<DTOs.Logins.Cookie>> _source = new();
public Task<List<DTOs.Logins.Cookie>> Task => _source.Task;
public List<Cookie> Cookies { get; } = new List<Cookie>();
public List<DTOs.Logins.Cookie> Cookies { get; } = new ();
public void Dispose()
{
_source.SetResult(Cookies);
@ -61,7 +61,7 @@ namespace Wabbajack.LibCefHelpers
public bool Visit(CefSharp.Cookie cookie, int count, int total, ref bool deleteCookie)
{
Cookies.Add(new Cookie
Cookies.Add(new DTOs.Logins.Cookie
{
Name = cookie.Name,
Value = cookie.Value,
@ -74,16 +74,6 @@ namespace Wabbajack.LibCefHelpers
return true;
}
}
[JsonName("HttpCookie")]
public class Cookie
{
public string Name { get; set; } = string.Empty;
public string Value { get; set; } = string.Empty;
public string Domain { get; set; } = string.Empty;
public string Path { get; set; } = string.Empty;
}
public static void ClearCookies()
{
var manager = Cef.GetGlobalCookieManager();
@ -91,7 +81,7 @@ namespace Wabbajack.LibCefHelpers
manager.VisitAllCookies(visitor);
}
public static async Task DeleteCookiesWhere(Func<Cookie,bool> filter)
public static async Task DeleteCookiesWhere(Func<DTOs.Logins.Cookie,bool> filter)
{
var manager = Cef.GetGlobalCookieManager();
var visitor = new CookieDeleter(filter);
@ -101,9 +91,9 @@ namespace Wabbajack.LibCefHelpers
class CookieDeleter : ICookieVisitor
{
private Func<Helpers.Cookie, bool>? _filter;
private Func<DTOs.Logins.Cookie, bool>? _filter;
public CookieDeleter(Func<Helpers.Cookie, bool>? filter = null)
public CookieDeleter(Func<DTOs.Logins.Cookie, bool>? filter = null)
{
_filter = filter;
}
@ -119,7 +109,7 @@ namespace Wabbajack.LibCefHelpers
}
else
{
var conv = new Helpers.Cookie
var conv = new DTOs.Logins.Cookie
{
Name = cookie.Name, Domain = cookie.Domain, Value = cookie.Value, Path = cookie.Path
};

View File

@ -0,0 +1,64 @@
using System;
using System.Drawing;
using System.Reactive.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Microsoft.Extensions.Logging;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Wabbajack.Common;
using Wabbajack.DTOs.Interventions;
using Wabbajack.DTOs.Logins;
using Wabbajack.Messages;
using Wabbajack.Networking.Http.Interfaces;
namespace Wabbajack.LoginManagers;
public class LoversLabLoginManager : ViewModel, INeedsLogin
{
private readonly ILogger<LoversLabLoginManager> _logger;
private readonly ITokenProvider<LoversLabLoginState> _token;
private readonly IUserInterventionHandler _handler;
public string SiteName { get; } = "Lovers Lab";
public ICommand TriggerLogin { get; set; }
public ICommand ClearLogin { get; set; }
public ImageSource Icon { get; set; }
[Reactive]
public bool HaveLogin { get; set; }
public LoversLabLoginManager(ILogger<LoversLabLoginManager> logger, ITokenProvider<LoversLabLoginState> token)
{
_logger = logger;
_token = token;
RefreshTokenState();
ClearLogin = ReactiveCommand.CreateFromTask(async () =>
{
_logger.LogInformation("Deleting Login information for {SiteName}", SiteName);
await _token.Delete();
RefreshTokenState();
}, this.WhenAnyValue(v => v.HaveLogin));
Icon = BitmapFrame.Create(
typeof(NexusLoginManager).Assembly.GetManifestResourceStream("Wabbajack.LoginManagers.Icons.nexus.png")!);
TriggerLogin = ReactiveCommand.CreateFromTask(async () =>
{
_logger.LogInformation("Logging into {SiteName}", SiteName);
await LoversLabLogin.Send();
RefreshTokenState();
}, this.WhenAnyValue(v => v.HaveLogin).Select(v => !v));
}
private void RefreshTokenState()
{
HaveLogin = _token.HaveToken();
}
}

View File

@ -1,16 +1,10 @@
using System;
using System.Drawing;
using System.Reactive.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Microsoft.Extensions.Logging;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Wabbajack.Common;
using Wabbajack.DTOs.Interventions;
using Wabbajack.DTOs.Logins;
using Wabbajack.Messages;

View File

@ -0,0 +1,64 @@
using System;
using System.Drawing;
using System.Reactive.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Microsoft.Extensions.Logging;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Wabbajack.Common;
using Wabbajack.DTOs.Interventions;
using Wabbajack.DTOs.Logins;
using Wabbajack.Messages;
using Wabbajack.Networking.Http.Interfaces;
namespace Wabbajack.LoginManagers;
public class VectorPlexusLoginManager : ViewModel, INeedsLogin
{
private readonly ILogger<VectorPlexusLoginManager> _logger;
private readonly ITokenProvider<VectorPlexusLoginState> _token;
private readonly IUserInterventionHandler _handler;
public string SiteName { get; } = "Vector Plexus";
public ICommand TriggerLogin { get; set; }
public ICommand ClearLogin { get; set; }
public ImageSource Icon { get; set; }
[Reactive]
public bool HaveLogin { get; set; }
public VectorPlexusLoginManager(ILogger<VectorPlexusLoginManager> logger, ITokenProvider<VectorPlexusLoginState> token)
{
_logger = logger;
_token = token;
RefreshTokenState();
ClearLogin = ReactiveCommand.CreateFromTask(async () =>
{
_logger.LogInformation("Deleting Login information for {SiteName}", SiteName);
await _token.Delete();
RefreshTokenState();
}, this.WhenAnyValue(v => v.HaveLogin));
Icon = BitmapFrame.Create(
typeof(NexusLoginManager).Assembly.GetManifestResourceStream("Wabbajack.LoginManagers.Icons.nexus.png")!);
TriggerLogin = ReactiveCommand.CreateFromTask(async () =>
{
_logger.LogInformation("Logging into {SiteName}", SiteName);
await VectorPlexusLogin.Send();
RefreshTokenState();
}, this.WhenAnyValue(v => v.HaveLogin).Select(v => !v));
}
private void RefreshTokenState()
{
HaveLogin = _token.HaveToken();
}
}

View File

@ -0,0 +1,34 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using ReactiveUI;
using Wabbajack.DTOs.Interventions;
namespace Wabbajack.Messages;
public class ALoginMessage : IUserIntervention
{
private readonly CancellationTokenSource _source;
public TaskCompletionSource CompletionSource { get; }
public CancellationToken Token => _source.Token;
public void SetException(Exception exception)
{
CompletionSource.SetException(exception);
_source.Cancel();
}
public ALoginMessage()
{
CompletionSource = new TaskCompletionSource();
_source = new CancellationTokenSource();
}
public void Cancel()
{
_source.Cancel();
CompletionSource.TrySetCanceled();
}
public bool Handled => CompletionSource.Task.IsCompleted;
}

View File

@ -0,0 +1,15 @@
using System.Threading.Tasks;
using ReactiveUI;
namespace Wabbajack.Messages;
public class LoversLabLogin : ALoginMessage
{
public static Task Send()
{
var msg = new LoversLabLogin();
MessageBus.Current.SendMessage(msg);
return msg.CompletionSource.Task;
}
}

View File

@ -7,36 +7,16 @@ using Wabbajack.Networking.Http.Interfaces;
namespace Wabbajack.Messages;
public class NexusLogin : IUserIntervention
public class NexusLogin : ALoginMessage
{
private readonly CancellationTokenSource _source;
public TaskCompletionSource CompletionSource { get; }
public CancellationToken Token => _source.Token;
public void SetException(Exception exception)
{
CompletionSource.SetException(exception);
_source.Cancel();
}
public NexusLogin()
{
CompletionSource = new TaskCompletionSource();
_source = new CancellationTokenSource();
}
public static Task Send()
{
var msg = new NexusLogin();
MessageBus.Current.SendMessage(msg);
return msg.CompletionSource.Task;
}
public void Cancel()
{
_source.Cancel();
CompletionSource.TrySetCanceled();
}
public bool Handled => CompletionSource.Task.IsCompleted;
}

View File

@ -0,0 +1,15 @@
using System.Threading.Tasks;
using ReactiveUI;
namespace Wabbajack.Messages;
public class VectorPlexusLogin : ALoginMessage
{
public static Task Send()
{
var msg = new VectorPlexusLogin();
MessageBus.Current.SendMessage(msg);
return msg.CompletionSource.Task;
}
}

View File

@ -1,5 +1,5 @@
using System;
using System.Threading.Tasks;
using System.Reactive.Subjects;
using CefSharp;
using CefSharp.Wpf;
using Microsoft.Extensions.Logging;
@ -10,7 +10,9 @@ public class CefService
{
private readonly ILogger<CefService> _logger;
private bool Inited { get; set; } = false;
private readonly Subject<string> _schemeStream = new();
public IObservable<string> SchemeStream => _schemeStream;
public Func<IBrowser, IFrame, string, IRequest, IResourceHandler>? SchemeHandler { get; set; }
public CefService(ILogger<CefService> logger)
@ -31,7 +33,7 @@ public class CefService
var settings = new CefSettings
{
CachePath = Consts.CefCacheLocation.ToString(),
JavascriptFlags = "--noexpose_wasm"
UserAgent = "Wabbajack In-App Browser"
};
settings.RegisterScheme(new CefCustomScheme()
{
@ -60,9 +62,9 @@ public class CefService
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
{
_logger.LogInformation("Scheme handler Got: {Scheme} : {Url}", schemeName, request.Url);
if (_service.SchemeHandler != null && schemeName == "wabbajack")
if (schemeName == "wabbajack")
{
return _service.SchemeHandler!(browser, frame, schemeName, request);
_service._schemeStream.OnNext(request.Url);
}
return new ResourceHandler();
}

View File

@ -0,0 +1,16 @@
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Wabbajack.Models;
using Wabbajack.Networking.Http.Interfaces;
namespace Wabbajack.UserIntervention;
public class LoversLabLoginHandler : OAuth2LoginHandler<Messages.LoversLabLogin, DTOs.Logins.LoversLabLoginState>
{
public LoversLabLoginHandler(ILogger<LoversLabLoginHandler> logger, HttpClient client, ITokenProvider<DTOs.Logins.LoversLabLoginState> tokenProvider,
WebBrowserVM browser, CefService service)
: base(logger, client, tokenProvider, browser, service)
{
}
}

View File

@ -6,20 +6,22 @@ using ReactiveUI;
using Wabbajack.DTOs.Logins;
using Wabbajack.LibCefHelpers;
using Wabbajack.Messages;
using Wabbajack.Models;
using Wabbajack.Networking.Http.Interfaces;
using Wabbajack.Services.OSIntegrated.TokenProviders;
namespace Wabbajack.UserIntervention;
public class NexusLoginHandler : WebUserInterventionBase
public class NexusLoginHandler : WebUserInterventionBase<NexusLogin>
{
private readonly ITokenProvider<NexusApiState> _provider;
public NexusLoginHandler(ILogger<NexusLoginHandler> logger, WebBrowserVM browserVM, ITokenProvider<NexusApiState> provider) : base(logger, browserVM)
public NexusLoginHandler(ILogger<NexusLoginHandler> logger, WebBrowserVM browserVM, ITokenProvider<NexusApiState> provider, CefService service)
: base(logger, browserVM, service)
{
_provider = provider;
}
public async Task Begin()
public override async Task Begin()
{
try
{
@ -29,7 +31,7 @@ public class NexusLoginHandler : WebUserInterventionBase
await 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"));
Helpers.Cookie[] cookies = {};
Cookie[] cookies = {};
while (true)
{
cookies = await Driver.GetCookies("nexusmods.com");
@ -89,13 +91,7 @@ public class NexusLoginHandler : WebUserInterventionBase
await _provider.SetToken(new NexusApiState()
{
ApiKey = key,
Cookies = cookies.Select(c => new Cookie()
{
Domain = c.Domain,
Name = c.Name,
Path = c.Path,
Value = c.Value
}).ToArray()
Cookies = cookies
});
((NexusLogin)Message).CompletionSource.SetResult();

View File

@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using Microsoft.Extensions.Logging;
using ReactiveUI;
using Wabbajack.DTOs.Interventions;
using Wabbajack.DTOs.Logins;
using Wabbajack.Messages;
using Wabbajack.Models;
using Wabbajack.Networking.Http.Interfaces;
using Wabbajack.Services.OSIntegrated;
namespace Wabbajack.UserIntervention;
public abstract class OAuth2LoginHandler<TIntervention, TLoginType> : WebUserInterventionBase<TIntervention>
where TIntervention : IUserIntervention
where TLoginType : OAuth2LoginState, new()
{
private readonly HttpClient _httpClient;
private readonly ITokenProvider<TLoginType> _tokenProvider;
public OAuth2LoginHandler(ILogger logger, HttpClient httpClient,
ITokenProvider<TLoginType> tokenProvider, WebBrowserVM browserVM, CefService service) : base(logger, browserVM, service)
{
_httpClient = httpClient;
_tokenProvider = tokenProvider;
}
public override async Task Begin()
{
Messages.NavigateTo.Send(Browser);
var tlogin = new TLoginType();
await Driver.WaitForInitialized();
using var handler = Driver.WithSchemeHandler(uri => uri.Scheme == "wabbajack");
UpdateStatus($"Please log in and allow Wabbajack to access your {tlogin.SiteName} account");
var scopes = string.Join(" ", tlogin.Scopes);
var state = Guid.NewGuid().ToString();
await NavigateTo(new Uri(tlogin.AuthorizationEndpoint + $"?response_type=code&client_id={tlogin.ClientID}&state={state}&scope={scopes}"));
var uri = await handler.Task.WaitAsync(Message.Token);
var cookies = await Driver.GetCookies(tlogin.AuthorizationEndpoint.Host);
var parsed = HttpUtility.ParseQueryString(uri.Query);
if (parsed.Get("state") != state)
{
Logger.LogCritical("Bad OAuth state, this shouldn't happen");
throw new Exception("Bad OAuth State");
}
if (parsed.Get("code") == null)
{
Logger.LogCritical("Bad code result from OAuth");
throw new Exception("Bad code result from OAuth");
}
var authCode = parsed.Get("code");
var formData = new KeyValuePair<string?, string?>[]
{
new("grant_type", "authorization_code"),
new("code", authCode),
new("client_id", tlogin.ClientID)
};
var msg = new HttpRequestMessage();
msg.Method = HttpMethod.Post;
msg.RequestUri = tlogin.TokenEndpoint;
msg.Headers.Add("User-Agent",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36");
msg.Headers.Add("Cookie", string.Join(";", cookies.Select(c => $"{c.Name}={c.Value}")));
msg.Content = new FormUrlEncodedContent(formData.ToList());
using var response = await _httpClient.SendAsync(msg, Message.Token);
var data = await response.Content.ReadFromJsonAsync<OAuthResultState>(cancellationToken: Message.Token);
await _tokenProvider.SetToken(new TLoginType
{
Cookies = cookies,
ResultState = data!
});
Messages.NavigateTo.Send(PrevPane);
}
}

View File

@ -0,0 +1,15 @@
using System.Net.Http;
using Microsoft.Extensions.Logging;
using Wabbajack.Models;
using Wabbajack.Networking.Http.Interfaces;
namespace Wabbajack.UserIntervention;
public class VectorPlexusLoginHandler : OAuth2LoginHandler<Messages.VectorPlexusLogin, DTOs.Logins.VectorPlexusLoginState>
{
public VectorPlexusLoginHandler(ILogger<VectorPlexusLoginHandler> logger, HttpClient client, ITokenProvider<DTOs.Logins.VectorPlexusLoginState> tokenProvider,
WebBrowserVM browser, CefService service)
: base(logger, client, tokenProvider, browser, service)
{
}
}

View File

@ -4,26 +4,28 @@ using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Wabbajack.DTOs.Interventions;
using Wabbajack.Interventions;
using Wabbajack.Models;
using Wabbajack.WebAutomation;
namespace Wabbajack.UserIntervention;
public class WebUserInterventionBase
public abstract class WebUserInterventionBase<T>
where T : IUserIntervention
{
protected readonly WebBrowserVM Browser;
protected readonly ILogger Logger;
protected IUserIntervention Message;
protected T Message;
protected ViewModel PrevPane;
protected IWebDriver Driver;
public WebUserInterventionBase(ILogger logger, WebBrowserVM browser)
protected WebUserInterventionBase(ILogger logger, WebBrowserVM browser, CefService service)
{
Logger = logger;
Browser = browser;
Driver = new CefSharpWrapper(logger, browser.Browser);
Driver = new CefSharpWrapper(logger, browser.Browser, service);
}
public void Configure(ViewModel prevPane, IUserIntervention message)
public void Configure(ViewModel prevPane, T message)
{
Message = message;
PrevPane = prevPane;
@ -39,4 +41,6 @@ public class WebUserInterventionBase
await Driver.NavigateTo(uri, Message.Token);
}
public abstract Task Begin();
}

View File

@ -101,57 +101,22 @@ namespace Wabbajack
.DisposeWith(CompositeDisposable);
MessageBus.Current.Listen<NexusLogin>()
.Subscribe(m => HandleNexusLogin(m))
.Subscribe(HandleLogin)
.DisposeWith(CompositeDisposable);
MessageBus.Current.Listen<LoversLabLogin>()
.Subscribe(HandleLogin)
.DisposeWith(CompositeDisposable);
MessageBus.Current.Listen<VectorPlexusLogin>()
.Subscribe(HandleLogin)
.DisposeWith(CompositeDisposable);
_resourceMonitor.Updates
.Select(r => string.Join(", ", r.Where(r => r.Throughput > 0)
.Select(s => $"{s.Name} - {s.Throughput.ToFileSizeString()}/sec")))
.BindToStrict(this, view => view.ResourceStatus);
// Set up logging
/* TODO
Utils.LogMessages
.ObserveOn(RxApp.TaskpoolScheduler)
.ToObservableChangeSet()
.Buffer(TimeSpan.FromMilliseconds(250), RxApp.TaskpoolScheduler)
.Where(l => l.Count > 0)
.FlattenBufferResult()
.ObserveOnGuiThread()
.Bind(Log)
.Subscribe()
.DisposeWith(CompositeDisposable);
Utils.LogMessages
.Where(a => a is IUserIntervention or CriticalFailureIntervention)
.ObserveOnGuiThread()
.SelectTask(async msg =>
{
try
{
await UserInterventionHandlers.Handle(msg);
}
catch (Exception ex)
when (ex.GetType() != typeof(TaskCanceledException))
{
_logger.LogError(ex, "Error while handling user intervention of type {Type}",msg?.GetType());
try
{
if (msg is IUserIntervention {Handled: false} intervention)
{
intervention.Cancel();
}
}
catch (Exception cancelEx)
{
_logger.LogError(cancelEx, "Error while cancelling user intervention of type {Type}",msg?.GetType());
}
}
})
.Subscribe()
.DisposeWith(CompositeDisposable);
*/
if (IsStartingFromModlist(out var path))
{
@ -192,15 +157,30 @@ namespace Wabbajack
private void HandleNavigateTo(ViewModel objViewModel)
{
ActivePane = objViewModel;
}
private void HandleNexusLogin(NexusLogin nexusLogin)
private void HandleLogin(NexusLogin nexusLogin)
{
var handler = _serviceProvider.GetRequiredService<NexusLoginHandler>();
handler.Configure(ActivePane, nexusLogin);
handler.Begin().FireAndForget();
}
private void HandleLogin(LoversLabLogin loversLabLogin)
{
var handler = _serviceProvider.GetRequiredService<LoversLabLoginHandler>();
handler.Configure(ActivePane, loversLabLogin);
handler.Begin().FireAndForget();
}
private void HandleLogin(VectorPlexusLogin vectorPlexusLogin)
{
var handler = _serviceProvider.GetRequiredService<VectorPlexusLoginHandler>();
handler.Configure(ActivePane, vectorPlexusLogin);
handler.Begin().FireAndForget();
}
private void HandleNavigateBack(NavigateBack navigateBack)
{
@ -210,6 +190,9 @@ namespace Wabbajack
private void HandleNavigateTo(NavigateToGlobal.ScreenType s)
{
if (s is NavigateToGlobal.ScreenType.Settings)
PreviousPanes.Add(ActivePane);
ActivePane = s switch
{
NavigateToGlobal.ScreenType.ModeSelectionView => ModeSelectionVM,

View File

@ -12,6 +12,7 @@ using Microsoft.Extensions.Logging;
using ReactiveUI;
using Wabbajack;
using Wabbajack.LoginManagers;
using Wabbajack.Messages;
using Wabbajack.Networking.WabbajackClientApi;
using Wabbajack.Services.OSIntegrated.TokenProviders;
using Wabbajack.View_Models.Settings;
@ -39,6 +40,7 @@ namespace Wabbajack
provider.GetRequiredService<WabbajackApiTokenProvider>()!, provider.GetRequiredService<Client>()!, this);
Filters = mainWindowVM.Settings.Filters;
OpenTerminalCommand = ReactiveCommand.CreateFromTask(OpenTerminal);
BackCommand = ReactiveCommand.Create(NavigateBack.Send);
}
private async Task OpenTerminal()

View File

@ -48,7 +48,7 @@ namespace Wabbajack
BackCommand = ReactiveCommand.Create(NavigateBack.Send);
Browser = cefService.CreateBrowser();
Driver = new CefSharpWrapper(_logger, Browser);
Driver = new CefSharpWrapper(_logger, Browser, cefService);
}

View File

@ -3,21 +3,27 @@ using System.Threading;
using System.Threading.Tasks;
using CefSharp;
using Microsoft.Extensions.Logging;
using Microsoft.VisualBasic.CompilerServices;
using Wabbajack.LibCefHelpers;
using Wabbajack.Models;
using Wabbajack.Networking.Http;
using Wabbajack.Paths;
using Cookie = Wabbajack.DTOs.Logins.Cookie;
namespace Wabbajack.WebAutomation
{
public class CefSharpWrapper : IWebDriver
{
private readonly IWebBrowser _browser;
private static readonly Random RetryRandom = new Random();
private readonly ILogger _logger;
private readonly CefService _service;
public Action<Uri>? DownloadHandler { get; set; }
public CefSharpWrapper(ILogger logger, IWebBrowser browser)
public CefSharpWrapper(ILogger logger, IWebBrowser browser, CefService service)
{
_logger = logger;
_browser = browser;
_service = service;
_browser.DownloadHandler = new DownloadHandler(this);
_browser.LifeSpanHandler = new PopupBlocker(this);
@ -56,8 +62,7 @@ namespace Wabbajack.WebAutomation
("<h1>400 Bad Request</h1>", 400),
("We could not locate the item you are trying to view.", 404),
};
private static readonly Random RetryRandom = new Random();
private readonly ILogger _logger;
public async Task<long> NavigateToAndDownload(Uri uri, AbsolutePath dest, bool quickMode = false, CancellationToken? token = null)
{
@ -115,7 +120,7 @@ namespace Wabbajack.WebAutomation
return (string)result.Result;
}
public Task<Helpers.Cookie[]> GetCookies(string domainPrefix)
public Task<Cookie[]> GetCookies(string domainPrefix)
{
return Helpers.GetCookies(domainPrefix);
}
@ -127,6 +132,45 @@ namespace Wabbajack.WebAutomation
while (!_browser.IsBrowserInitialized)
await Task.Delay(100);
}
public ISchemeHandler WithSchemeHandler(Predicate<Uri> predicate)
{
return new SchemeHandler(predicate, _service);
}
private class SchemeHandler : ISchemeHandler
{
private readonly TaskCompletionSource<Uri> _tcs;
private readonly IDisposable _disposable;
public SchemeHandler(Predicate<Uri> predicate, CefService service)
{
_tcs = new TaskCompletionSource<Uri>();
_disposable = service.SchemeStream.Subscribe(s =>
{
if (Uri.TryCreate(s, UriKind.Absolute, out var result) && predicate(result))
{
_tcs.TrySetResult(result);
}
});
}
public void Dispose()
{
_tcs.TrySetCanceled();
_disposable.Dispose();
}
public Task<Uri> Task => _tcs.Task;
}
public async Task RegisterSchemeCallback()
{
var frame = _browser.GetFocusedFrame();
}
public string Location => _browser.Address;

View File

@ -1,11 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Wabbajack.LibCefHelpers;
using Wabbajack.DTOs.Logins;
namespace Wabbajack.WebAutomation
{
@ -13,8 +9,14 @@ namespace Wabbajack.WebAutomation
{
Task NavigateTo(Uri uri, CancellationToken? token = null);
Task<string> EvaluateJavaScript(string text);
Task<Helpers.Cookie[]> GetCookies(string domainPrefix);
Task<Cookie[]> GetCookies(string domainPrefix);
public Action<Uri>? DownloadHandler { get; set; }
public Task WaitForInitialized();
ISchemeHandler WithSchemeHandler(Predicate<Uri> wabbajack);
}
public interface ISchemeHandler : IDisposable
{
public Task<Uri> Task { get; }
}
}

View File

@ -9,6 +9,7 @@ using HtmlAgilityPack;
using Microsoft.Extensions.Logging;
using Wabbajack.Common;
using Wabbajack.LibCefHelpers;
using Wabbajack.Models;
using Wabbajack.Paths;
using Wabbajack.Paths.IO;
@ -19,19 +20,12 @@ namespace Wabbajack.WebAutomation
private readonly IWebBrowser _browser;
private readonly CefSharpWrapper _driver;
public Driver(ILogger logger)
public Driver(ILogger logger, CefService service)
{
_browser = new ChromiumWebBrowser();
_driver = new CefSharpWrapper(logger, _browser);
_driver = new CefSharpWrapper(logger, _browser, service);
}
public static async Task<Driver> Create(ILogger logger)
{
var driver = new Driver(logger);
await driver._driver.WaitForInitialized();
return driver;
}
public async Task<Uri?> NavigateTo(Uri uri, CancellationToken? token = null)
{
try
@ -118,7 +112,7 @@ namespace Wabbajack.WebAutomation
Helpers.ClearCookies();
}
public async Task DeleteCookiesWhere(Func<Helpers.Cookie, bool> filter)
public async Task DeleteCookiesWhere(Func<DTOs.Logins.Cookie, bool> filter)
{
await Helpers.DeleteCookiesWhere(filter);
}