The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

VAPID - Voluntary Application Server Identification

VERSION

Version 0.02

SYNOPSIS

        use VAPID qw/generate/;

        my ($public, $private) = generate_vapid_keys()

        validate_public_key($public);
        validate_private_key($private);

        ...

        my $header = generate_vapid_header(
                'https://updates.push.services.mozilla.com',
                'mailto:email@lnation.org',
                $public,
                $private,
                time + 60
        );

EXPORT

generate_vapid_keys

Generates vapid private and public keys.

generate_vapid_header

Generates the Authorization and Crypto-Key headers that should be passed when making a request to push a notification.

generate_future_expiration_timestamp

Generates a time that is in future based upon the number of seconds if passed, the default is 12 hours.

validate_subject

Validate the subject.

validate_public_key

Validate the public key.

validate_private_key

Validate the private key.

validate_expiration

Validate the expiration key.

Example

The following is pseudo code but it should get you started.

STEP 1 - generate private and public keys

        my ($public, $private) = generate_vapid_keys()

        $c->stash({
                VAPID_USER_PUBLIC_KEY => $public
        });

STEP 2 - main.js

        var publicKey = [% VAPID_USER_PUBLIC_KEY %];
        navigator.serviceWorker.getRegistrations().then(function (registrations) {
                navigator.serviceWorker.register('/service-worker.js').then(function (worker) {
                        console.log('Service Worker Registered');
                        worker.pushManager.getSubscription().then(function(sub) {
                                if (sub === null) {
                                // Update UI to ask user to register for Push
                                        subscribeUser();
                                        console.log('Not subscribed to push service!');
                                } else {
                                // We have a subscription, update the database
                                        console.log('Subscription object: ', sub);
                                }
                        });
                });
        });

        function subscribeUser() {
                if ('serviceWorker' in navigator) {
                        navigator.serviceWorker.ready.then(function(reg) {
                                reg.pushManager.subscribe({
                                        userVisibleOnly: true,
                                        applicationServerKey: publicKey
                                }).then(function(sub) {
                                // We have a subscription, update the database
                                        console.log('Endpoint URL: ', sub.endpoint);
                                }).catch(function(e) {
                                        if (Notification.permission === 'denied') {
                                                console.warn('Permission for notifications was denied');
                                        } else {
                                                console.error('Unable to subscribe to push', e);
                                        }
                                });
                        })
                }
        }

STEP 3 - service-worker.js

        self.addEventListener('push', function(e) {
                var body;
                if (e.data) {
                        body = e.data.text();
                } else {
                        body = 'Push message no payload';
                }

                var options = {
                        body: body,
                        icon: 'images/notification-flat.png',
                        vibrate: [100, 50, 100],
                        data: {
                                dateOfArrival: Date.now(),
                                primaryKey: 1
                        },
                };
                e.waitUntil(
                        self.registration.showNotification('Push Notification', options)
                );
        });

STEP 4 - manifest.json

        {
                "short_name" : "Push",
                "name" : "Push Dashboard",
                "icons" : [
                        {
                        "src" : "/icon-144x144.png",
                        "type" : "image/png",
                        "sizes" : "144x144"
                        }
                ],
                "display" : "standalone",
                "start_url" : "/",
                "background_color" : "#fff",
                "theme_color" : "#fff",
                "scope" : "/"
        }       

STEP 5 - generate headers

        my $notificaiton_host = URI->new($subscription_url)->host;
        my $header = generate_vapid_header(
                "https://$notification_host",
                'mailto:email@lnation.org',
                $public,
                $private,
                time + 60
        );

STEP 6 - curl // UA code

        curl "{SUBSCRIBE_URL}" --request POST --header "TTL: 60" --header "Content-Length: 0" --header "Authorization: {AUTHORIZATION_HEADER}" --header "Crypto-Key: {CRYPTO_KEY_HEADER}"

AUTHOR

LNATION, <email at lnation.org>

BUGS

Please report any bugs or feature requests to bug-vapid at rt.cpan.org, or through the web interface at https://rt.cpan.org/NoAuth/ReportBug.html?Queue=VAPID. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc VAPID

You can also look for information at:

ACKNOWLEDGEMENTS

LICENSE AND COPYRIGHT

This software is Copyright (c) 2020 by LNATION.

This is free software, licensed under:

  The Artistic License 2.0 (GPL Compatible)