web push

Web Push library for Ruby (RFC8030) - A fork of zaru/webpush actively maintained by Pushpad with many improvements, bug fixes and updates.

150
16
Ruby

WebPush

Gem Version
Build Status

This gem makes it possible to send push messages to web browsers from Ruby backends using the Web Push Protocol. It supports Message Encryption for Web Push and VAPID.

Note: This is an open source gem for Web Push. If you want to send web push notifications from Ruby using Pushpad, you need to use another gem (pushpad gem).

Installation

Add this line to the Gemfile:

gem 'web-push'

Or install the gem:

$ gem install web-push

Usage

Sending a web push message to a visitor of your website requires a number of steps:

  1. In the user’s web browser, a serviceWorker is installed and activated and its pushManager property is subscribed to push events with your VAPID public key, which creates a subscription JSON object on the client side.
  2. Your server uses the web-push gem to send a notification with the subscription obtained from the client and an optional payload (the message).
  3. Your service worker is set up to receive 'push' events. To trigger a desktop notification, the user has accepted the prompt to receive notifications from your site.

Generating VAPID keys

Use web-push to generate a VAPID key pair (that has both a public_key and private_key) and save it on the server side.

# One-time, on the server
vapid_key = WebPush.generate_key

# Save these in your application server settings
vapid_key.public_key
vapid_key.private_key

# Or you can save in PEM format if you prefer
vapid_key.to_pem

Installing a service worker

Your application must use JavaScript to register a service worker script at an appropriate scope (root is recommended).

navigator.serviceWorker.register('/service-worker.js')

Subscribing to push notifications

The VAPID public key that you generated earlier needs to be made available to JavaScript, which can be done in many ways, for example with a fetch request or when rendering the HTML template in Ruby:

<script>
// Make the VAPID public key available to the client as a Uint8Array
window.vapidPublicKey = new Uint8Array(<%= Base64.urlsafe_decode64(ENV['VAPID_PUBLIC_KEY']).bytes %>)

// Or you can pass it as a string if you prefer
window.vapidPublicKey = "<%= ENV['VAPID_PUBLIC_KEY'].delete('=') %>"
</script>

Your JavaScript code uses the pushManager interface to subscribe to push notifications, passing the VAPID public key to the subscription settings.

// When serviceWorker is supported, installed, and activated,
// subscribe the pushManager property with the vapidPublicKey
navigator.serviceWorker.ready.then((serviceWorkerRegistration) => {
  serviceWorkerRegistration.pushManager
  .subscribe({
    userVisibleOnly: true,
    applicationServerKey: window.vapidPublicKey
  });
});

Triggering a web push notification

In order to send web push notifications, the push subscription must be stored in the backend. Get the subscription with pushManager.getSubscription() and store it in your database.

Then you can use this gem to send web push messages:

WebPush.payload_send(
  message: message,
  endpoint: subscription['endpoint'],
  p256dh: subscription['keys']['p256dh'],
  auth: subscription['keys']['auth'],
  vapid: {
    subject: "mailto:[email protected]",
    public_key: ENV['VAPID_PUBLIC_KEY'],
    private_key: ENV['VAPID_PRIVATE_KEY']
  },
  ssl_timeout: 5, # optional value for Net::HTTP#ssl_timeout=
  open_timeout: 5, # optional value for Net::HTTP#open_timeout=
  read_timeout: 5 # optional value for Net::HTTP#read_timeout=
)

Receiving the push event

Your service-worker.js script should respond to 'push' events. One action it can take is to trigger desktop notifications by calling showNotification on the registration property.

self.addEventListener('push', (event) => {
  // Get the push message
  var message = event.data;
  // Display a notification
  event.waitUntil(self.registration.showNotification('Example'));
});

Before the notifications can be displayed, the user must grant permission for notifications in a browser prompt. Use something like this in your JavaScript code:

Notification.requestPermission();

If everything worked, you should see a desktop notification triggered via web push. Yay!

API

With a payload

message = {
  title: "Example",
  body: "Hello, world!",
  icon: "https://example.com/icon.png"
}

WebPush.payload_send(
  endpoint: "https://fcm.googleapis.com/gcm/send/eah7hak....",
  message: JSON.generate(message),
  p256dh: "BO/aG9nYXNkZmFkc2ZmZHNmYWRzZmFl...",
  auth: "aW1hcmthcmFpa3V6ZQ==",
  ttl: 600, # optional, ttl in seconds, defaults to 2419200 (4 weeks)
  urgency: 'normal' # optional, it can be very-low, low, normal, high, defaults to normal
)

Without a payload

WebPush.payload_send(
  endpoint: "https://fcm.googleapis.com/gcm/send/eah7hak....",
  p256dh: "BO/aG9nYXNkZmFkc2ZmZHNmYWRzZmFl...",
  auth: "aW1hcmthcmFpa3V6ZQ=="
)

With VAPID

VAPID details are given as a hash with :subject, :public_key, and
:private_key. The :subject is a contact URI for the application server as either a “mailto:” or an “https:” address. The :public_key and :private_key should be passed as the base64-encoded values generated with WebPush.generate_key.

WebPush.payload_send(
  endpoint: "https://fcm.googleapis.com/gcm/send/eah7hak....",
  message: "A message",
  p256dh: "BO/aG9nYXNkZmFkc2ZmZHNmYWRzZmFl...",
  auth: "aW1hcmthcmFpa3V6ZQ==",
  vapid: {
    subject: "mailto:[email protected]",
    public_key: ENV['VAPID_PUBLIC_KEY'],
    private_key: ENV['VAPID_PRIVATE_KEY']
  }
)

With VAPID in PEM format

This library also supports the PEM format for the VAPID keys:

WebPush.payload_send(
  endpoint: "https://fcm.googleapis.com/gcm/send/eah7hak....",
  message: "A message",
  p256dh: "BO/aG9nYXNkZmFkc2ZmZHNmYWRzZmFl...",
  auth: "aW1hcmthcmFpa3V6ZQ==",
  vapid: {
    subject: "mailto:[email protected]",
    pem: ENV['VAPID_KEYS']
  }
)

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/pushpad/web-push.

Credits

This library is a fork of zaru/webpush actively maintained by Pushpad with many improvements, bug fixes and frequent updates.