Base64 Server Key Encryption for Firebase Cloud Messaging

I am stuck with this problem from 3 days and searched Google, but to no avail. I followed the instructions in the Push Notifications Example . But I get this nasty error when I try to implement it.

Uncaught (in promise) DOMException: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.

I realized that the colon (:) is not allowed in the Base64 String, but the server key specified in Firebase in the Cloud Messenging tab,

AAAA-8MWvk0:APA91bHmU8XL-rzOn9SPbpG98NSqAJcuhYBBh7oze_XhprBpK7Q9PPWm3PwBo6Llxby4zjhVtgvKPIaSAQGp-8RfMV10_d1GekzICrVX9oYO8pi6dOM4VTp52CCAzug6NYIa10tNddsgE2P5QowGAYcnRHxLkrHXsw

which contains a colon (don't worry, its just a test application, so no privacy issues).

When I tried to use the old server key, it just throws an error. I tried to use other keys given in Firebase too, but to no avail. Please tell me which server key to use and how?

I am attaching my piece of code that actually does push subscription.

 const API_KEY = "AIzaSyByIOl-mW0pu8SEXFeutB8jq59hhiau0wI";
 var GCM_ENDPOINT = 'https://fcm.googleapis.com/fcm/send';
 const legacy  = 'AIzaSyDGF8t125bJ4wBvYn_UdRewkTxHGr7KpH8';
 const applicationServerPublicKey = 'AAAA-8MWvk0APA91bHmU8XL-rzOn9SPbpG98NSqAJcuhYBBh7oze_XhprBpK7Q9PPWm3PwBo6Llxby4zjhVtgvKPIaSAQGp-8RfMV10_d1GekzICrVX9oYO8pi6dOM4VTp52CCAzug6NYIa10tNddsgE2P5QowGAYcnRHxLkrHXsw';

function urlB64ToUint8Array(base64String) {
 const padding = '='.repeat((4 - base64String.length % 4) % 4);
 const base64 = (base64String + padding)
 .replace(/\-/g, '+')
 .replace(/_/g, '/');
 console.log(base64);
 const rawData = window.atob(base64);
 console.log(rawData);
 const outputArray = new Uint8Array(rawData.length);

 for (let i = 0; i < rawData.length; ++i) {
  outputArray[i] = rawData.charCodeAt(i);
 }
 return outputArray;
}

function endpointWorkaround(pushSubscription) {
 // Make sure we only mess with GCM
 if(pushSubscription.endpoint.indexOf('https://fcm.googleapis.com/fcm/send') !== 0) {
  return pushSubscription.endpoint;
 }

 var mergedEndpoint = pushSubscription.endpoint;
 // Chrome 42 + 43 will not have the subscriptionId attached
 // to the endpoint.
 if (pushSubscription.subscriptionId &&
 pushSubscription.endpoint.indexOf(pushSubscription.subscriptionId) === -1)    {
  // Handle version 42 where you have separate subId and Endpoint
  mergedEndpoint = pushSubscription.endpoint + '/' +
  pushSubscription.subscriptionId;
 }
 return mergedEndpoint;
}

function sendSubscriptionToServer(subscription) {
 // TODO: Send the subscription.endpoint
 // to your server and save it to send a
 // push message at a later date
 //
 // For compatibly of Chrome 43, get the endpoint via
 // endpointWorkaround(subscription)
 console.log('TODO: Implement sendSubscriptionToServer()',    JSON.stringify(subscription));

 var mergedEndpoint = endpointWorkaround(subscription);

 // This is just for demo purposes / an easy to test by
 // generating the appropriate cURL command
 var temp = showCurlCommand(mergedEndpoint);
 return temp;
}

// NOTE: This code is only suitable for GCM endpoints,
// When another browser has a working version, alter
// this to send a PUSH request directly to the endpoint
function showCurlCommand(mergedEndpoint) {
 // The curl command to trigger a push message straight from GCM
 if (mergedEndpoint.indexOf(GCM_ENDPOINT) !== 0) {
  console.warn('This browser isn\'t currently ' + 'supported for this demo');
  return;
 }

 var endpointSections = mergedEndpoint.split('/');
 var subscriptionId = endpointSections[endpointSections.length - 1];

 var curlCommand = 'curl --header "Authorization: key=' + API_KEY + '" --header Content-Type:"application/json" ' + GCM_ENDPOINT + ' -d "{\\"registration_ids\\":[\\"' + subscriptionId + '\\"]}"';

 console.log(curlCommand);
 return subscriptionId;
}

function initialiseState() {
 // Are Notifications supported in the service worker?
 if (!('showNotification' in ServiceWorkerRegistration.prototype)) {
  console.warn('Notifications aren\'t supported.');
  return;
 }

 // Check the current Notification permission.
 // If its denied, it a permanent block until the
 // user changes the permission
 if (Notification.permission === 'denied') {
  console.warn('The user has blocked notifications.');
  return;
 }

 // Check if push messaging is supported
 if (!('PushManager' in window)) {
  console.warn('Push messaging isn\'t supported.');
  return;
 }
 var prom = new Promise(function(resolve, reject) {
  navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
    // Do we already have a push message subscription?
serviceWorkerRegistration.pushManager.getSubscription().then(function(subscription) {
            // Enable any UI which subscribes / unsubscribes from
            // push messages.
            // var pushButton = document.querySelector('.js-push-button');
            // pushButton.disabled = false;

            if (!subscription) {
                // We aren’t subscribed to push, so set UI
                // to allow the user to enable push
        subscribe();
                return;
            }

            // Keep your server in sync with the latest subscription
      var temp = sendSubscriptionToServer(subscription);
      if(temp){
        resolve(temp);
      }else{
        reject("Oops!")
      }

            // Set your UI to show they have subscribed for
            // push messages
            // pushButton.textContent = 'Disable Push Messages';
            // isPushEnabled = true;
        })
        .catch(function(err) {
            console.error('Error during getSubscription()', err);
      reject(err);
        });
});
});
return prom;
}

