Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve decodeBase64() to throw on invalid input rather than silently accept it #7019

Merged
merged 8 commits into from
Feb 11, 2023

Conversation

dconeybe
Copy link
Contributor

@dconeybe dconeybe commented Feb 9, 2023

Fix all decodeBase64() functions to throw an exception when given invalid input. Previously, some implementations silently accepted invalid input, potentially leading to bugs.

The decodeBase64() function in packages/firestore/src/platform/base64.ts has different implementations on different platforms (e.g. browser, node, and react native). These implementations behave differently when given an invalid base64 string to decode:

  • browser throws DOMException on any invalid input.
  • node silently ignores invalid input by truncating at the first invalid character.
  • react native throws Error on some invalid inputs, and silently accepts others.

The node implementation used to have a regular expression that validated the input (link); however, it was removed in #6008 because it was too slow.

The "parent" decodeBase64() function now validates that the input string is valid base64 using an algorithm that is orders of magnitude more efficient and robust than a regular expression. It verifies that the input string has the expected length based on the number of bytes returned from the platform-specific base64 decoding function to which it delegates. If the length is not correct then the platform-specific function must have truncated at an invalid base64 character. In this case a new Base64DecodeError is thrown.

Credit for this PR goes to @milaGGL from #6992. I'm merely merging a small component of that PR into the master branch to reduce the diff when her PR ultimately gets merged.

@changeset-bot
Copy link

changeset-bot bot commented Feb 9, 2023

🦋 Changeset detected

Latest commit: 63b10fc

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 28 packages
Name Type
@firebase/firestore Patch
@firebase/util Patch
firebase Patch
@firebase/firestore-compat Patch
@firebase/analytics-compat Patch
@firebase/analytics Patch
@firebase/app-check-compat Patch
@firebase/app-check Patch
@firebase/app-compat Patch
@firebase/app Patch
@firebase/auth-compat Patch
@firebase/auth Patch
@firebase/component Patch
@firebase/database-compat Patch
@firebase/database-types Patch
@firebase/database Patch
@firebase/functions-compat Patch
@firebase/functions Patch
@firebase/installations-compat Patch
@firebase/installations Patch
@firebase/messaging-compat Patch
@firebase/messaging Patch
@firebase/performance-compat Patch
@firebase/performance Patch
@firebase/remote-config-compat Patch
@firebase/remote-config Patch
@firebase/storage-compat Patch
@firebase/storage Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@google-oss-bot
Copy link
Contributor

google-oss-bot commented Feb 9, 2023

Size Report 1

