Skip to content

feat(auth): persist environment credentials and rename drops - #13

Merged
rleikis merged 2 commits into
mainfrom
feat/persist-site-credentials-and-drops
Sep 18, 2026
Merged

rleikis merged 2 commits into
mainfrom
feat/persist-site-credentials-and-drops

Conversation

@rleikis

@rleikis rleikis commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Summary

Persist event files and environment-specific credentials across sessions while updating DNF terminology to Drops.

Changes

  • Persist the last event file and restore it on startup.
  • Encrypt saved email/password credentials with Windows DPAPI and keep staging/production credentials separate.
  • Clear the password when switching environments and restore matching saved credentials when available.
  • Update the OST event status bar from selected event metadata.
  • Rename DNF importer/model/formatter terminology to DropType and DropStation.
  • Add focused credential and event-file persistence tests.

Testing

  • dotnet test .\ost-uploader.sln --no-restore -p:UseAppHost=false -p:BaseOutputPath=.\.tmp-drops-test-output\ --verbosity normal
  • 32 tests passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Credential scoping, legacy token restoration, and event-file validation issues remain unresolved.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds event-file and encrypted environment credential persistence, updates event status handling, and renames DNF terminology to Drops.

Changes:

  • Persists and restores event files and credentials.
  • Updates environment-specific authentication behavior.
  • Renames importer, formatter, and model terminology.
  • Adds and updates focused tests.
File summaries
File Summary
ost-uploader/TimesJsonFormatter.cs Updates status formatting for Drop terminology.
ost-uploader/TimesImporter.cs Renames imported DNF fields to Drop fields.
ost-uploader/SecureCredentialStore.cs Stores encrypted credentials.
ost-uploader/MainWindow.xaml.cs Handles event restoration, credentials, and environment UI.
ost-uploader/MainWindow.xaml Updates the application UI.
ost-uploader/EventFilePreferenceStore.cs Persists the last event file.
ost-uploader.Tests/TimesJsonFormatterTests.cs Tests updated status formatting.
ost-uploader.Tests/TimesImporterTests.cs Tests renamed importer fields.
ost-uploader.Tests/SecureCredentialStoreTests.cs Tests credential persistence.
ost-uploader.Tests/EventFileLoaderTests.cs Tests event-file loading and persistence.
Review details

Suppressed comments (6)

ost-uploader/MainWindow.xaml.cs:369

  • baseUrl here is the full event-group endpoint (for example, https://www.opensplittime.org/api/v1/event_groups/42), and GetCredentialFilePath hashes that entire value. As a result, a production login saved for one event cannot be restored when the user opens a different production event, even though the authentication environment is the same; this conflicts with persisting environment-specific credentials. Use a normalized auth/environment key (such as GetAuthBaseUrl(baseUrl)) consistently for both save and lookup while retaining the full endpoint for API calls.
            if (!_credentialStore.TryGetSavedCredentials(baseUrl, out var email, out var password, out var saved))

ost-uploader/MainWindow.xaml.cs:635

  • This replaces the previous TryGetValidToken restoration path with a credentials-only lookup. Existing installations have an unexpired token in credentials.bin without email/password, so that token is now ignored on upgrade and the user is forced to log in again. Preserve a valid token-only fallback or migrate the legacy file when loading saved credentials.
                        RestoreSavedCredentialsForSite(_apiBaseUrl);

ost-uploader/MainWindow.xaml.cs:606

  • This populates the selector with whatever EventFileLoader returns, including a staging-only list: the loader currently treats openSplitTime.production as optional even though the event-file contract requires production and only makes staging optional. That lets an invalid event file enable authentication without a production site. Reject files without production (while allowing optional staging) before adding these UI entries.
                            var item = new ComboBoxItem { Content = s.Title, Tag = s };

ost-uploader/MainWindow.xaml.cs:344

  • This is reset automatically on every environment switch, so logging in to the new site with the box left unchecked reaches the existing global Clear() path and deletes every hashed credential file, including the other environment's saved login. That defeats the new per-environment persistence; make clearing scoped to the selected environment or distinguish an explicit user opt-out from this automatic reset.
                saveToken_CheckBox.IsChecked = false;
                RestoreSavedCredentialsForSite(newUrl);

ost-uploader/SecureCredentialStore.cs:164

  • Clear() now deletes every hashed credential file. MainWindow calls this when the user logs into one environment with “Save credentials” unchecked, so opting out for production also erases the saved staging credentials (and vice versa), contrary to keeping environments separate. Clear only the credential file for the current site, or provide a scoped clear operation.
                var prefix = Path.GetFileNameWithoutExtension(_filePath) + "-";
                if (directory != null)
                {
                    foreach (var path in Directory.EnumerateFiles(directory, prefix + "*" + Path.GetExtension(_filePath)))
                        File.Delete(path);

ost-uploader/TimesImporter.cs:46

  • The rename is incomplete for the bundled UltraTracker samples: ost-uploader/resources/Aid00Times.csv, Aid01Times.csv, and Aid05Times.csv still expose dnfType,dnfStation headers, while the updated tests and model use DropType,DropStation. Update those shipped sample exports as well so users do not continue seeing the old terminology.
                    DropType = fields[5],
                    DropStation = fields[6],
  • Files reviewed: 10/10 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread ost-uploader/SecureCredentialStore.cs Resolved
Co-authored-by: rleikis <10184069+rleikis@users.noreply.github.com>
@rleikis
rleikis merged commit ae83e97 into main Sep 18, 2026
1 check passed
@rleikis
rleikis deleted the feat/persist-site-credentials-and-drops branch September 18, 2026 20:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants