From 0a709f97ea254bb9ac4ed16e8fa5f99b9d5c1721 Mon Sep 17 00:00:00 2001 From: whimsical-c4lic0 Date: Fri, 20 Feb 2026 00:35:19 -0600 Subject: [PATCH] Add legacy auth method to GUI, remove unnecessary activity log entries, and avoid deleting the auth.json file when auth fails --- OF DL.Cli/Program.cs | 13 -- OF DL.Core/Helpers/Constants.cs | 4 + OF DL.Gui/ViewModels/AppScreen.cs | 1 + OF DL.Gui/ViewModels/MainWindowViewModel.cs | 222 +++++++++++--------- OF DL.Gui/Views/MainWindow.axaml | 56 +++++ OF DL.Gui/Views/MainWindow.axaml.cs | 13 ++ 6 files changed, 195 insertions(+), 114 deletions(-) diff --git a/OF DL.Cli/Program.cs b/OF DL.Cli/Program.cs index 476a625..731abb4 100644 --- a/OF DL.Cli/Program.cs +++ b/OF DL.Cli/Program.cs @@ -209,14 +209,6 @@ public class Program(IServiceProvider serviceProvider) Log.Error("Auth failed"); authService.CurrentAuth = null; - if (!configService.CurrentConfig.DisableBrowserAuth) - { - if (File.Exists("auth.json")) - { - File.Delete("auth.json"); - } - } - if (!configService.CurrentConfig.NonInteractiveMode && !configService.CurrentConfig.DisableBrowserAuth) { @@ -747,11 +739,6 @@ public class Program(IServiceProvider serviceProvider) else if (File.Exists("auth.json")) { Log.Information("Auth file found but could not be deserialized"); - if (!configService.CurrentConfig.DisableBrowserAuth) - { - Log.Debug("Deleting auth.json"); - File.Delete("auth.json"); - } if (configService.CurrentConfig.NonInteractiveMode) { diff --git a/OF DL.Core/Helpers/Constants.cs b/OF DL.Core/Helpers/Constants.cs index 40123a6..fe43056 100644 --- a/OF DL.Core/Helpers/Constants.cs +++ b/OF DL.Core/Helpers/Constants.cs @@ -6,6 +6,10 @@ public static class Constants public const string DocumentationUrl = "https://docs.ofdl.tools/"; + public const string AuthHelperExtensionUrl = "https://github.com/whimsical-c4lic0/OF-DL-Auth-Helper/"; + + public const string LegacyAuthDocumentationUrl = "https://docs.ofdl.tools/config/auth/#legacy-methods"; + public const string ApiUrl = "https://onlyfans.com/api2/v2"; public const int ApiPageSize = 50; diff --git a/OF DL.Gui/ViewModels/AppScreen.cs b/OF DL.Gui/ViewModels/AppScreen.cs index 159021a..f6eb897 100644 --- a/OF DL.Gui/ViewModels/AppScreen.cs +++ b/OF DL.Gui/ViewModels/AppScreen.cs @@ -5,6 +5,7 @@ public enum AppScreen Loading, Config, Auth, + ManualAuth, UserSelection, Error } diff --git a/OF DL.Gui/ViewModels/MainWindowViewModel.cs b/OF DL.Gui/ViewModels/MainWindowViewModel.cs index f702c79..05235c1 100644 --- a/OF DL.Gui/ViewModels/MainWindowViewModel.cs +++ b/OF DL.Gui/ViewModels/MainWindowViewModel.cs @@ -12,6 +12,7 @@ using Avalonia.Threading; using Newtonsoft.Json; using OF_DL.Enumerations; using OF_DL.Gui.Services; +using OF_DL.Helpers; using OF_DL.Models; using OF_DL.Models.Config; using OF_DL.Models.Downloads; @@ -258,7 +259,18 @@ public partial class MainWindowViewModel( [ObservableProperty] private string _authScreenMessage = string.Empty; - [ObservableProperty] [NotifyCanExecuteChangedFor(nameof(StartBrowserLoginCommand))] + [ObservableProperty] private string _manualAuthScreenMessage = string.Empty; + + [ObservableProperty] private string _manualAuthInstructionsText = string.Empty; + + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(GoBackToAuthScreenCommand))] + [NotifyCanExecuteChangedFor(nameof(ContinueWithManualAuthCommand))] + private bool _isManualAuthValidationInProgress; + + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(StartBrowserLoginCommand))] + [NotifyCanExecuteChangedFor(nameof(OpenManualAuthScreenCommand))] private bool _isBrowserLoginInProgress; [ObservableProperty] private string _errorMessage = string.Empty; @@ -354,6 +366,8 @@ public partial class MainWindowViewModel( public bool IsAuthScreen => CurrentScreen == AppScreen.Auth; + public bool IsManualAuthScreen => CurrentScreen == AppScreen.ManualAuth; + public bool IsUserSelectionScreen => CurrentScreen == AppScreen.UserSelection; public bool IsErrorScreen => CurrentScreen == AppScreen.Error; @@ -545,10 +559,12 @@ public partial class MainWindowViewModel( AvailableUsers.Clear(); UserLists.Clear(); SelectedListName = null; + IsManualAuthValidationInProgress = false; + ManualAuthScreenMessage = string.Empty; AuthenticatedUserDisplay = "Not authenticated."; - AuthScreenMessage = "You have been logged out. Click 'Login with Browser' to authenticate."; - StatusMessage = "Logged out."; + AuthScreenMessage = + "You have been logged out. OF DL needs access to your OnlyFans account.\nAn included web browser can be used to sign-in, or you can create an \"auth.json\" file manually."; CurrentScreen = AppScreen.Auth; OnPropertyChanged(nameof(SelectedUsersSummary)); DownloadSelectedCommand.NotifyCanExecuteChanged(); @@ -570,7 +586,6 @@ public partial class MainWindowViewModel( EnforceGuiOnlyConfigValues(configService.CurrentConfig); BuildConfigFields(configService.CurrentConfig); ConfigScreenMessage = "Edit configuration values and save to apply changes."; - StatusMessage = "Editing configuration."; CurrentScreen = AppScreen.Config; } @@ -584,7 +599,6 @@ public partial class MainWindowViewModel( if (!loaded) { ConfigScreenMessage = "Configuration is still invalid."; - StatusMessage = ConfigScreenMessage; CurrentScreen = AppScreen.Config; return; } @@ -592,7 +606,6 @@ public partial class MainWindowViewModel( if (_configReturnScreen == AppScreen.UserSelection && _allUsers.Count > 0) { CurrentScreen = AppScreen.UserSelection; - StatusMessage = "Configuration changes canceled."; return; } @@ -611,7 +624,6 @@ public partial class MainWindowViewModel( } ConfigScreenMessage = "Refreshing user lists..."; - StatusMessage = ConfigScreenMessage; try { @@ -624,14 +636,11 @@ public partial class MainWindowViewModel( UpdateIgnoredUsersListFieldOptions(); ConfigScreenMessage = $"User lists refreshed ({_allLists.Count})."; - StatusMessage = ConfigScreenMessage; AppendLog(ConfigScreenMessage); } catch (Exception ex) { - ConfigScreenMessage = $"Could not refresh user lists: {ex.Message}"; - StatusMessage = ConfigScreenMessage; - AppendLog(ConfigScreenMessage); + AppendLog($"Could not refresh user lists: {ex.Message}"); } } @@ -641,7 +650,6 @@ public partial class MainWindowViewModel( if (!TryBuildConfig(out Config newConfig)) { ConfigScreenMessage = "Fix configuration validation errors and save again."; - StatusMessage = ConfigScreenMessage; return; } @@ -655,14 +663,12 @@ public partial class MainWindowViewModel( { ConfigScreenMessage = "config.conf could not be loaded after saving. Please review your values."; CurrentScreen = AppScreen.Config; - StatusMessage = ConfigScreenMessage; BuildConfigFields(configService.CurrentConfig); return; } BuildConfigFields(configService.CurrentConfig); ConfigScreenMessage = "Configuration saved."; - StatusMessage = "Configuration saved."; if (!await ValidateEnvironmentAsync(false)) { @@ -682,16 +688,8 @@ public partial class MainWindowViewModel( [RelayCommand(CanExecute = nameof(CanStartBrowserLogin))] private async Task StartBrowserLoginAsync() { - if (configService.CurrentConfig.DisableBrowserAuth) - { - AuthScreenMessage = "Browser authentication is disabled in config."; - return; - } - IsBrowserLoginInProgress = true; - AppendLog("Starting browser authentication flow."); - StartBrowserLoginCommand.NotifyCanExecuteChanged(); bool success; try { @@ -702,8 +700,7 @@ public partial class MainWindowViewModel( return; } - AuthScreenMessage = message; - AppendLog(message); + Dispatcher.UIThread.Post(() => SetLoading(message)); }); } finally @@ -714,27 +711,86 @@ public partial class MainWindowViewModel( if (!success || authService.CurrentAuth == null) { AuthScreenMessage = - "Authentication failed. Log in using the opened browser window and retry."; + "Authentication failed. Retry the browser based login, or use\n'Manual Authentication' to continue."; CurrentScreen = AppScreen.Auth; - StatusMessage = "Authentication failed."; - AppendLog("Browser authentication failed."); return; } await authService.SaveToFileAsync(); - bool isAuthValid = await ValidateCurrentAuthAsync(true); + bool isAuthValid = await ValidateCurrentAuthAsync(); if (!isAuthValid) { - AuthScreenMessage = "Authentication is still invalid after login. Please retry."; + AuthScreenMessage = + "Authentication is still invalid after login.\nPlease retry, or use 'Manual Authentication' to continue."; CurrentScreen = AppScreen.Auth; - StatusMessage = "Authentication failed."; return; } await LoadUsersAndListsAsync(); } + [RelayCommand(CanExecute = nameof(CanOpenManualAuthScreen))] + private void OpenManualAuthScreen() + { + IsManualAuthValidationInProgress = false; + ManualAuthScreenMessage = string.Empty; + + string configFolder = EnvironmentHelper.IsRunningInDocker() + ? "your OF DL config folder" + : "the same folder as OF DL"; + + ManualAuthInstructionsText = + $"An \"auth.json\" file is required to use OF DL. See the documentation for creating this file manually." + + $"\nOnce you've created the \"auth.json\", save it to {configFolder}."; + CurrentScreen = AppScreen.ManualAuth; + } + + [RelayCommand(CanExecute = nameof(CanGoBackToAuthScreen))] + private void GoBackToAuthScreen() + { + IsManualAuthValidationInProgress = false; + ManualAuthScreenMessage = string.Empty; + AuthScreenMessage = + "OF DL needs access to your OnlyFans account.\nAn included web browser can be used to sign-in, or you can create an \"auth.json\" file manually."; + CurrentScreen = AppScreen.Auth; + } + + [RelayCommand(CanExecute = nameof(CanContinueWithManualAuth))] + private async Task ContinueWithManualAuthAsync() + { + IsManualAuthValidationInProgress = true; + ManualAuthScreenMessage = "Validating auth.json..."; + + try + { + bool loadedFromFile = await authService.LoadFromFileAsync(); + if (!loadedFromFile) + { + authService.CurrentAuth = null; + IsAuthenticated = false; + AuthenticatedUserDisplay = "Not authenticated."; + ManualAuthScreenMessage = + "auth.json was not found or could not be read. Update auth.json and try again."; + return; + } + + bool isValid = await ValidateCurrentAuthAsync(); + if (!isValid) + { + ManualAuthScreenMessage = + "auth.json failed validation. Update the file and try again."; + return; + } + + await LoadUsersAndListsAsync(); + } + finally + { + IsManualAuthValidationInProgress = false; + } + } + [RelayCommand(CanExecute = nameof(CanApplySelectedList))] private async Task SelectUsersFromListAsync() { @@ -763,7 +819,6 @@ public partial class MainWindowViewModel( user.IsSelected = selectedUsernames.Contains(user.Username); } - StatusMessage = $"Selected {selectedUsernames.Count} users from list '{SelectedListName}'."; OnPropertyChanged(nameof(SelectedUsersSummary)); OnPropertyChanged(nameof(AllUsersSelected)); DownloadSelectedCommand.NotifyCanExecuteChanged(); @@ -831,7 +886,6 @@ public partial class MainWindowViewModel( if (_workCancellationSource is { IsCancellationRequested: false }) { _workCancellationSource.Cancel(); - StatusMessage = "Stop requested. Waiting for current operation to cancel..."; UpdateProgressStatus("Stopping..."); AppendLog("Stop requested."); } @@ -842,13 +896,11 @@ public partial class MainWindowViewModel( List selectedUsers = AvailableUsers.Where(user => user.IsSelected).ToList(); if (!downloadPurchasedTabOnly && selectedUsers.Count == 0) { - StatusMessage = "Select at least one user before downloading."; return; } if (downloadPurchasedTabOnly && _allUsers.Count == 0) { - StatusMessage = "No users are loaded. Refresh users and retry."; return; } @@ -868,9 +920,6 @@ public partial class MainWindowViewModel( AppendLog(downloadPurchasedTabOnly ? "Starting Purchased Tab download." : $"Starting download for {selectedUsers.Count} users."); - StatusMessage = downloadPurchasedTabOnly - ? "Starting Purchased Tab download..." - : $"Starting download for {selectedUsers.Count} users..."; // Show progress bar immediately with indeterminate state StartDownloadProgress( @@ -915,19 +964,14 @@ public partial class MainWindowViewModel( ThrowIfStopRequested(); eventHandler.OnScrapeComplete(DateTime.Now - start); - StatusMessage = downloadPurchasedTabOnly - ? "Purchased Tab download completed." - : "Download run completed."; } catch (OperationCanceledException) { - StatusMessage = "Operation canceled."; AppendLog("Operation canceled."); } catch (Exception ex) { AppendLog($"Download failed: {ex.Message}"); - StatusMessage = "Download failed. Check logs."; } finally { @@ -990,11 +1034,27 @@ public partial class MainWindowViewModel( !IsDownloading && !IsBrowserLoginInProgress; + private bool CanOpenManualAuthScreen() => + CurrentScreen == AppScreen.Auth && + !IsDownloading && + !IsBrowserLoginInProgress; + + private bool CanGoBackToAuthScreen() => + CurrentScreen == AppScreen.ManualAuth && + !IsDownloading && + !IsManualAuthValidationInProgress; + + private bool CanContinueWithManualAuth() => + CurrentScreen == AppScreen.ManualAuth && + !IsDownloading && + !IsManualAuthValidationInProgress; + partial void OnCurrentScreenChanged(AppScreen value) { OnPropertyChanged(nameof(IsLoadingScreen)); OnPropertyChanged(nameof(IsConfigScreen)); OnPropertyChanged(nameof(IsAuthScreen)); + OnPropertyChanged(nameof(IsManualAuthScreen)); OnPropertyChanged(nameof(IsUserSelectionScreen)); OnPropertyChanged(nameof(IsErrorScreen)); OnPropertyChanged(nameof(SelectedUsersSummary)); @@ -1007,6 +1067,9 @@ public partial class MainWindowViewModel( LogoutCommand.NotifyCanExecuteChanged(); EditConfigCommand.NotifyCanExecuteChanged(); StartBrowserLoginCommand.NotifyCanExecuteChanged(); + OpenManualAuthScreenCommand.NotifyCanExecuteChanged(); + GoBackToAuthScreenCommand.NotifyCanExecuteChanged(); + ContinueWithManualAuthCommand.NotifyCanExecuteChanged(); OpenSinglePostOrMessageModalCommand.NotifyCanExecuteChanged(); SubmitSinglePostOrMessageCommand.NotifyCanExecuteChanged(); } @@ -1021,6 +1084,9 @@ public partial class MainWindowViewModel( RefreshIgnoredUsersListsCommand.NotifyCanExecuteChanged(); LogoutCommand.NotifyCanExecuteChanged(); StartBrowserLoginCommand.NotifyCanExecuteChanged(); + OpenManualAuthScreenCommand.NotifyCanExecuteChanged(); + GoBackToAuthScreenCommand.NotifyCanExecuteChanged(); + ContinueWithManualAuthCommand.NotifyCanExecuteChanged(); OpenSinglePostOrMessageModalCommand.NotifyCanExecuteChanged(); SubmitSinglePostOrMessageCommand.NotifyCanExecuteChanged(); } @@ -1093,7 +1159,6 @@ public partial class MainWindowViewModel( ConfigScreenMessage = "config.conf is invalid. Update all fields below and save to continue."; CurrentScreen = AppScreen.Config; - StatusMessage = ConfigScreenMessage; return; } @@ -1114,7 +1179,6 @@ public partial class MainWindowViewModel( { if (_allUsers.Count == 0) { - StatusMessage = "No users are loaded. Refresh users and retry."; return; } @@ -1135,7 +1199,6 @@ public partial class MainWindowViewModel( DateTime start = DateTime.Now; string label = request.Type == SingleDownloadType.Post ? "single post" : "single paid message"; AppendLog($"Starting {label} download from URL."); - StatusMessage = $"Starting {label} download..."; StartDownloadProgress($"Initializing {label} download...", 0, false); @@ -1155,9 +1218,8 @@ public partial class MainWindowViewModel( { if (!_allUsers.TryGetValue(request.Username, out long userId)) { - StatusMessage = - $"Creator '{request.Username}' is not in loaded users. Refresh users and ensure you are subscribed."; - AppendLog(StatusMessage); + AppendLog( + $"Creator '{request.Username}' is not in loaded users. Refresh users and ensure you are subscribed."); return; } @@ -1179,8 +1241,7 @@ public partial class MainWindowViewModel( string? resolvedUsername = await downloadOrchestrationService.ResolveUsernameAsync(userId); if (string.IsNullOrWhiteSpace(resolvedUsername)) { - StatusMessage = $"Could not resolve username for user ID {userId}."; - AppendLog(StatusMessage); + AppendLog($"Could not resolve username for user ID {userId}."); return; } @@ -1205,19 +1266,14 @@ public partial class MainWindowViewModel( ThrowIfStopRequested(); eventHandler.OnScrapeComplete(DateTime.Now - start); - StatusMessage = request.Type == SingleDownloadType.Post - ? "Single post download completed." - : "Single paid message download completed."; } catch (OperationCanceledException) { - StatusMessage = "Operation canceled."; AppendLog("Operation canceled."); } catch (Exception ex) { AppendLog($"Single item download failed: {ex.Message}"); - StatusMessage = "Single item download failed. Check logs."; } finally { @@ -1275,7 +1331,6 @@ public partial class MainWindowViewModel( if (!confirmed) { - StatusMessage = "Download canceled."; AppendLog("Download canceled after missing CDM keys warning."); } @@ -1354,17 +1409,11 @@ public partial class MainWindowViewModel( bool hasValidAuth = await TryLoadAndValidateExistingAuthAsync(logAuthenticationMessage); if (!hasValidAuth) { - if (configService.CurrentConfig.DisableBrowserAuth) - { - ShowError( - "Authentication is missing or invalid and browser auth is disabled. Enable browser auth in config or provide a valid auth.json."); - return; - } - + IsManualAuthValidationInProgress = false; + ManualAuthScreenMessage = string.Empty; AuthScreenMessage = - "Authentication is required. Click 'Login with Browser' and complete the OnlyFans login flow."; + "OF DL needs access to your OnlyFans account.\nAn included web browser can be used to sign-in, or you can create an \"auth.json\" file manually."; CurrentScreen = AppScreen.Auth; - StatusMessage = "Authentication required."; return; } @@ -1401,7 +1450,6 @@ public partial class MainWindowViewModel( configService.CurrentConfig.FFmpegPath, "FFmpeg"); CurrentScreen = AppScreen.Config; - StatusMessage = ConfigScreenMessage; return false; } @@ -1418,7 +1466,6 @@ public partial class MainWindowViewModel( configService.CurrentConfig.FFprobePath, "FFprobe"); CurrentScreen = AppScreen.Config; - StatusMessage = ConfigScreenMessage; return false; } @@ -1442,14 +1489,13 @@ public partial class MainWindowViewModel( private async Task TryLoadAndValidateExistingAuthAsync(bool logAuthenticationMessage) { bool loadedFromFile = await authService.LoadFromFileAsync(); - if (!loadedFromFile) + if (loadedFromFile) { - IsAuthenticated = false; - AppendLog("No valid auth.json found."); - return false; + return await ValidateCurrentAuthAsync(); } - return await ValidateCurrentAuthAsync(logAuthenticationMessage); + IsAuthenticated = false; + return false; } private bool ValidateConfiguredToolPathsOnStartup() @@ -1479,11 +1525,10 @@ public partial class MainWindowViewModel( ConfigScreenMessage = "Configuration has invalid FFmpeg/FFprobe path values. Fix and save to continue."; CurrentScreen = AppScreen.Config; - StatusMessage = ConfigScreenMessage; return false; } - private async Task ValidateCurrentAuthAsync(bool logAuthenticationMessage) + private async Task ValidateCurrentAuthAsync() { authService.ValidateCookieString(); UserEntities.User? user = await authService.ValidateAuthAsync(); @@ -1491,35 +1536,13 @@ public partial class MainWindowViewModel( { authService.CurrentAuth = null; IsAuthenticated = false; - if (File.Exists("auth.json") && !configService.CurrentConfig.DisableBrowserAuth) - { - File.Delete("auth.json"); - } - - AppendLog("Auth validation failed."); return false; } string displayName = !string.IsNullOrWhiteSpace(user.Name) ? user.Name : "Unknown Name"; string displayUsername = !string.IsNullOrWhiteSpace(user.Username) ? user.Username : "Unknown Username"; - if (HidePrivateInfo) - { - AuthenticatedUserDisplay = "[Hidden for Privacy]"; - if (logAuthenticationMessage) - { - AppendLog("Authenticated as [Hidden for Privacy]."); - } - } - else - { - AuthenticatedUserDisplay = $"{displayName} ({displayUsername})"; - if (logAuthenticationMessage) - { - AppendLog($"Authenticated as {AuthenticatedUserDisplay}."); - } - } - + AuthenticatedUserDisplay = HidePrivateInfo ? "[Hidden for Privacy]" : $"{displayName} ({displayUsername})"; IsAuthenticated = true; return true; } @@ -1564,8 +1587,7 @@ public partial class MainWindowViewModel( } CurrentScreen = AppScreen.UserSelection; - StatusMessage = $"Loaded {_allUsers.Count} users and {_allLists.Count} lists."; - AppendLog(StatusMessage); + AppendLog($"Loaded {_allUsers.Count} users and {_allLists.Count} lists."); DownloadSelectedCommand.NotifyCanExecuteChanged(); DownloadPurchasedTabCommand.NotifyCanExecuteChanged(); SelectUsersFromListCommand.NotifyCanExecuteChanged(); @@ -2032,14 +2054,12 @@ public partial class MainWindowViewModel( private void SetLoading(string message) { LoadingMessage = message; - StatusMessage = message; CurrentScreen = AppScreen.Loading; } private void ShowError(string message) { ErrorMessage = message; - StatusMessage = message; CurrentScreen = AppScreen.Error; AppendLog(message); } diff --git a/OF DL.Gui/Views/MainWindow.axaml b/OF DL.Gui/Views/MainWindow.axaml index 5550a63..86405cd 100644 --- a/OF DL.Gui/Views/MainWindow.axaml +++ b/OF DL.Gui/Views/MainWindow.axaml @@ -71,6 +71,20 @@ + + + + @@ -1011,6 +1025,48 @@ Classes="primary" IsEnabled="{Binding !IsBrowserLoginInProgress}" Command="{Binding StartBrowserLoginCommand}" /> +