parse-community / parse-server-push-adapter

A push notification adapter for Parse Server
https://parseplatform.org
MIT License
85 stars 100 forks source link

feat: Send Android push notifications to Firebase Cloud Messaging API (HTTP v1) by setting the push adapter option `firebaseServiceAccount` #222

Closed jimnor0xF closed 4 months ago

jimnor0xF commented 10 months ago

New Pull Request Checklist

Issue Description

Closes https://github.com/parse-community/parse-server-push-adapter/issues/219.

Adds FCM support to the parse-server-push-adapter.

Approach

https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages Payload example:

  await Parse.Push.send(
    {
      where: query,
      notification: {
        title: title,
        body: body
      },
      data: {
        type: type
      },
      android: {
        priority: 'high'
      },
      apns: {
        headers: {
          'apns-priority': '5'
        },
        payload: {
          aps: {
            contentAvailable: true
          }
        }
      }
    },
    { useMasterKey: true }
  )

TODOs before merging

parse-github-assistant[bot] commented 10 months ago

Thanks for opening this pull request!

mtrezza commented 10 months ago

If I understand this PR correctly, you are adding a "raw FCM support" to the adapter, correct? That just to clarify, because this push adapter already has FCM support, in fact I believe GCM has been first deprecated in 2019 and has already been turned off by now. In code the term "GCM" is still used, but the payload is handled by dependency @parse/node-gcm which is already using FCM -- but with an API that is deprecated, as described in https://github.com/parse-community/parse-server-push-adapter/issues/219.

Currently makes all deviceTypes use FCM. Not sure if this is what we want.

I don't think so, because we'd force a developer to use a 3rd party service (Firebase) to send a push to APNS. But I think you're making a good point; it should be configurable to use FCM also for Apple devices. So we'll probably need a new adapter option to configure the routing according to deviceType.

Since this is our current adapter config structure:

push: {
    android: {
      apiKey: '...'
    },
    ios: {
      pfx: '/file/path/to/XXX.p12',
      passphrase: '', // optional password to your p12/PFX
      bundleId: '',
      production: false
    }
}

It's based on device type android, ios, so we could introduce new keys like ios.fcmApiKey and android.fcmApiKey. For ios.fcmApiKey it means that notifications to Apple devices will also be sent through FCM. For android.fcmApiKey it means hat it will require the "raw" FCM payload. For a developer it has the advantage that it's the same FCM payload structure bot all device types, if they configure the adapter this way and want to set up FCM to send pushes to APNS.

The "raw" FCM payload would be a breaking change from the current FCM payload if I'm not mistaken. We don't want this to be a breaking change, so while I think it makes sense allow to pass this "raw" payload, we would need an additional change to adapt the current "GCM" file to use the firebase-admin SDK while maintaining the current payload structure. But since you have already managed to write the "raw" FCM code, it would just require a payload conversion I assume?

I'd split this up into 2 changes (in 2 PRs if you like):

jimnor0xF commented 10 months ago

Correct, and I agree with all points listed above. Mostly wanted to get something working quick for myself to begin with ;) I'll go ahead with the approach you suggested.

mtrezza commented 10 months ago

Great, and thanks for taking this on, this is really a key issue for many Parse Server deployments.

jimnor0xF commented 9 months ago

@mtrezza Addressed some of the above mentioned issues.

You mentioned this: "so while I think it makes sense allow to pass this "raw" payload, we would need an additional change to adapt the current "GCM" file to use the firebase-admin SDK while maintaining the current payload structure."

GCM uses "apiKey" which is not compatible with the FCM v1 API. Instead, I added some logic so GCM payloads are supported in the FCM module.

If "rawPayload" is present in the Parse.Push.send method it will use the raw FCM payload instead.

codecov[bot] commented 9 months ago

Codecov Report

Attention: 67 lines in your changes are missing coverage. Please review.

Comparison is base (5536102) 100.00% compared to head (707223e) 81.38%.

:exclamation: Current head 707223e differs from pull request most recent head cccba90. Consider uploading reports for the commit cccba90 to get more accurate results

Additional details and impacted files ```diff @@ Coverage Diff @@ ## master #222 +/- ## ============================================ - Coverage 100.00% 81.38% -18.62% ============================================ Files 5 6 +1 Lines 277 360 +83 ============================================ + Hits 277 293 +16 - Misses 0 67 +67 ``` | [Files](https://app.codecov.io/gh/parse-community/parse-server-push-adapter/pull/222?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community) | Coverage Δ | | |---|---|---| | [src/ParsePushAdapter.js](https://app.codecov.io/gh/parse-community/parse-server-push-adapter/pull/222?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community#diff-c3JjL1BhcnNlUHVzaEFkYXB0ZXIuanM=) | `95.12% <71.42%> (-4.88%)` | :arrow_down: | | [src/FCM.js](https://app.codecov.io/gh/parse-community/parse-server-push-adapter/pull/222?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community#diff-c3JjL0ZDTS5qcw==) | `16.66% <16.66%> (ø)` | |

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

mtrezza commented 8 months ago

@jimnor0xF Would you be so king and rebase this PR to resolve the conflicts? I've done some upgrading in other PRs.

jimnor0xF commented 8 months ago

@jimnor0xF Would you be so king and rebase this PR to resolve the conflicts? I've done some upgrading in other PRs.

Rebased.

mtrezza commented 8 months ago

The package-lock has a suspiciously large change, even though only 1 dep has been added; could you please use the file from alpha and just run npm i -ED firebase-admin@11.10.1?

mtrezza commented 7 months ago

@jimnor0xF Apologies, I wrote -ED, but this shouldn't be a dev dependency, right? Because it's currently only added under devDependencies. If this shouldn't be a dev dependency, could you use the alpha file again and just do npm i -E firebase-admin@11.10.1?

mtrezza commented 7 months ago

Thanks, running CI...

paulrolfe commented 4 months ago

Hey, just wanted to say thank you for this PR @jimnor0xF, I've put it into use in my project to send pushes using FCM and it's working great. Hope it gets merged into master soon.

parseplatformorg commented 4 months ago

🎉 This change has been released in version 5.1.0

breadluvr commented 1 month ago

Hello,

I'm experiencing issues with integrating Firebase Cloud Messaging using a service account on Heroku with parse-server@7.1.0-alpha.6. While the server functions correctly with the older GCM API, transitioning to FCM with service account credentials leads to a generic Heroku error without detailed diagnostics. Here are the steps I've followed:

Base Installation: parse-server@7.1.0-alpha.6 works with the legacy GCM API.

Issue with FCM Service Account: Problems begin when configuring the firebaseServiceAccount for FCM.

Configuration Details:

I exported the service account JSON file from the Google Cloud Console.

Set up the service account credentials in the server configuration as follows:

push: {
  android: {
    firebaseServiceAccount: {
      type: "service_account",
      project_id: process.env.PUSH_ANDROID_PROJECT_ID,
      private_key_id: process.env.PUSH_ANDROID_PRIVATE_KEY_ID,
      private_key: process.env.PUSH_ANDROID_PRIVATE_KEY,
      client_email: process.env.PUSH_ANDROID_CLIENT_EMAIL,
      client_id: process.env.PUSH_ANDROID_CLIENT_ID,
      auth_uri: "https://accounts.google.com/o/oauth2/auth",
      token_uri: "https://oauth2.googleapis.com/token",
      auth_provider_x509_cert_url: "https://www.googleapis.com/oauth2/v1/certs",
      client_x509_cert_url: process.env.PUSH_ANDROID_CERT_URL,
      universe_domain: "googleapis.com",
    }
  }
}

I also tried using JSON.stringify on the object.

Alternative Attempt: I've also tried etting the firebaseServiceAccount as a path to the JSON file as suggested in spec/ParsePushAdapter.spec.js:

push: {
  android: {
    firebaseServiceAccount: path.join(__dirname, 'foo', 'bar.json')
  }
}

Both methods result in a generic Heroku error, and I'm unable to find relevant documentation on setting up the new FCM authentication method using a service account. Could you provide any insights or guidance on what might be causing these issues or how to resolve them?

mtrezza commented 1 month ago

There is a fix we'll merge. If you then still encounter a bug please open a new GitHub issue.

Note that we don't use GitHub for support. For help with Parse Platform we recommend our community forum or our community chat.