Skip to content

fix: [SDK-5332] validate public API inputs to prevent native crashes - #1186

Merged
fadi-george merged 6 commits into
mainfrom
ar/sdk-5332
Oct 3, 2026
Merged

fadi-george merged 6 commits into
mainfrom
ar/sdk-5332

Conversation

@abdulraqeeb33

@abdulraqeeb33 abdulraqeeb33 commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

Description

One Line Summary

Validate public API inputs in Dart so invalid values return before reaching the native SDKs.

Details

Motivation

Fixes SDK-5332. Part of SDK-5327, matching react-native-onesignal#1997.

Empty identity strings were forwarded to the native channel. Some public methods also take dynamic or double values that Dart's types don't constrain, and the native bridges pass them through as is.

Dart's sound null safety already stops null or wrong-typed String, bool, int, and enum arguments, so the React Native boolean, integer, and log level guards aren't needed here.

Scope

isMissing in lib/src/utils.dart rejects null and empty strings for:

  • initialize(appId)
  • login(externalId)
  • addAlias / addAliases (label and id)
  • removeAlias / removeAliases
  • addEmail / removeEmail
  • addSms / removeSms
  • addTagWithKey / addTags (key only). An empty tag value is allowed. A null tag value is rejected.
  • removeTag / removeTags
  • addTrigger / addTriggers (key only). An empty trigger value is allowed.
  • removeTrigger / removeTriggers
  • trackEvent(name)
  • addOutcome / addUniqueOutcome / addOutcomeWithValue (name)
  • removeGroupedNotifications(notificationGroup)
  • Live Activities: enterLiveActivity (activityId, token), exitLiveActivity (activityId), setPushToStartToken (activityType, token), removePushToStartToken (activityType), startDefault (activityId)

Additional checks:

  • startDefault requires attributes and content to be maps. Both are dynamic, and the iOS bridge passes them straight through as NSDictionary.
  • addOutcomeWithValue rejects NaN and infinite values. Native handling differs: Android sends NaN as an outcome with no value, and +Infinity throws a caught JSONException that drops the outcome.

Rejected calls log a [OneSignal] message through a shared logError helper. Whitespace is still allowed. Public method signatures are unchanged.

setLanguage("") is not rejected. It is the reset to the device language, and there is no other reset path.

Testing

Unit testing

flutter test passed (272 tests). New and updated tests cover the rejection paths for login, tags, email, outcomes (empty name and non-finite value), removeGroupedNotifications, and every Live Activities method, including non-map startDefault attributes and content. flutter analyze lib test reported no issues.

Manual testing

Not run. The guards return before the method channel call, and the unit tests assert the mock channel is not invoked.

Affected code checklist

  • Notifications
    • Display
    • Open
    • Push Processing
    • Confirm Deliveries
  • Outcomes
  • Sessions
  • In-App Messaging
  • REST API requests
  • Public API changes

Checklist

Overview

  • I have filled out all REQUIRED sections above
  • PR does one thing
  • Any Public API changes are explained in the PR details and conform to existing APIs

Testing

  • I have included test coverage for these changes, or explained why they are not needed
  • All automated tests pass, or I explained why that is not possible
  • I have personally tested this on my device, or explained why that is not possible

Final pass

  • Code is as readable as possible.
  • I have reviewed this PR myself, ensuring it meets each checklist item

@abdulraqeeb33
abdulraqeeb33 requested a review from a team as a code owner September 22, 2026 20:42
Comment thread lib/src/user.dart Outdated
AR Abdul Azeez and others added 6 commits October 2, 2026 22:17
Blank login, app id, language, alias, email, sms, tag key, trigger key, and custom event names were forwarded to native. One helper now drops those calls.

Co-authored-by: Cursor <cursoragent@cursor.com>
Empty language is the only reset path, so the blank-string guard was a breaking change.

Co-authored-by: Cursor <cursoragent@cursor.com>
The checks read as predicates: isMissing, isMissingAny, and hasMissingEntries.
@fadi-george fadi-george changed the title fix: [SDK-5332] reject blank identity strings fix: [SDK-5332] validate public API inputs to prevent native crashes Oct 3, 2026
@fadi-george
fadi-george merged commit 237195f into main Oct 3, 2026
7 checks passed
@fadi-george
fadi-george deleted the ar/sdk-5332 branch October 3, 2026 06:08
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.

2 participants