function unsubscribe() {
 // var pushButton = document.querySelector('.js-push-button');
 // pushButton.disabled = true;

 navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
  // To unsubscribe from push messaging, you need get the
  // subcription object, which you can call unsubscribe() on.
  serviceWorkerRegistration.pushManager.getSubscription().then(
  function(pushSubscription) {
   // Check we have a subscription to unsubscribe
   if (!pushSubscription) {
    // No subscription object, so set the state
    // to allow the user to subscribe to push
    //  isPushEnabled = false;
    //  pushButton.disabled = false;
    //  pushButton.textContent = 'Enable Push Messages';
    return;
   }

   // TODO: Make a request to your server to remove
   // the users data from your data store so you
   // don't attempt to send them push messages anymore

   // We have a subcription, so call unsubscribe on it
   pushSubscription.unsubscribe().then(function() {
    //  pushButton.disabled = false;
    //  pushButton.textContent = 'Enable Push Messages';
    //  isPushEnabled = false;
   }).catch(function(e) {
     // We failed to unsubscribe, this can lead to
     // an unusual state, so may be best to remove
     // the subscription id from your data store and
     // inform the user that you disabled push

     console.log('Unsubscription error: ', e);
     //  pushButton.disabled = false;
   });
 }).catch(function(e) {
   console.error('Error thrown while unsubscribing from ' + 'push messaging.', e);
 });
});
}

function subscribe() {
 // Disable the button so it can't be changed while
 // we process the permission request
 // var pushButton = document.querySelector('.js-push-button');
 // pushButton.disabled = true;

 navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
  const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
  serviceWorkerRegistration.pushManager.subscribe({userVisibleOnly: true,  applicationServerKey: applicationServerKey})
 .then(function(subscription) {
  console.log(subscription);
  // The subscription was successful
  //  isPushEnabled = true;
  //  pushButton.textContent = 'Disable Push Messages';
  //  pushButton.disabled = false;

  // TODO: Send the subscription subscription.endpoint
  // to your server and save it to send a push message
  // at a later date
  return sendSubscriptionToServer(subscription);
 })
 .catch(function(e) {
  if (Notification.permission === 'denied') {
   // The user denied the notification permission which
   // means we failed to subscribe and the user will need
   // to manually change the notification permission to
   // subscribe to push messages
   console.log('Permission for Notifications was denied');
   //  pushButton.disabled = true;
  } else {
   // A problem occurred with the subscription, this can
   // often be down to an issue or lack of the gcm_sender_id
   // and / or gcm_user_visible_only
   console.log('Unable to subscribe to push.', e);
   //  pushButton.disabled = false;
   //  pushButton.textContent = 'Enable Push Messages';
  }
 });
});
}
+4
source share
1 answer

This sadly confuses Chrome.

At the most basic level: Web Push is completely separate from Firebase Messaging for the Internet.

Web Push Key and Application Server

Web push requires an application server key, this is what you pass in the subscription call to the push worker manager:

pushManager.subscribe({userVisibleOnly: true, applicationServerKey: MY_KEY});

In web push, there applicationServerKeymust be a Uint8Array (i.e. an array of 65 bytes). This key can be generated anyway, just make sure you close the private key and use the public key in your web application.

, , , : https://web-push-codelab.appspot.com/

" " ( push-, ).

, -push node CLI.

Firebase

Firebase Messaging SDK push , . , Firebase Messaging SDK API Cloud Firebase push- Web Push Protocol, , .

" " Firebase - , push-, "".

https://fcm.googleapis.com/fcm/send
Content-Type: application/json
Authorization: key=<YOUR SERVER KEY HERE>

  • Firebase Messaging SDK -push, , API .
  • Web Push ( -) Firebase ( push), push push push-. (Chrome Firebase , , -, Firebase).
+2

Source: https://habr.com/ru/post/1664957/


All Articles