Affected Products

  • @firebase/firestore

    TypeBase (4b44553)Merge (0da034b)Diff
    browser274 kB274 kB+195 B (+0.1%)
    esm5341 kB341 kB+257 B (+0.1%)
    module274 kB274 kB+195 B (+0.1%)
    react-native274 kB274 kB+210 B (+0.1%)
  • @firebase/firestore-lite

    TypeBase (4b44553)Merge (0da034b)Diff
    browser87.4 kB87.6 kB+195 B (+0.2%)
    esm5105 kB105 kB+253 B (+0.2%)
    module87.4 kB87.6 kB+195 B (+0.2%)
    react-native87.6 kB87.8 kB+212 B (+0.2%)
  • @firebase/util

    TypeBase (4b44553)Merge (0da034b)Diff
    browser22.9 kB23.1 kB+159 B (+0.7%)
    esm524.4 kB24.7 kB+315 B (+1.3%)
    main30.0 kB30.4 kB+443 B (+1.5%)
    module22.9 kB23.1 kB+159 B (+0.7%)
  • bundle

    43 size changes

    TypeBase (4b44553)Merge (0da034b)Diff
    analytics (logEvent)43.0 kB43.1 kB+93 B (+0.2%)
    app-check (CustomProvider)36.1 kB36.2 kB+93 B (+0.3%)
    app-check (ReCaptchaEnterpriseProvider)38.4 kB38.5 kB+95 B (+0.2%)
    app-check (ReCaptchaV3Provider)38.4 kB38.5 kB+95 B (+0.2%)
    auth (Anonymous)67.4 kB67.5 kB+95 B (+0.1%)
    auth (EmailAndPassword)71.5 kB71.6 kB+95 B (+0.1%)
    auth (GoogleFBTwitterGitHubPopup)93.9 kB94.0 kB+94 B (+0.1%)
    auth (GooglePopup)91.1 kB91.2 kB+95 B (+0.1%)
    auth (GoogleRedirect)91.4 kB91.5 kB+95 B (+0.1%)
    auth (Phone)77.6 kB77.7 kB+95 B (+0.1%)
    database (Append to a list of data)148 kB148 kB+93 B (+0.1%)
    database (Filtering data)147 kB147 kB+93 B (+0.1%)
    database (Listen for child events)163 kB164 kB+93 B (+0.1%)
    database (Listen for value events + Detach listeners)163 kB164 kB+93 B (+0.1%)
    database (Listen for value events)163 kB163 kB+93 B (+0.1%)
    database (Read data once)163 kB163 kB+93 B (+0.1%)
    database (Save data as transactions)165 kB165 kB+93 B (+0.1%)
    database (Sort data)149 kB149 kB+93 B (+0.1%)
    database (Write data)147 kB147 kB+93 B (+0.1%)
    firestore (Persistence)281 kB281 kB+288 B (+0.1%)
    firestore (Query Cursors)220 kB220 kB+288 B (+0.1%)
    firestore (Query)218 kB218 kB+288 B (+0.1%)
    firestore (Read data once)205 kB205 kB+288 B (+0.1%)
    firestore (Realtime updates)207 kB207 kB+288 B (+0.1%)
    firestore (Transaction)188 kB188 kB+288 B (+0.2%)
    firestore (Write data)188 kB188 kB+288 B (+0.2%)
    firestore-lite (Query Cursors)81.3 kB81.6 kB+288 B (+0.4%)
    firestore-lite (Query)77.4 kB77.7 kB+288 B (+0.4%)
    firestore-lite (Read data once)59.4 kB59.7 kB+288 B (+0.5%)
    firestore-lite (Transaction)84.0 kB84.3 kB+288 B (+0.3%)
    firestore-lite (Write data)68.9 kB69.2 kB+288 B (+0.4%)
    functions (call)30.9 kB31.0 kB+100 B (+0.3%)
    messaging (send + receive)46.4 kB46.5 kB+95 B (+0.2%)
    performance (trace)50.8 kB50.9 kB+95 B (+0.2%)
    remote-config (getAndFetch)45.4 kB45.4 kB+93 B (+0.2%)
    storage (getBytes)41.1 kB41.2 kB+93 B (+0.2%)
    storage (getDownloadURL)43.2 kB43.3 kB+93 B (+0.2%)
    storage (getMetadata)42.7 kB42.8 kB+93 B (+0.2%)
    storage (list + listAll)42.1 kB42.2 kB+93 B (+0.2%)
    storage (updateMetadata)42.9 kB43.0 kB+93 B (+0.2%)
    storage (uploadBytes)48.0 kB48.1 kB+93 B (+0.2%)
    storage (uploadBytesResumable)58.0 kB58.1 kB+93 B (+0.2%)
    storage (uploadString)48.2 kB48.3 kB+93 B (+0.2%)

  • firebase

    19 size changes

    TypeBase (4b44553)Merge (0da034b)Diff
    firebase-app-check-compat.js22.6 kB22.7 kB+101 B (+0.4%)
    firebase-app-check.js21.4 kB21.5 kB+104 B (+0.5%)
    firebase-app-compat.js28.8 kB28.9 kB+99 B (+0.3%)
    firebase-app.js92.8 kB93.1 kB+243 B (+0.3%)
    firebase-auth-compat.js126 kB126 kB+101 B (+0.1%)
    firebase-auth-cordova.js138 kB138 kB+96 B (+0.1%)
    firebase-auth-react-native.js150 kB150 kB+126 B (+0.1%)
    firebase-auth.js117 kB117 kB+101 B (+0.1%)
    firebase-compat.js747 kB747 kB+297 B (+0.0%)
    firebase-database-compat.js166 kB166 kB+105 B (+0.1%)
    firebase-database.js154 kB154 kB+100 B (+0.1%)
    firebase-firestore-compat.js321 kB321 kB+295 B (+0.1%)
    firebase-firestore-lite.js94.0 kB94.3 kB+294 B (+0.3%)
    firebase-firestore.js323 kB323 kB+297 B (+0.1%)
    firebase-functions.js10.9 kB11.0 kB+91 B (+0.8%)
    firebase-performance-standalone-compat.es2017.js89.9 kB90.0 kB+106 B (+0.1%)
    firebase-performance-standalone-compat.js67.0 kB67.2 kB+140 B (+0.2%)
    firebase-storage-compat.js41.2 kB41.3 kB+101 B (+0.2%)
    firebase-storage.js40.2 kB40.3 kB+99 B (+0.2%)

Test Logs

  1. https://storage.googleapis.com/firebase-sdk-metric-reports/rB93EGV0Ly.html

@google-oss-bot
Copy link
Contributor

google-oss-bot commented Feb 9, 2023

Size Analysis Report 1

This report is too large (756,081 characters) to be displayed here in a GitHub comment. Please use the below link to see the full report on Google Cloud Storage.

Test Logs

  1. https://storage.googleapis.com/firebase-sdk-metric-reports/HSfuMEnsml.html

@dconeybe dconeybe requested a review from milaGGL February 9, 2023 20:18
Copy link
Contributor

@milaGGL milaGGL left a comment

Choose a reason for hiding this comment

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

LGTM

Base automatically changed from dconeybe/PlatformTextEncoderRefactor to master February 10, 2023 14:11
);
} catch (e) {
if (e instanceof DecodeBase64StringError) {
throw new Base64DecodeError('Invalid base64 string: ' + e);
Copy link
Contributor

Choose a reason for hiding this comment

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

I haven't followed these all the way up the chain but will they eventually get wrapped in a FirestoreError?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, the error won't be re-thrown as a FirestoreError. The specific use case is a future optimization that involves decoding base64. If, for some reason, we get invalid base64 from the backend then we will just ignore it and disable the optimization. We don't expect to ever get invalid base64, but it could theoretically happen and if it ever does we don't want to crash.

The problem was that it was previously not possible to reliably detect an invalid base64 string. This PR fixes that by having the new Base64DecodeError always thrown if an invalid base64 string is given as input. The future code will catch this exception and use it to disable the optimization.

@dconeybe dconeybe merged commit c59f537 into master Feb 11, 2023
@dconeybe dconeybe deleted the dconeybe/Base64DecodeFailOnBadInput branch February 11, 2023 00:31
NhienLam pushed a commit that referenced this pull request Feb 14, 2023
@google-oss-bot google-oss-bot mentioned this pull request Mar 1, 2023
@firebase firebase locked and limited conversation to collaborators Mar 13, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants