Skip to content

Fix NPE in parseUriLogin when site_url query param is missing#22824

Open
nbradbury wants to merge 3 commits intotrunkfrom
issue/parse-uri-login-npe
Open

Fix NPE in parseUriLogin when site_url query param is missing#22824
nbradbury wants to merge 3 commits intotrunkfrom
issue/parse-uri-login-npe

Conversation

@nbradbury
Copy link
Copy Markdown
Contributor

@nbradbury nbradbury commented Apr 30, 2026

Description

Fixes two related issues in the Application Password login deep-link callback flow:

1. NullPointerException in parseUriLogin (Sentry 3CBF, 756 users)

UrlUtils.normalizeUrl(null) returns null when the auth-callback URI lacks a site_url query param, but ApiRootUrlCache.get declared key: String (non-null), so Kotlin's runtime null check threw an NPE before any recoverable error could be surfaced.

Fix: relax ApiRootUrlCache.get to accept String? and return null for null/empty input.

2. User-rejection callback handled as crash (Sentry 3F8V, 287 users)

WordPress's wp-admin/authorize-application.php redirects to the configured success_url with ?success=false (and no credentials) when the user clicks "No, I do not approve this connection". The activity blindly tried to parse credentials from this URI, which:

  • Used to crash via the NPE above.
  • After fix Menu Drawer Item refactor #1, would have routed to BadData, sent a "A_P: bad_data" report to Sentry, and shown a misleading error toast to a user who deliberately cancelled.

Fix: detect success=false at the top of setupSite, skip the crash report, and show an "Authorization cancelled" toast instead. The rejection is still tracked via the existing APPLICATION_PASSWORD_STORING_FAILED analytics event with reason user_rejected, so we can measure how often it happens.

Testing instructions

Automated

  1. Run ./gradlew :WordPress:testJetpackDebugUnitTest --tests "org.wordpress.android.ui.accounts.login.ApiRootUrlCacheTest" --tests "org.wordpress.android.ui.accounts.applicationpassword.ApplicationPasswordLoginViewModelTest"
  • Verify all tests pass, including get returns null for null key and given user rejected authorization, when setup site, then emit user_rejected without crash report.

Manual: rejection flow

  1. On a self-hosted site, start the Application Password login flow and reach the wp-admin/authorize-application.php consent page.
  2. Tap No, I do not approve this connection.
  • Verify the app shows an "Authorization cancelled" toast (not "There was an error storing…").
  • Verify no Sentry report is generated for this action.

Manual: happy path regression

  1. Sign in to a self-hosted site via Application Password and approve the connection.
  • Verify the login flow still completes successfully and the credentials-stored toast appears.

ApiRootUrlCache.get now accepts a nullable key, since UrlUtils.normalizeUrl
returns null for missing/malformed site_url params and the runtime non-null
check threw before the BadData path could surface a recoverable error.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@dangermattic
Copy link
Copy Markdown
Collaborator

dangermattic commented Apr 30, 2026

1 Warning
⚠️ PR is not assigned to a milestone.

Generated by 🚫 Danger

@wpmobilebot
Copy link
Copy Markdown
Contributor

wpmobilebot commented Apr 30, 2026

App Icon📲 You can test the changes from this Pull Request in WordPress Android by scanning the QR code below to install the corresponding build.

App NameWordPress Android
Build TypeDebug
Versionpr22824-317aad3
Build Number1488
Application IDorg.wordpress.android.prealpha
Commit317aad3
Installation URL3dp5tprmr7ha8
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@wpmobilebot
Copy link
Copy Markdown
Contributor

wpmobilebot commented Apr 30, 2026

App Icon📲 You can test the changes from this Pull Request in Jetpack Android by scanning the QR code below to install the corresponding build.

App NameJetpack Android
Build TypeDebug
Versionpr22824-317aad3
Build Number1488
Application IDcom.jetpack.android.prealpha
Commit317aad3
Installation URL5jqrheb6fsft8
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 30, 2026

Codecov Report

❌ Patch coverage is 83.33333% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 37.15%. Comparing base (8243021) to head (317aad3).
⚠️ Report is 1 commits behind head on trunk.

Files with missing lines Patch % Lines
...i/accounts/login/ApplicationPasswordLoginHelper.kt 0.00% 3 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##            trunk   #22824   +/-   ##
=======================================
  Coverage   37.15%   37.15%           
=======================================
  Files        2314     2314           
  Lines      124323   124340   +17     
  Branches    16892    16895    +3     
=======================================
+ Hits        46187    46201   +14     
- Misses      74390    74393    +3     
  Partials     3746     3746           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@nbradbury nbradbury marked this pull request as ready for review April 30, 2026 16:52
@nbradbury nbradbury requested a review from adalpari April 30, 2026 16:52
@jkmassel
Copy link
Copy Markdown
Contributor

The downstream storeApplicationPasswordCredentialsFrom already routes a null siteUrl to BadData, which surfaces a user-facing error instead of crashing the activity

This seems like a larger issue – if we need the siteUrl, we should already have it from parsing the site details – we'd never be able to show the auth flow without already having that.

I suspect this issue might be caused by folks who hit "Reject" on the authorization page – if that's the case, it should be pretty easy to reproduce, but this bug makes me think we're not handling it properly.

WordPress's authorize-application.php redirects to the success_url with
success=false (and no credentials) when the user clicks "No, I do not
approve this connection". The activity blindly tried to parse credentials
from this URI, leading to bad_data Sentry reports and a misleading error
toast for a deliberate user choice.

Detect success=false at the top of setupSite, skip the crash report, and
show an "Authorization cancelled" toast instead. Track the rejection via
the existing storing-failed analytics event so we can measure how often it
happens.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nbradbury
Copy link
Copy Markdown
Contributor Author

I suspect this issue might be caused by folks who hit "Reject" on the authorization page

@jkmassel I had Claude review your comment and you are correct - this PR fixed the NPE but we weren't handling rejection at all. I've updated the PR and its description to address this.

review-response-app-pass-rejection-2026-05-01.pdf

@wpmobilebot

This comment was marked as resolved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants