Skip to content

feat: add native app auth code login flow#2440

Merged
deadlyjack merged 4 commits into
mainfrom
fix/harden-app-auth-code
Jul 3, 2026
Merged

feat: add native app auth code login flow#2440
deadlyjack merged 4 commits into
mainfrom
fix/harden-app-auth-code

Conversation

@deadlyjack

Copy link
Copy Markdown
Member
  • move Android login to custom tab auth-code exchange
  • handle reserved auth callback intents natively
  • add semantic plugin version comparison for updates
  • improve sidebar avatar loading state
  • cover auth/version and quick-tools behavior in sanity tests

- move Android login to custom tab auth-code exchange
- handle reserved auth callback intents natively
- add semantic plugin version comparison for updates
- improve sidebar avatar loading state
- cover auth/version and quick-tools behavior in sanity tests
@greptile-apps

greptile-apps Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR replaces the previous intent-URI login flow with a native PKCE auth-code exchange via Custom Tabs on Android, adds semantic version comparison for plugin update checks, and improves the sidebar avatar loading state.

  • Auth flow overhaul: Authenticator.java now generates a PKCE state/verifier/challenge, opens a Custom Tab, and exchanges the authorization code via a background HTTP POST to /api/user/app-token/exchange. The System.java plugin and JS intent handler both filter the reserved acode://auth/callback scheme to prevent double-processing. The JS-side 60 s window is correctly a rejection deadline (not a resolution delay) — loginEvents.emit() resolves callbacks immediately on success.
  • Semantic versioning: A new utils/version.js module provides parseVersion / compareVersions / isVersionGreater used across plugin update checks, dependency resolution, and the plugin detail page; sanity tests cover the four basic comparison cases.
  • Sidebar avatar loading: Renames the CSS class from \"loading\" to \"avatar-loading\" and adds a dedicated pulse animation to avoid class-name collisions.

Confidence Score: 5/5

The auth flow, PKCE implementation, and thread-safety changes are solid; minor edge cases in version parsing logic are non-blocking.

The core auth code exchange and the JS-side timeout redesign are both correct. The two findings are narrow edge cases in the version comparison logic — an unparseable json.version string silently suppressing a server-flagged update, and a behaviour change for unversioned dependency entries — neither of which affects the main login or update flows under normal server responses.

src/lib/checkPluginsUpdate.js deserves a second look around the json.version fast-path guard; src/lib/installPlugin.js around the dependency skip condition for manifests without a version field.

Important Files Changed

Filename Overview
src/plugins/auth/src/android/Authenticator.java New PKCE auth-code flow via Custom Tabs; addresses previous thread concerns (volatile callback, timeouts, concurrent login cancellation).
src/lib/auth.js Replaces the intent-based login with a native Cordova exec; 60 s timer is now a rejection deadline (not a delay) and loginEvents resolves callbacks immediately on success.
src/lib/checkPluginsUpdate.js Adds semantic version comparison; when json.version is truthy but unparseable, the early return silently drops a server-flagged update without falling through to the legacy fetch.
src/lib/installPlugin.js Dependency version check changed from strict equality to isVersionGreater; unversioned remote dependencies now skip reinstall when already installed (behavior change).
src/utils/version.js New semver utility (parseVersion / compareVersions / isVersionGreater) with strict 3-part enforcement and v-prefix stripping.
src/plugins/system/android/com/foxdebug/system/System.java Filters acode://auth/callback intents from the system intent handler to prevent double-processing; logic mirrors Authenticator correctly.
src/handlers/intent.js Returns early for auth/callback module-action pair so the JS intent bus does not process native auth redirects.
src/components/sidebar/index.js Renames avatar loading class from loading to avatar-loading to avoid collisions.
src/test/sanity.tests.js Adds four version comparison assertions covering patch, minor, equal, and downgrade cases.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User
    participant JS as auth.js
    participant Java as Authenticator.java
    participant Server as acode.app
    participant Tab as Custom Tab

    User->>JS: authService.login()
    JS->>Java: "cordova.exec(login, {baseUrl, versionCode})"
    Java->>Java: generate PKCE state, verifier, challenge
    Java->>Java: persist pending state to EncryptedPrefs
    Java->>Tab: "launchUrl with authFlow=app-code"
    Java-->>JS: "NO_RESULT keepCallback=true"
    Note over JS: resume fires, 60s rejection timer starts
    User->>Tab: Authenticate
    Tab->>Java: acode://auth/callback via onNewIntent
    Java->>Java: handleAuthCallback, validate state
    Java->>Server: POST /api/user/app-token/exchange
    Server-->>Java: token response
    Java->>Java: persist token, clear pending state
    Java-->>JS: callback.success()
    JS->>JS: loginEvents.emit(), clearTimeout, resolve immediately
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant User
    participant JS as auth.js
    participant Java as Authenticator.java
    participant Server as acode.app
    participant Tab as Custom Tab

    User->>JS: authService.login()
    JS->>Java: "cordova.exec(login, {baseUrl, versionCode})"
    Java->>Java: generate PKCE state, verifier, challenge
    Java->>Java: persist pending state to EncryptedPrefs
    Java->>Tab: "launchUrl with authFlow=app-code"
    Java-->>JS: "NO_RESULT keepCallback=true"
    Note over JS: resume fires, 60s rejection timer starts
    User->>Tab: Authenticate
    Tab->>Java: acode://auth/callback via onNewIntent
    Java->>Java: handleAuthCallback, validate state
    Java->>Server: POST /api/user/app-token/exchange
    Server-->>Java: token response
    Java->>Java: persist token, clear pending state
    Java-->>JS: callback.success()
    JS->>JS: loginEvents.emit(), clearTimeout, resolve immediately
Loading

Reviews (3): Last reviewed commit: "fix: preserve plugin update fallback not..." | Re-trigger Greptile

Comment thread src/plugins/auth/src/android/Authenticator.java Outdated
Comment thread src/plugins/auth/src/android/Authenticator.java Outdated
Comment thread src/plugins/auth/src/android/Authenticator.java Outdated
Ajit Kumar added 2 commits July 2, 2026 21:25
- drop quick-tools tests accidentally carried over during conflict resolution
- remove missing quickToolsState import from sanity tests
- keep auth branch version comparison coverage intact
@deadlyjack

Copy link
Copy Markdown
Member Author

@greptile_apps review again

Comment thread src/lib/checkPluginsUpdate.js
- keep server-confirmed plugin updates when legacy metadata fetch lacks a version
- reject any previous pending Android login callback before replacing it
@deadlyjack

Copy link
Copy Markdown
Member Author

@greptile_apps review again

@deadlyjack deadlyjack merged commit 0912603 into main Jul 3, 2026
13 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in The Code Board - Acode Jul 3, 2026
@deadlyjack deadlyjack deleted the fix/harden-app-auth-code branch July 3, 2026 01:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant