diff --git a/src/fcm/index.js b/src/fcm/index.js index 408c097..776de1f 100644 --- a/src/fcm/index.js +++ b/src/fcm/index.js @@ -2,35 +2,70 @@ const crypto = require('crypto'); const request = require('request-promise'); const { escape } = require('../utils/base64'); -const FCM_SUBSCRIBE = 'https://fcm.googleapis.com/fcm/connect/subscribe'; +const FIREBASE_INSTALLATION = 'https://firebaseinstallations.googleapis.com/v1/'; +const FCM_REGISTRATION = 'https://fcmregistrations.googleapis.com/v1/'; const FCM_ENDPOINT = 'https://fcm.googleapis.com/fcm/send'; -module.exports = registerFCM; +module.exports = { installFCM, registerFCM }; -async function registerFCM({ senderId, token }) { +function generateFirebaseFID() { + // A valid FID has exactly 22 base64 characters, which is 132 bits, or 16.5 + // bytes. our implementation generates a 17 byte array instead. + let fid = crypto.randomBytes(17); + + // Replace the first 4 random bits with the constant FID header of 0b0111. + fid[0] = 0b01110000 + (fid[0] % 0b00010000); + + return fid.toString('base64'); +} + +async function installFCM(config) { + const response = await request({ + url : `${FIREBASE_INSTALLATION}projects/${config.firebase.projectID}/installations`, + method : 'POST', + headers : { + 'x-firebase-client': btoa(JSON.stringify({ heartbeats: [], version: 2 })).toString('base64'), + 'x-goog-api-key': config.firebase.apiKey + }, + body : { + appId: config.firebase.appID, + authVersion: 'FIS_v2', + fid: generateFirebaseFID(), + sdkVersion: 'w:0.6.4' + }, + json: true + }); + return response; +} + +async function registerFCM(config) { const keys = await createKeys(); const response = await request({ - url : FCM_SUBSCRIBE, + url : `${FCM_REGISTRATION}projects/${config.firebase.projectID}/registrations`, method : 'POST', headers : { - 'Content-Type' : 'application/x-www-form-urlencoded', + 'x-goog-api-key' : config.firebase.apiKey, + 'x-goog-firebase-installations-auth' : config.authToken }, - form : { - authorized_entity : senderId, - endpoint : `${FCM_ENDPOINT}/${token}`, - encryption_key : keys.publicKey - .replace(/=/g, '') - .replace(/\+/g, '-') - .replace(/\//g, '_'), - encryption_auth : keys.authSecret - .replace(/=/g, '') - .replace(/\+/g, '-') - .replace(/\//g, '_'), + body : { + web: { + applicationPubKey: config.vapidKey, + auth: keys.authSecret + .replace(/=/g, '') + .replace(/\+/g, '-') + .replace(/\//g, '_'), + endpoint: `${FCM_ENDPOINT}/${config.token}`, + p256dh: keys.publicKey + .replace(/=/g, '') + .replace(/\+/g, '-') + .replace(/\//g, '_') + } }, + json: true }); return { keys, - fcm : JSON.parse(response), + fcm : response, }; }