mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Can login to IPS4 sites, and can log in via Google
This commit is contained in:
parent
9f87d91918
commit
764895de49
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
};
|
||||
|
64
Wabbajack.App.Wpf/LoginManagers/LoversLabLoginManager.cs
Normal file
64
Wabbajack.App.Wpf/LoginManagers/LoversLabLoginManager.cs
Normal 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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
64
Wabbajack.App.Wpf/LoginManagers/VectorPlexusLoginManager.cs
Normal file
64
Wabbajack.App.Wpf/LoginManagers/VectorPlexusLoginManager.cs
Normal 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();
|
||||
}
|
||||
}
|
34
Wabbajack.App.Wpf/Messages/ALoginMessage.cs
Normal file
34
Wabbajack.App.Wpf/Messages/ALoginMessage.cs
Normal 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;
|
||||
}
|
15
Wabbajack.App.Wpf/Messages/LoversLabLogin.cs
Normal file
15
Wabbajack.App.Wpf/Messages/LoversLabLogin.cs
Normal 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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
15
Wabbajack.App.Wpf/Messages/VectorPlexusLogin.cs
Normal file
15
Wabbajack.App.Wpf/Messages/VectorPlexusLogin.cs
Normal 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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
16
Wabbajack.App.Wpf/UserIntervention/LoversLabLoginHandler.cs
Normal file
16
Wabbajack.App.Wpf/UserIntervention/LoversLabLoginHandler.cs
Normal 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)
|
||||
{
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
95
Wabbajack.App.Wpf/UserIntervention/OAuth2LoginHandler.cs
Normal file
95
Wabbajack.App.Wpf/UserIntervention/OAuth2LoginHandler.cs
Normal 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);
|
||||
}
|
||||
}
|
@ -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)
|
||||
{
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
@ -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,
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user