Skip to content

Post entries through /api/entry and handle two-factor login - #5

Merged
laffer1 merged 1 commit into
masterfrom
api-entry-and-2fa
Nov 3, 2026
Merged

laffer1 merged 1 commit into
masterfrom
api-entry-and-2fa

Conversation

@laffer1

@laffer1 laffer1 commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #4

Changes

  • Entry: sends a JSON POST /api/entry with the session cookie from /api/login, so the username and password no longer go with each post. Every field is sent explicitly (security 0/1/2, mood/location ids, format: "TEXT", draft: false, tags: []). The server fails after saving when tags is missing, which is why it is always sent. A blank body is rejected before sending. 403 is reported as an expired login, and 400 shows the server's error text.
  • Auth.restLogin(): succeeds only on status: "JJ.LOGIN.OK", not on any 200. JJ.LOGIN.2FA sets isSecondFactorRequired(), and the new verifySecondFactor(code) finishes the login at POST /api/login/2fa on the same session:
    • 401 means a wrong code, which can be retried.
    • 401 with JJ.LOGIN.NONE or a 429 means the user has to log in again.
  • Session: cookies are kept in memory only and updated from each login response, so the session id the server switches to after a 2FA login gets picked up. The Cookie header is built as plain name=value pairs, because JAX-RS Cookie objects serialize in the RFC 2109 $Version form.
  • FormGui: keeps the logged-in Auth, posts with it, and prompts for the 2FA code (the wording depends on whether the code was e-mailed or comes from an authenticator app).
  • Removed the unused Auth.secureCheckAccount() (/loginAccount) and the form-post helpers in HttpUtils.

The request formats come from the server source (LoginController, TwoFactorLoginController, EntryController, EntryTo) and from jj_rest.c in the unix client.

Testing

  • ./mvnw verify: 56 tests pass (the live-server test is still @Ignored), and the JaCoCo gate and shaded jar build pass.
  • StubServer now supports a reply per path and Set-Cookie. The tests cover the cookie carried from login to post, every JSON field, the 2FA success/wrong-code/locked/forgotten cases, and the error replies.
  • Not tested against justjournal.com or by hand in the GUI.

Not included

  • Loading moods from GET /api/mood (optional in the issue); the built-in table stays.

🤖 Generated with Claude Code

Summary by Sourcery

Migrate authentication and entry submission to the REST API with session cookies and complete two-factor login support.

New Features:

  • Add session-based JSON journal entry posting through /api/entry.
  • Support two-factor authentication during login, including code verification and retry handling.
  • Retain and update in-memory session cookies across login, two-factor verification, and entry submission.

Bug Fixes:

  • Reject blank entries before sending them and provide clearer handling for expired sessions and server validation errors.

Enhancements:

  • Update the GUI to retain authenticated sessions and prompt for email or authenticator-based two-factor codes.
  • Remove obsolete account-checking and form-posting helpers in favor of the REST API flow.

Tests:

  • Expand client tests to cover JSON request fields, session cookies, two-factor outcomes, and entry/login error responses.

The client logged in with POST /api/login but still posted entries to the
old /updateJournal servlet, sending the username and password with every
post. Desktop clients are moving to the documented JSON API.

- Entry sends a JSON POST /api/entry with the session cookie from the
  login. Every field is sent, including an empty tags list, since the
  server fails after saving when tags is missing.
- Auth.restLogin() only succeeds on status JJ.LOGIN.OK instead of any
  200. Accounts with two-factor login get JJ.LOGIN.2FA, and the new
  verifySecondFactor() finishes the login at /api/login/2fa; the GUI
  prompts for the code.
- Remove the unused Auth.secureCheckAccount() and the form-post helpers
  in HttpUtils that nothing else used.

Closes #4

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

Migrates authentication and journal posting to the JSON REST API with in-memory session-cookie management, adds a complete two-factor login flow and GUI integration, removes obsolete form helpers, and substantially expands endpoint-level test coverage.

Sequence diagram for two-factor login and session management

sequenceDiagram
    actor User
    participant FormGui
    participant Auth
    participant LoginAPI
    participant TwoFactorAPI

    User->>FormGui: login()
    FormGui->>Auth: restLogin()
    Auth->>LoginAPI: POST /api/login
    LoginAPI-->>Auth: JJ.LOGIN.2FA + Set-Cookie
    Auth->>Auth: keepCookies()
    Auth-->>FormGui: isSecondFactorRequired()
    FormGui->>User: verifySecondFactor(code)
    User-->>FormGui: code
    FormGui->>Auth: verifySecondFactor(code)
    Auth->>TwoFactorAPI: POST /api/login/2fa + Cookie
    TwoFactorAPI-->>Auth: JJ.LOGIN.OK + Set-Cookie
    Auth->>Auth: keepCookies()
    Auth-->>FormGui: isLoggedIn()
Loading

Sequence diagram for authenticated journal entry posting

sequenceDiagram
    actor User
    participant FormGui
    participant Entry
    participant Auth
    participant EntryAPI

    User->>FormGui: submit entry
    FormGui->>Entry: update(...)
    Entry->>Auth: request(client, api/entry)
    Auth-->>Entry: request with Cookie header
    Entry->>EntryAPI: POST /api/entry + JSON EntryTo
    EntryAPI-->>Entry: status + JSON reply
    alt status is 200 and reply status is ok
        Entry-->>FormGui: success
    else status is 403 or 401
        Entry-->>FormGui: SESSION_EXPIRED
    else status is 400
        Entry-->>FormGui: server error text
    end
Loading

File-Level Changes

Change Details Files
Replaced form-based authentication and entry submission with JSON REST requests backed by an in-memory cookie session.
  • POST credentials to /api/login and require JJ.LOGIN.OK for a completed login.
  • Build a complete EntryTo JSON payload and post it to /api/entry without resending credentials.
  • Preserve and rotate Set-Cookie values, emitting plain name=value pairs on subsequent requests.
  • Map entry response statuses and server error text to user-facing errors; reject blank bodies locally.
src/main/java/com/justjournal/client/Auth.java
src/main/java/com/justjournal/client/Entry.java
src/main/java/com/justjournal/client/model/EntryTo.java
src/main/java/com/justjournal/client/HttpUtils.java
Added two-factor authentication as a stateful continuation of the login flow.
  • Recognize JJ.LOGIN.2FA and expose the required method while retaining the pending session.
  • Submit trimmed codes to /api/login/2fa, allowing retries for incorrect codes.
  • Handle forgotten sessions and rate limiting as conditions requiring a new login.
  • Update the GUI to prompt with method-specific instructions and retain the successful Auth instance for posting.
src/main/java/com/justjournal/client/Auth.java
src/main/java/com/justjournal/client/FormGui.java
src/main/java/com/justjournal/client/model/LoginResponse.java
src/main/java/com/justjournal/client/model/TwoFactorRequest.java
Expanded endpoint-focused test infrastructure and coverage for REST payloads, cookies, errors, and 2FA transitions.
  • Allow the stub server to return path-specific JSON responses and Set-Cookie headers while recording request bodies and cookies.
  • Verify exact login and entry JSON fields, credential omission, cookie propagation and rotation, validation, status handling, and all 2FA outcomes.
  • Update the ignored live-server test to use the new login API.
src/test/java/com/justjournal/client/AuthTest.java
src/test/java/com/justjournal/client/EntryTest.java
src/test/java/com/justjournal/client/StubServer.java
src/test/java/com/justjournal/client/jj_authTest.java

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@laffer1

laffer1 commented Nov 3, 2026

Copy link
Copy Markdown
Collaborator Author

✅ Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
✅ Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@laffer1
laffer1 merged commit 076eb59 into master Nov 3, 2026
8 of 11 checks passed
@deepsource-io

deepsource-io Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

DeepSource Code Review

We reviewed changes in 75f60d1...4196e19 on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
Java Nov 3, 2026 8:45a.m. Review ↗

Important

AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.

@sourcery-ai sourcery-ai Bot 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.

Hey - I've reviewed your changes and they look great!

Linked issues

#4 Post entries through `/api/entry` instead of `/updateJournal` · 3 of 3 met

# Requirement Status Notes
1 Post entries as JSON to /api/entry using the /api/login session, with the specified field mappings; only body is required. ✅ Met Entry sends the JSON model with the requested mappings, uses the logged-in Auth session, and rejects a blank body before sending.
2 Check the /api/login status for JJ.LOGIN.OK and handle two-factor login by prompting for a code or showing a clear error. ✅ Met Auth checks the response status and handles /api/login/2fa; FormGui prompts for a code and distinguishes e-mail from authenticator codes.
3 Remove the unused Auth.secureCheckAccount() method. ✅ Met The method is removed, and no usages remain.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨

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.

Post entries through /api/entry instead of /updateJournal

1 participant