Socket
Socket
Sign inDemoInstall

@firebase/messaging

Package Overview
Dependencies
Maintainers
3
Versions
3277
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@firebase/messaging - npm Package Compare versions

Comparing version 0.1.9-canary.a1e346f to 0.1.9-canary.f173ad0

dist/cjs/src/helpers/base64-to-array-buffer.d.ts

51

dist/cjs/src/controllers/controller-interface.d.ts

@@ -1,2 +0,5 @@

import TokenManager from '../models/token-manager';
import TokenDetailsModel from '../models/token-details-model';
import VapidDetailsModel from '../models/vapid-details-model';
import IIDModel from '../models/iid-model';
export declare const TOKEN_EXPIRATION_MILLIS: number;
export default class ControllerInterface {

@@ -7,3 +10,5 @@ app: any;

private messagingSenderId_;
private tokenManager_;
private tokenDetailsModel_;
private vapidDetailsModel_;
private iidModel_;
/**

@@ -16,16 +21,29 @@ * An interface of the Messaging Service API

* @export
* @return {Promise<string> | Promise<null>} Returns a promise that
* resolves to an FCM token.
*/
getToken(): Promise<any>;
getToken(): Promise<string | null>;
/**
* This method deletes tokens that the token manager looks after and then
* unregisters the push subscription if it exists.
* manageExistingToken is triggered if there's an existing FCM token in the
* database and it can take 3 different actions:
* 1) Retrieve the existing FCM token from the database.
* 2) If VAPID details have changed: Delete the existing token and create a
* new one with the new VAPID key.
* 3) If the database cache is invalidated: Send a request to FCM to update
* the token, and to check if the token is still valid on FCM-side.
*/
private manageExistingToken(tokenDetails, swReg);
private isTokenStillValid(tokenDetails);
private updateToken(tokenDetails, swReg);
private getNewToken(swReg);
/**
* This method deletes tokens that the token manager looks after,
* unsubscribes the token from FCM and then unregisters the push
* subscription if it exists. It returns a promise that indicates
* whether or not the unsubscribe request was processed successfully.
* @export
* @param {string} token
* @return {Promise<void>}
*/
deleteToken(token: any): Promise<boolean>;
deleteToken(token: string): Promise<Boolean>;
getSWRegistration_(): Promise<ServiceWorkerRegistration>;
getPublicVapidKey_(): Promise<Uint8Array>;
requestPermission(): void;
getPushSubscription_(registration: any, publicVapidKey: any): Promise<PushSubscription>;
/**

@@ -38,2 +56,7 @@ * @export

* @export
* @param {!string} b64PublicKey
*/
usePublicVapidKey(b64PublicKey: any): void;
/**
* @export
* @param {!firebase.Observer|function(*)} nextOrObserver

@@ -65,3 +88,3 @@ * @param {function(!Error)=} optError

*/
delete(): Promise<void>;
delete(): Promise<[void, void]>;
/**

@@ -73,7 +96,9 @@ * Returns the current Notification Permission state.

getNotificationPermission_(): any;
getTokenDetailsModel(): TokenDetailsModel;
getVapidDetailsModel(): VapidDetailsModel;
/**
* @protected
* @returns {TokenManager}
* @returns {IIDModel}
*/
getTokenManager(): TokenManager;
getIIDModel(): IIDModel;
}

@@ -20,5 +20,10 @@ /**

var errors_1 = require("../models/errors");
var token_manager_1 = require("../models/token-manager");
var token_details_model_1 = require("../models/token-details-model");
var vapid_details_model_1 = require("../models/vapid-details-model");
var notification_permission_1 = require("../models/notification-permission");
var iid_model_1 = require("../models/iid-model");
var array_buffer_to_base64_1 = require("../helpers/array-buffer-to-base64");
var SENDER_ID_OPTION_NAME = 'messagingSenderId';
// Database cache should be invalidated once a week.
exports.TOKEN_EXPIRATION_MILLIS = 7 * 24 * 60 * 60 * 1000; // 7 days
var ControllerInterface = /** @class */ (function () {

@@ -37,11 +42,11 @@ /**

this.messagingSenderId_ = app.options[SENDER_ID_OPTION_NAME];
this.tokenManager_ = new token_manager_1.default();
this.tokenDetailsModel_ = new token_details_model_1.default();
this.vapidDetailsModel_ = new vapid_details_model_1.default();
this.iidModel_ = new iid_model_1.default();
this.app = app;
this.INTERNAL = {};
this.INTERNAL.delete = function () { return _this.delete; };
this.INTERNAL.delete = function () { return _this.delete(); };
}
/**
* @export
* @return {Promise<string> | Promise<null>} Returns a promise that
* resolves to an FCM token.
*/

@@ -59,23 +64,143 @@ ControllerInterface.prototype.getToken = function () {

}
return this.getSWRegistration_().then(function (registration) {
return _this.tokenManager_
.getSavedToken(_this.messagingSenderId_, registration)
.then(function (token) {
if (token) {
return token;
var swReg;
return this.getSWRegistration_()
.then(function (reg) {
swReg = reg;
return _this.tokenDetailsModel_.getTokenDetailsFromSWScope(swReg.scope);
})
.then(function (tokenDetails) {
if (tokenDetails) {
return _this.manageExistingToken(tokenDetails, swReg);
}
return _this.getNewToken(swReg);
});
};
/**
* manageExistingToken is triggered if there's an existing FCM token in the
* database and it can take 3 different actions:
* 1) Retrieve the existing FCM token from the database.
* 2) If VAPID details have changed: Delete the existing token and create a
* new one with the new VAPID key.
* 3) If the database cache is invalidated: Send a request to FCM to update
* the token, and to check if the token is still valid on FCM-side.
*/
ControllerInterface.prototype.manageExistingToken = function (tokenDetails, swReg) {
var _this = this;
return this.isTokenStillValid(tokenDetails).then(function (isValid) {
if (isValid) {
var now = Date.now();
if (now < tokenDetails['createTime'] + exports.TOKEN_EXPIRATION_MILLIS) {
return tokenDetails['fcmToken'];
}
return _this.tokenManager_.createToken(_this.messagingSenderId_, registration);
else {
return _this.updateToken(tokenDetails, swReg);
}
}
else {
// If the VAPID details are updated, delete the existing token,
// and create a new one.
return _this.deleteToken(tokenDetails['fcmToken']).then(function () {
return _this.getNewToken(swReg);
});
}
});
};
/*
* Checks if the tokenDetails match the details provided in the clients.
*/
ControllerInterface.prototype.isTokenStillValid = function (tokenDetails) {
// TODO Validate rest of the details.
return this.getPublicVapidKey_().then(function (publicKey) {
if (array_buffer_to_base64_1.default(publicKey) !== tokenDetails['vapidKey']) {
return false;
}
return true;
});
};
ControllerInterface.prototype.updateToken = function (tokenDetails, swReg) {
var _this = this;
var publicVapidKey;
var updatedToken;
var subscription;
return this.getPublicVapidKey_()
.then(function (publicKey) {
publicVapidKey = publicKey;
return _this.getPushSubscription_(swReg, publicVapidKey);
})
.then(function (pushSubscription) {
subscription = pushSubscription;
return _this.iidModel_.updateToken(_this.messagingSenderId_, tokenDetails['fcmToken'], tokenDetails['fcmPushSet'], subscription, publicVapidKey);
})
.catch(function (err) {
return _this.deleteToken(tokenDetails['fcmToken']).then(function () {
throw err;
});
})
.then(function (token) {
updatedToken = token;
var allDetails = {
swScope: swReg.scope,
vapidKey: publicVapidKey,
subscription: subscription,
fcmSenderId: _this.messagingSenderId_,
fcmToken: updatedToken,
fcmPushSet: tokenDetails['fcmPushSet']
};
return _this.tokenDetailsModel_.saveTokenDetails(allDetails);
})
.then(function () {
return _this.vapidDetailsModel_.saveVapidDetails(swReg.scope, publicVapidKey);
})
.then(function () {
return updatedToken;
});
};
ControllerInterface.prototype.getNewToken = function (swReg) {
var _this = this;
var publicVapidKey;
var subscription;
var tokenDetails;
return this.getPublicVapidKey_()
.then(function (publicKey) {
publicVapidKey = publicKey;
return _this.getPushSubscription_(swReg, publicVapidKey);
})
.then(function (pushSubscription) {
subscription = pushSubscription;
return _this.iidModel_.getToken(_this.messagingSenderId_, subscription, publicVapidKey);
})
.then(function (iidTokenDetails) {
tokenDetails = iidTokenDetails;
var allDetails = {
swScope: swReg.scope,
vapidKey: publicVapidKey,
subscription: subscription,
fcmSenderId: _this.messagingSenderId_,
fcmToken: tokenDetails['token'],
fcmPushSet: tokenDetails['pushSet']
};
return _this.tokenDetailsModel_.saveTokenDetails(allDetails);
})
.then(function () {
return _this.vapidDetailsModel_.saveVapidDetails(swReg.scope, publicVapidKey);
})
.then(function () {
return tokenDetails['token'];
});
};
/**
* This method deletes tokens that the token manager looks after and then
* unregisters the push subscription if it exists.
* This method deletes tokens that the token manager looks after,
* unsubscribes the token from FCM and then unregisters the push
* subscription if it exists. It returns a promise that indicates
* whether or not the unsubscribe request was processed successfully.
* @export
* @param {string} token
* @return {Promise<void>}
*/
ControllerInterface.prototype.deleteToken = function (token) {
var _this = this;
return this.tokenManager_.deleteToken(token).then(function () {
return this.tokenDetailsModel_
.deleteToken(token)
.then(function (details) {
return _this.iidModel_.deleteToken(details['fcmSenderId'], details['fcmToken'], details['fcmPushSet']);
})
.then(function () {
return _this.getSWRegistration_()

@@ -97,2 +222,5 @@ .then(function (registration) {

};
ControllerInterface.prototype.getPublicVapidKey_ = function () {
throw this.errorFactory_.create(errors_1.default.codes.SHOULD_BE_INHERITED);
};
//

@@ -104,2 +232,5 @@ // The following methods should only be available in the window.

};
ControllerInterface.prototype.getPushSubscription_ = function (registration, publicVapidKey) {
throw this.errorFactory_.create(errors_1.default.codes.AVAILABLE_IN_WINDOW);
};
/**

@@ -114,2 +245,9 @@ * @export

* @export
* @param {!string} b64PublicKey
*/
ControllerInterface.prototype.usePublicVapidKey = function (b64PublicKey) {
throw this.errorFactory_.create(errors_1.default.codes.AVAILABLE_IN_WINDOW);
};
/**
* @export
* @param {!firebase.Observer|function(*)} nextOrObserver

@@ -155,3 +293,6 @@ * @param {function(!Error)=} optError

ControllerInterface.prototype.delete = function () {
return this.tokenManager_.closeDatabase();
return Promise.all([
this.tokenDetailsModel_.closeDatabase(),
this.vapidDetailsModel_.closeDatabase()
]);
};

@@ -166,8 +307,14 @@ /**

};
ControllerInterface.prototype.getTokenDetailsModel = function () {
return this.tokenDetailsModel_;
};
ControllerInterface.prototype.getVapidDetailsModel = function () {
return this.vapidDetailsModel_;
};
/**
* @protected
* @returns {TokenManager}
* @returns {IIDModel}
*/
ControllerInterface.prototype.getTokenManager = function () {
return this.tokenManager_;
ControllerInterface.prototype.getIIDModel = function () {
return this.iidModel_;
};

@@ -174,0 +321,0 @@ return ControllerInterface;

@@ -65,3 +65,3 @@ import ControllerInterface from './controller-interface';

*/
attemptToMessageClient_(client: any, message: any): Promise<{}>;
attemptToMessageClient_(client: any, message: any): Promise<void>;
/**

@@ -88,2 +88,7 @@ * @private

getSWRegistration_(): Promise<any>;
/**
* This will return the default VAPID key or the uint8array version of the
* public VAPID key provided by the developer.
*/
getPublicVapidKey_(): Promise<Uint8Array>;
}

@@ -30,4 +30,4 @@ /**

var errors_1 = require("../models/errors");
var fcm_details_1 = require("../models/fcm-details");
var worker_page_message_1 = require("../models/worker-page-message");
var fcm_details_1 = require("../models/fcm-details");
var FCM_MSG = 'FCM_MSG';

@@ -82,4 +82,6 @@ var SWController = /** @class */ (function (_super) {

if (notificationDetails) {
var notificationTitle = notificationDetails.title || '';
return self.registration.showNotification(notificationTitle, notificationDetails);
var notificationTitle_1 = notificationDetails.title || '';
return _this.getSWRegistration_().then(function (reg) {
return reg.showNotification(notificationTitle_1, notificationDetails);
});
}

@@ -97,32 +99,33 @@ else if (_this.bgMessageHandler_) {

var _this = this;
var promiseChain = this.getToken().then(function (token) {
if (!token) {
// We can't resubscribe if we don't have an FCM token for this scope.
throw _this.errorFactory_.create(errors_1.default.codes.NO_FCM_TOKEN_FOR_RESUBSCRIBE);
}
var tokenDetails = null;
var tokenManager = _this.getTokenManager();
return tokenManager
.getTokenDetailsFromToken(token)
.then(function (details) {
tokenDetails = details;
if (!tokenDetails) {
throw _this.errorFactory_.create(errors_1.default.codes.INVALID_SAVED_TOKEN);
}
// Attempt to get a new subscription
return self.registration.pushManager.subscribe(fcm_details_1.default.SUBSCRIPTION_OPTIONS);
var promiseChain = this.getSWRegistration_()
.then(function (registration) {
return registration.pushManager
.getSubscription()
.then(function (subscription) {
// TODO: Check if it's still valid
// TODO: If not, then update token
})
.then(function (newSubscription) {
// Send new subscription to FCM.
return tokenManager.subscribeToFCM(tokenDetails.fcmSenderId, newSubscription, tokenDetails.fcmPushSet);
})
.catch(function (err) {
// The best thing we can do is log this to the terminal so
// developers might notice the error.
return tokenManager.deleteToken(tokenDetails.fcmToken).then(function () {
throw _this.errorFactory_.create(errors_1.default.codes.UNABLE_TO_RESUBSCRIBE, {
message: err
var tokenDetailsModel = _this.getTokenDetailsModel();
return tokenDetailsModel
.getTokenDetailsFromSWScope(registration.scope)
.then(function (tokenDetails) {
if (!tokenDetails) {
// This should rarely occure, but could if indexedDB
// is corrupted or wiped
throw err;
}
// Attempt to delete the token if we know it's bad
return _this.deleteToken(tokenDetails['fcmToken']).then(function () {
throw err;
});
});
});
})
.catch(function (err) {
throw _this.errorFactory_.create(errors_1.default.codes.UNABLE_TO_RESUBSCRIBE, {
message: err
});
});

@@ -146,2 +149,6 @@ event.waitUntil(promiseChain);

var msgPayload = event.notification.data[FCM_MSG];
if (!msgPayload['notification']) {
// Nothing to do.
return;
}
var clickAction = msgPayload['notification']['click_action'];

@@ -158,3 +165,3 @@ if (!clickAction) {

}
return windowClient;
return windowClient.focus();
})

@@ -215,3 +222,3 @@ .then(function (windowClient) {

SWController.prototype.setBackgroundMessageHandler = function (callback) {
if (callback && typeof callback !== 'function') {
if (!callback || typeof callback !== 'function') {
throw this.errorFactory_.create(errors_1.default.codes.BG_HANDLER_FUNCTION_EXPECTED);

@@ -230,3 +237,3 @@ }

// This at least handles whether to include trailing slashes or not
var parsedURL = new URL(url).href;
var parsedURL = new URL(url, self.location).href;
return self.clients

@@ -240,3 +247,3 @@ .matchAll({

for (var i = 0; i < clientList.length; i++) {
var parsedClientUrl = new URL(clientList[i].url).href;
var parsedClientUrl = new URL(clientList[i].url, self.location).href;
if (parsedClientUrl === parsedURL) {

@@ -248,5 +255,5 @@ suitableClient = clientList[i];

if (suitableClient) {
suitableClient.focus();
return suitableClient;
}
return null;
});

@@ -264,10 +271,9 @@ };

SWController.prototype.attemptToMessageClient_ = function (client, message) {
var _this = this;
return new Promise(function (resolve, reject) {
if (!client) {
return reject(_this.errorFactory_.create(errors_1.default.codes.NO_WINDOW_CLIENT_TO_MSG));
}
client.postMessage(message);
resolve();
});
// NOTE: This returns a promise in case this API is abstracted later on to
// do additional work
if (!client) {
return Promise.reject(this.errorFactory_.create(errors_1.default.codes.NO_WINDOW_CLIENT_TO_MSG));
}
client.postMessage(message);
return Promise.resolve();
};

@@ -319,2 +325,19 @@ /**

};
/**
* This will return the default VAPID key or the uint8array version of the
* public VAPID key provided by the developer.
*/
SWController.prototype.getPublicVapidKey_ = function () {
var _this = this;
return this.getSWRegistration_()
.then(function (swReg) {
return _this.getVapidDetailsModel().getVapidFromSWScope(swReg.scope);
})
.then(function (vapidKeyFromDatabase) {
if (vapidKeyFromDatabase === null) {
return fcm_details_1.default.DEFAULT_PUBLIC_VAPID_KEY;
}
return vapidKeyFromDatabase;
});
};
return SWController;

@@ -321,0 +344,0 @@ }(controller_interface_1.default));

@@ -5,2 +5,3 @@ import { FirebaseMessaging } from '@firebase/messaging-types';

private registrationToUse_;
private publicVapidKeyToUse_;
private manifestCheckPromise_;

@@ -50,3 +51,10 @@ private messageObserver_;

/**
* This method allows a developer to override the default vapid key
* and instead use a custom VAPID public key.
* @export
* @param {!string} publicKey A URL safe base64 encoded string.
*/
usePublicVapidKey(publicKey: any): void;
/**
* @export
* @param {!firebase.Observer|function(*)} nextOrObserver An observer object

@@ -60,3 +68,3 @@ * or a function triggered on message.

*/
onMessage(nextOrObserver: any, optError: any, optCompleted: any): () => void;
onMessage(nextOrObserver: any, optError?: any, optCompleted?: any): () => void;
/**

@@ -91,2 +99,15 @@ * @export

/**
* This will return the default VAPID key or the uint8array version of the public VAPID key
* provided by the developer.
* @private
*/
getPublicVapidKey_(): Promise<Uint8Array>;
/**
* Gets a PushSubscription for the current user.
* @private
* @param {ServiceWorkerRegistration} registration
* @return {Promise<PushSubscription>}
*/
getPushSubscription_(swRegistration: any, publicVapidKey: any): any;
/**
* This method will set up a message listener to handle

@@ -93,0 +114,0 @@ * events from the service worker that should trigger

@@ -33,2 +33,4 @@ /**

var notification_permission_1 = require("../models/notification-permission");
var fcm_details_1 = require("../models/fcm-details");
var base64_to_array_buffer_1 = require("../helpers/base64-to-array-buffer");
var util_1 = require("@firebase/util");

@@ -51,2 +53,32 @@ var WindowController = /** @class */ (function (_super) {

});
/**
* @private
* @type {ServiceWorkerRegistration}
*/
_this.registrationToUse_;
/**
* @private
* @type {Promise}
*/
_this.manifestCheckPromise_;
/**
* @private
* @type {firebase.Observer}
*/
_this.messageObserver_ = null;
/**
* @private {!firebase.Subscribe} The subscribe function to the onMessage
* observer.
*/
_this.onMessage_ = util_1.createSubscribe(function (observer) {
_this.messageObserver_ = observer;
});
/**
* @private
* @type {firebase.Observer}
*/
_this.tokenRefreshObserver_ = null;
_this.onTokenRefresh_ = util_1.createSubscribe(function (observer) {
_this.tokenRefreshObserver_ = observer;
});
_this.setupSWMessageListener_();

@@ -140,9 +172,3 @@ return _this;

// browsers stop support callbacks for promised version
var permissionPromise = Notification.requestPermission(function (result) {
if (permissionPromise) {
// Let the promise manage this
return;
}
managePermissionResult(result);
});
var permissionPromise = Notification.requestPermission(managePermissionResult);
if (permissionPromise) {

@@ -171,3 +197,22 @@ // Prefer the promise version as it's the future API.

/**
* This method allows a developer to override the default vapid key
* and instead use a custom VAPID public key.
* @export
* @param {!string} publicKey A URL safe base64 encoded string.
*/
WindowController.prototype.usePublicVapidKey = function (publicKey) {
if (typeof publicKey !== 'string') {
throw this.errorFactory_.create(errors_1.default.codes.INVALID_PUBLIC_VAPID_KEY);
}
if (typeof this.publicVapidKeyToUse_ !== 'undefined') {
throw this.errorFactory_.create(errors_1.default.codes.USE_PUBLIC_KEY_BEFORE_GET_TOKEN);
}
var parsedKey = base64_to_array_buffer_1.default(publicKey);
if (parsedKey.length !== 65) {
throw this.errorFactory_.create(errors_1.default.codes.PUBLIC_KEY_DECRYPTION_FAILED);
}
this.publicVapidKeyToUse_ = parsedKey;
};
/**
* @export
* @param {!firebase.Observer|function(*)} nextOrObserver An observer object

@@ -276,2 +321,33 @@ * or a function triggered on message.

/**
* This will return the default VAPID key or the uint8array version of the public VAPID key
* provided by the developer.
* @private
*/
WindowController.prototype.getPublicVapidKey_ = function () {
if (this.publicVapidKeyToUse_) {
return Promise.resolve(this.publicVapidKeyToUse_);
}
return Promise.resolve(fcm_details_1.default.DEFAULT_PUBLIC_VAPID_KEY);
};
/**
* Gets a PushSubscription for the current user.
* @private
* @param {ServiceWorkerRegistration} registration
* @return {Promise<PushSubscription>}
*/
WindowController.prototype.getPushSubscription_ = function (swRegistration, publicVapidKey) {
// Check for existing subscription first
var subscription;
var fcmTokenDetails;
return swRegistration.pushManager.getSubscription().then(function (subscription) {
if (subscription) {
return subscription;
}
return swRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: publicVapidKey
});
});
};
/**
* This method will set up a message listener to handle

@@ -298,3 +374,5 @@ * events from the service worker that should trigger

var pushMessage = workerPageMessage[worker_page_message_1.default.PARAMS.DATA];
_this.messageObserver_.next(pushMessage);
if (_this.messageObserver_) {
_this.messageObserver_.next(pushMessage);
}
break;

@@ -301,0 +379,0 @@ default:

import { ErrorFactory } from '@firebase/util';
export default class DBInterface {
private dbName_;
private DB_NAME_;
private dbVersion_;

@@ -5,0 +5,0 @@ private openDbPromise_;

@@ -27,3 +27,3 @@ /**

this.errorFactory_ = new util_1.ErrorFactory('messaging', 'Messaging', errors_1.default.map);
this.dbName_ = dbName;
this.DB_NAME_ = dbName;
this.dbVersion_ = dbVersion;

@@ -44,3 +44,3 @@ this.openDbPromise_ = null;

this.openDbPromise_ = new Promise(function (resolve, reject) {
var request = indexedDB.open(_this.dbName_, _this.dbVersion_);
var request = indexedDB.open(_this.DB_NAME_, _this.dbVersion_);
request.onerror = function (event) {

@@ -53,4 +53,11 @@ reject(event.target.error);

request.onupgradeneeded = function (event) {
var db = event.target.result;
_this.onDBUpgrade(db);
try {
var db = event.target.result;
_this.onDBUpgrade(db);
}
catch (err) {
// close the database as it can't be used.
db.close();
reject(err);
}
};

@@ -57,0 +64,0 @@ });

@@ -20,2 +20,5 @@ declare const _default: {

TOKEN_SUBSCRIBE_NO_PUSH_SET: string;
TOKEN_UNSUBSCRIBE_FAILED: string;
TOKEN_UPDATE_FAILED: string;
TOKEN_UPDATE_NO_TOKEN: string;
USE_SW_BEFORE_GET_TOKEN: string;

@@ -37,2 +40,5 @@ INVALID_DELETE_TOKEN: string;

FAILED_DELETE_VAPID_KEY: string;
INVALID_PUBLIC_VAPID_KEY: string;
USE_PUBLIC_KEY_BEFORE_GET_TOKEN: string;
PUBLIC_KEY_DECRYPTION_FAILED: string;
};

@@ -39,0 +45,0 @@ map: {

@@ -36,2 +36,5 @@ /**

TOKEN_SUBSCRIBE_NO_PUSH_SET: 'token-subscribe-no-push-set',
TOKEN_UNSUBSCRIBE_FAILED: 'token-unsubscribe-failed',
TOKEN_UPDATE_FAILED: 'token-update-failed',
TOKEN_UPDATE_NO_TOKEN: 'token-update-no-token',
USE_SW_BEFORE_GET_TOKEN: 'use-sw-before-get-token',

@@ -52,3 +55,6 @@ INVALID_DELETE_TOKEN: 'invalid-delete-token',

BAD_PUSH_SET: 'bad-push-set',
FAILED_DELETE_VAPID_KEY: 'failed-delete-vapid-key'
FAILED_DELETE_VAPID_KEY: 'failed-delete-vapid-key',
INVALID_PUBLIC_VAPID_KEY: 'invalid-public-vapid-key',
USE_PUBLIC_KEY_BEFORE_GET_TOKEN: 'use-public-key-before-get-token',
PUBLIC_KEY_DECRYPTION_FAILED: 'public-vapid-key-decryption-failed'
};

@@ -76,2 +82,5 @@ var ERROR_MAP = (_a = {},

_a[CODES.TOKEN_SUBSCRIBE_NO_PUSH_SET] = 'FCM returned an invalid response ' + 'when getting an FCM token.',
_a[CODES.TOKEN_UNSUBSCRIBE_FAILED] = 'A problem occured while unsubscribing the ' + 'user from FCM: {$message}',
_a[CODES.TOKEN_UPDATE_FAILED] = 'A problem occured while updating the ' + 'user from FCM: {$message}',
_a[CODES.TOKEN_UPDATE_NO_TOKEN] = 'FCM returned no token when updating ' + 'the user to push.',
_a[CODES.USE_SW_BEFORE_GET_TOKEN] = 'You must call useServiceWorker() before ' +

@@ -100,3 +109,3 @@ 'calling getToken() to ensure your service worker is used.',

'least one character.',
_a[CODES.BAD_VAPID_KEY] = 'The public VAPID key must be a string with at ' + 'least one character.',
_a[CODES.BAD_VAPID_KEY] = 'The public VAPID key is not a Uint8Array with 65 bytes.',
_a[CODES.BAD_SUBSCRIPTION] = 'The subscription must be a valid ' + 'PushSubscription.',

@@ -108,2 +117,4 @@ _a[CODES.BAD_TOKEN] = 'The FCM Token used for storage / lookup was not ' +

_a[CODES.FAILED_DELETE_VAPID_KEY] = 'The VAPID key could not be deleted.',
_a[CODES.INVALID_PUBLIC_VAPID_KEY] = 'The public VAPID key must be a string.',
_a[CODES.PUBLIC_KEY_DECRYPTION_FAILED] = 'The public VAPID key did not equal ' + '65 bytes when decrypted.',
_a);

@@ -110,0 +121,0 @@ exports.default = {

declare const _default: {
ENDPOINT: string;
APPLICATION_SERVER_KEY: number[];
SUBSCRIPTION_OPTIONS: {
DEFAULT_PUBLIC_VAPID_KEY: Uint8Array;
SUBSCRIPTION_DETAILS: {
userVisibleOnly: boolean;
applicationServerKey: Uint8Array;
};
ENDPOINT: string;
};
export default _default;

@@ -18,3 +18,3 @@ /**

Object.defineProperty(exports, "__esModule", { value: true });
var FCM_APPLICATION_SERVER_KEY = [
var DEFAULT_PUBLIC_VAPID_KEY = new Uint8Array([
0x04,

@@ -85,13 +85,14 @@ 0x33,

0x6e
];
]);
var SUBSCRIPTION_DETAILS = {
userVisibleOnly: true,
applicationServerKey: new Uint8Array(FCM_APPLICATION_SERVER_KEY)
applicationServerKey: DEFAULT_PUBLIC_VAPID_KEY
};
exports.default = {
ENDPOINT: 'https://fcm.googleapis.com',
APPLICATION_SERVER_KEY: FCM_APPLICATION_SERVER_KEY,
SUBSCRIPTION_OPTIONS: SUBSCRIPTION_DETAILS
DEFAULT_PUBLIC_VAPID_KEY: DEFAULT_PUBLIC_VAPID_KEY,
SUBSCRIPTION_DETAILS: SUBSCRIPTION_DETAILS,
ENDPOINT: 'https://fcm.googleapis.com'
// ENDPOINT: 'https://jmt17.google.com'
};
//# sourceMappingURL=fcm-details.js.map
import DBInterface from './db-interface';
export default class TokenDetailsModel extends DBInterface {
constructor();
static readonly dbName: string;
static readonly DB_NAME: string;
/**

@@ -51,7 +51,6 @@ * @override

* method for deleting at a later date.
* @param {string} token Token to be deleted
* @return {Promise<Object>} Resolves once the FCM token details have been
* deleted and returns the deleted details.
*/
deleteToken(token: any): Promise<{}>;
deleteToken(token: string): Promise<{}>;
}

@@ -50,5 +50,5 @@ /**

function TokenDetailsModel() {
return _super.call(this, TokenDetailsModel.dbName, DB_VERSION) || this;
return _super.call(this, TokenDetailsModel.DB_NAME, DB_VERSION) || this;
}
Object.defineProperty(TokenDetailsModel, "dbName", {
Object.defineProperty(TokenDetailsModel, "DB_NAME", {
get: function () {

@@ -95,3 +95,4 @@ return 'fcm_token_details_db';

if (input.vapidKey) {
if (typeof input.vapidKey !== 'string' || input.vapidKey.length === 0) {
if (!(input.vapidKey instanceof Uint8Array) ||
input.vapidKey.length !== 65) {
return Promise.reject(this.errorFactory_.create(errors_1.default.codes.BAD_VAPID_KEY));

@@ -229,3 +230,3 @@ }

swScope: swScope,
vapidKey: vapidKey,
vapidKey: array_buffer_to_base64_1.default(vapidKey),
endpoint: subscription.endpoint,

@@ -236,3 +237,4 @@ auth: array_buffer_to_base64_1.default(subscription['getKey']('auth')),

fcmToken: fcmToken,
fcmPushSet: fcmPushSet
fcmPushSet: fcmPushSet,
createTime: Date.now()
};

@@ -256,3 +258,2 @@ return new Promise(function (resolve, reject) {

* method for deleting at a later date.
* @param {string} token Token to be deleted
* @return {Promise<Object>} Resolves once the FCM token details have been

@@ -259,0 +260,0 @@ * deleted and returns the deleted details.

import DBInterface from './db-interface';
export default class VapidDetailsModel extends DBInterface {
constructor();
static readonly dbName: string;
static readonly DB_NAME: string;
/**

@@ -13,22 +13,14 @@ * @override

* in indexedDB.
* @param {string} swScope
* @return {Promise<string>} The vapid key associated with that scope.
*/
getVapidFromSWScope(swScope: any): Promise<{}>;
getVapidFromSWScope(swScope: string): Promise<Uint8Array>;
/**
* Save a vapid key against a swScope for later date.
* @param {string} swScope The service worker scope to be associated with
* this push subscription.
* @param {string} vapidKey The public vapid key to be associated with
* the swScope.
* @return {Promise<void>}
*/
saveVapidDetails(swScope: any, vapidKey: any): Promise<{}>;
saveVapidDetails(swScope: string, vapidKey: Uint8Array): Promise<void>;
/**
* This method deletes details of the current FCM VAPID key for a SW scope.
* @param {string} swScope Scope to be deleted
* @return {Promise<string>} Resolves once the scope / vapid details have been
* deleted and returns the deleted vapid key.
* Resolves once the scope/vapid details have been deleted and returns the
* deleted vapid key.
*/
deleteVapidDetails(swScope: any): Promise<{}>;
deleteVapidDetails(swScope: string): Promise<Uint8Array>;
}

@@ -32,8 +32,9 @@ /**

var DB_VERSION = 1;
var UNCOMPRESSED_PUBLIC_KEY_SIZE = 65;
var VapidDetailsModel = /** @class */ (function (_super) {
__extends(VapidDetailsModel, _super);
function VapidDetailsModel() {
return _super.call(this, VapidDetailsModel.dbName, DB_VERSION) || this;
return _super.call(this, VapidDetailsModel.DB_NAME, DB_VERSION) || this;
}
Object.defineProperty(VapidDetailsModel, "dbName", {
Object.defineProperty(VapidDetailsModel, "DB_NAME", {
get: function () {

@@ -57,4 +58,2 @@ return 'fcm_vapid_details_db';

* in indexedDB.
* @param {string} swScope
* @return {Promise<string>} The vapid key associated with that scope.
*/

@@ -70,7 +69,7 @@ VapidDetailsModel.prototype.getVapidFromSWScope = function (swScope) {

var scopeRequest = objectStore.get(swScope);
scopeRequest.onerror = function (event) {
reject(event.target.error);
scopeRequest.onerror = function () {
reject(scopeRequest.error);
};
scopeRequest.onsuccess = function (event) {
var result = event.target.result;
scopeRequest.onsuccess = function () {
var result = scopeRequest.result;
var vapidKey = null;

@@ -87,7 +86,2 @@ if (result) {

* Save a vapid key against a swScope for later date.
* @param {string} swScope The service worker scope to be associated with
* this push subscription.
* @param {string} vapidKey The public vapid key to be associated with
* the swScope.
* @return {Promise<void>}
*/

@@ -99,3 +93,3 @@ VapidDetailsModel.prototype.saveVapidDetails = function (swScope, vapidKey) {

}
if (typeof vapidKey !== 'string' || vapidKey.length === 0) {
if (vapidKey === null || vapidKey.length !== UNCOMPRESSED_PUBLIC_KEY_SIZE) {
return Promise.reject(this.errorFactory_.create(errors_1.default.codes.BAD_VAPID_KEY));

@@ -112,6 +106,6 @@ }

var request = objectStore.put(details);
request.onerror = function (event) {
reject(event.target.error);
request.onerror = function () {
reject(request.error);
};
request.onsuccess = function (event) {
request.onsuccess = function () {
resolve();

@@ -124,5 +118,4 @@ };

* This method deletes details of the current FCM VAPID key for a SW scope.
* @param {string} swScope Scope to be deleted
* @return {Promise<string>} Resolves once the scope / vapid details have been
* deleted and returns the deleted vapid key.
* Resolves once the scope/vapid details have been deleted and returns the
* deleted vapid key.
*/

@@ -140,7 +133,7 @@ VapidDetailsModel.prototype.deleteVapidDetails = function (swScope) {

var request = objectStore.delete(swScope);
request.onerror = function (event) {
reject(event.target.error);
request.onerror = function () {
reject(request.error);
};
request.onsuccess = function (event) {
if (event.target.result === 0) {
request.onsuccess = function () {
if (request.result === 0) {
reject(_this.errorFactory_.create(errors_1.default.codes.FAILED_DELETE_VAPID_KEY));

@@ -147,0 +140,0 @@ return;

@@ -1,2 +0,5 @@

import TokenManager from '../models/token-manager';
import TokenDetailsModel from '../models/token-details-model';
import VapidDetailsModel from '../models/vapid-details-model';
import IIDModel from '../models/iid-model';
export declare const TOKEN_EXPIRATION_MILLIS: number;
export default class ControllerInterface {

@@ -7,3 +10,5 @@ app: any;

private messagingSenderId_;
private tokenManager_;
private tokenDetailsModel_;
private vapidDetailsModel_;
private iidModel_;
/**

@@ -16,16 +21,29 @@ * An interface of the Messaging Service API

* @export
* @return {Promise<string> | Promise<null>} Returns a promise that
* resolves to an FCM token.
*/
getToken(): Promise<any>;
getToken(): Promise<string | null>;
/**
* This method deletes tokens that the token manager looks after and then
* unregisters the push subscription if it exists.
* manageExistingToken is triggered if there's an existing FCM token in the
* database and it can take 3 different actions:
* 1) Retrieve the existing FCM token from the database.
* 2) If VAPID details have changed: Delete the existing token and create a
* new one with the new VAPID key.
* 3) If the database cache is invalidated: Send a request to FCM to update
* the token, and to check if the token is still valid on FCM-side.
*/
private manageExistingToken(tokenDetails, swReg);
private isTokenStillValid(tokenDetails);
private updateToken(tokenDetails, swReg);
private getNewToken(swReg);
/**
* This method deletes tokens that the token manager looks after,
* unsubscribes the token from FCM and then unregisters the push
* subscription if it exists. It returns a promise that indicates
* whether or not the unsubscribe request was processed successfully.
* @export
* @param {string} token
* @return {Promise<void>}
*/
deleteToken(token: any): Promise<boolean>;
deleteToken(token: string): Promise<Boolean>;
getSWRegistration_(): Promise<ServiceWorkerRegistration>;
getPublicVapidKey_(): Promise<Uint8Array>;
requestPermission(): void;
getPushSubscription_(registration: any, publicVapidKey: any): Promise<PushSubscription>;
/**

@@ -38,2 +56,7 @@ * @export

* @export
* @param {!string} b64PublicKey
*/
usePublicVapidKey(b64PublicKey: any): void;
/**
* @export
* @param {!firebase.Observer|function(*)} nextOrObserver

@@ -65,3 +88,3 @@ * @param {function(!Error)=} optError

*/
delete(): Promise<void>;
delete(): Promise<[void, void]>;
/**

@@ -73,7 +96,9 @@ * Returns the current Notification Permission state.

getNotificationPermission_(): any;
getTokenDetailsModel(): TokenDetailsModel;
getVapidDetailsModel(): VapidDetailsModel;
/**
* @protected
* @returns {TokenManager}
* @returns {IIDModel}
*/
getTokenManager(): TokenManager;
getIIDModel(): IIDModel;
}

@@ -19,5 +19,10 @@ /**

import Errors from '../models/errors';
import TokenManager from '../models/token-manager';
import TokenDetailsModel from '../models/token-details-model';
import VapidDetailsModel from '../models/vapid-details-model';
import NOTIFICATION_PERMISSION from '../models/notification-permission';
import IIDModel from '../models/iid-model';
import arrayBufferToBase64 from '../helpers/array-buffer-to-base64';
var SENDER_ID_OPTION_NAME = 'messagingSenderId';
// Database cache should be invalidated once a week.
export var TOKEN_EXPIRATION_MILLIS = 7 * 24 * 60 * 60 * 1000; // 7 days
var ControllerInterface = /** @class */ (function () {

@@ -36,11 +41,11 @@ /**

this.messagingSenderId_ = app.options[SENDER_ID_OPTION_NAME];
this.tokenManager_ = new TokenManager();
this.tokenDetailsModel_ = new TokenDetailsModel();
this.vapidDetailsModel_ = new VapidDetailsModel();
this.iidModel_ = new IIDModel();
this.app = app;
this.INTERNAL = {};
this.INTERNAL.delete = function () { return _this.delete; };
this.INTERNAL.delete = function () { return _this.delete(); };
}
/**
* @export
* @return {Promise<string> | Promise<null>} Returns a promise that
* resolves to an FCM token.
*/

@@ -58,23 +63,143 @@ ControllerInterface.prototype.getToken = function () {

}
return this.getSWRegistration_().then(function (registration) {
return _this.tokenManager_
.getSavedToken(_this.messagingSenderId_, registration)
.then(function (token) {
if (token) {
return token;
var swReg;
return this.getSWRegistration_()
.then(function (reg) {
swReg = reg;
return _this.tokenDetailsModel_.getTokenDetailsFromSWScope(swReg.scope);
})
.then(function (tokenDetails) {
if (tokenDetails) {
return _this.manageExistingToken(tokenDetails, swReg);
}
return _this.getNewToken(swReg);
});
};
/**
* manageExistingToken is triggered if there's an existing FCM token in the
* database and it can take 3 different actions:
* 1) Retrieve the existing FCM token from the database.
* 2) If VAPID details have changed: Delete the existing token and create a
* new one with the new VAPID key.
* 3) If the database cache is invalidated: Send a request to FCM to update
* the token, and to check if the token is still valid on FCM-side.
*/
ControllerInterface.prototype.manageExistingToken = function (tokenDetails, swReg) {
var _this = this;
return this.isTokenStillValid(tokenDetails).then(function (isValid) {
if (isValid) {
var now = Date.now();
if (now < tokenDetails['createTime'] + TOKEN_EXPIRATION_MILLIS) {
return tokenDetails['fcmToken'];
}
return _this.tokenManager_.createToken(_this.messagingSenderId_, registration);
else {
return _this.updateToken(tokenDetails, swReg);
}
}
else {
// If the VAPID details are updated, delete the existing token,
// and create a new one.
return _this.deleteToken(tokenDetails['fcmToken']).then(function () {
return _this.getNewToken(swReg);
});
}
});
};
/*
* Checks if the tokenDetails match the details provided in the clients.
*/
ControllerInterface.prototype.isTokenStillValid = function (tokenDetails) {
// TODO Validate rest of the details.
return this.getPublicVapidKey_().then(function (publicKey) {
if (arrayBufferToBase64(publicKey) !== tokenDetails['vapidKey']) {
return false;
}
return true;
});
};
ControllerInterface.prototype.updateToken = function (tokenDetails, swReg) {
var _this = this;
var publicVapidKey;
var updatedToken;
var subscription;
return this.getPublicVapidKey_()
.then(function (publicKey) {
publicVapidKey = publicKey;
return _this.getPushSubscription_(swReg, publicVapidKey);
})
.then(function (pushSubscription) {
subscription = pushSubscription;
return _this.iidModel_.updateToken(_this.messagingSenderId_, tokenDetails['fcmToken'], tokenDetails['fcmPushSet'], subscription, publicVapidKey);
})
.catch(function (err) {
return _this.deleteToken(tokenDetails['fcmToken']).then(function () {
throw err;
});
})
.then(function (token) {
updatedToken = token;
var allDetails = {
swScope: swReg.scope,
vapidKey: publicVapidKey,
subscription: subscription,
fcmSenderId: _this.messagingSenderId_,
fcmToken: updatedToken,
fcmPushSet: tokenDetails['fcmPushSet']
};
return _this.tokenDetailsModel_.saveTokenDetails(allDetails);
})
.then(function () {
return _this.vapidDetailsModel_.saveVapidDetails(swReg.scope, publicVapidKey);
})
.then(function () {
return updatedToken;
});
};
ControllerInterface.prototype.getNewToken = function (swReg) {
var _this = this;
var publicVapidKey;
var subscription;
var tokenDetails;
return this.getPublicVapidKey_()
.then(function (publicKey) {
publicVapidKey = publicKey;
return _this.getPushSubscription_(swReg, publicVapidKey);
})
.then(function (pushSubscription) {
subscription = pushSubscription;
return _this.iidModel_.getToken(_this.messagingSenderId_, subscription, publicVapidKey);
})
.then(function (iidTokenDetails) {
tokenDetails = iidTokenDetails;
var allDetails = {
swScope: swReg.scope,
vapidKey: publicVapidKey,
subscription: subscription,
fcmSenderId: _this.messagingSenderId_,
fcmToken: tokenDetails['token'],
fcmPushSet: tokenDetails['pushSet']
};
return _this.tokenDetailsModel_.saveTokenDetails(allDetails);
})
.then(function () {
return _this.vapidDetailsModel_.saveVapidDetails(swReg.scope, publicVapidKey);
})
.then(function () {
return tokenDetails['token'];
});
};
/**
* This method deletes tokens that the token manager looks after and then
* unregisters the push subscription if it exists.
* This method deletes tokens that the token manager looks after,
* unsubscribes the token from FCM and then unregisters the push
* subscription if it exists. It returns a promise that indicates
* whether or not the unsubscribe request was processed successfully.
* @export
* @param {string} token
* @return {Promise<void>}
*/
ControllerInterface.prototype.deleteToken = function (token) {
var _this = this;
return this.tokenManager_.deleteToken(token).then(function () {
return this.tokenDetailsModel_
.deleteToken(token)
.then(function (details) {
return _this.iidModel_.deleteToken(details['fcmSenderId'], details['fcmToken'], details['fcmPushSet']);
})
.then(function () {
return _this.getSWRegistration_()

@@ -96,2 +221,5 @@ .then(function (registration) {

};
ControllerInterface.prototype.getPublicVapidKey_ = function () {
throw this.errorFactory_.create(Errors.codes.SHOULD_BE_INHERITED);
};
//

@@ -103,2 +231,5 @@ // The following methods should only be available in the window.

};
ControllerInterface.prototype.getPushSubscription_ = function (registration, publicVapidKey) {
throw this.errorFactory_.create(Errors.codes.AVAILABLE_IN_WINDOW);
};
/**

@@ -113,2 +244,9 @@ * @export

* @export
* @param {!string} b64PublicKey
*/
ControllerInterface.prototype.usePublicVapidKey = function (b64PublicKey) {
throw this.errorFactory_.create(Errors.codes.AVAILABLE_IN_WINDOW);
};
/**
* @export
* @param {!firebase.Observer|function(*)} nextOrObserver

@@ -154,3 +292,6 @@ * @param {function(!Error)=} optError

ControllerInterface.prototype.delete = function () {
return this.tokenManager_.closeDatabase();
return Promise.all([
this.tokenDetailsModel_.closeDatabase(),
this.vapidDetailsModel_.closeDatabase()
]);
};

@@ -165,8 +306,14 @@ /**

};
ControllerInterface.prototype.getTokenDetailsModel = function () {
return this.tokenDetailsModel_;
};
ControllerInterface.prototype.getVapidDetailsModel = function () {
return this.vapidDetailsModel_;
};
/**
* @protected
* @returns {TokenManager}
* @returns {IIDModel}
*/
ControllerInterface.prototype.getTokenManager = function () {
return this.tokenManager_;
ControllerInterface.prototype.getIIDModel = function () {
return this.iidModel_;
};

@@ -173,0 +320,0 @@ return ControllerInterface;

@@ -65,3 +65,3 @@ import ControllerInterface from './controller-interface';

*/
attemptToMessageClient_(client: any, message: any): Promise<{}>;
attemptToMessageClient_(client: any, message: any): Promise<void>;
/**

@@ -88,2 +88,7 @@ * @private

getSWRegistration_(): Promise<any>;
/**
* This will return the default VAPID key or the uint8array version of the
* public VAPID key provided by the developer.
*/
getPublicVapidKey_(): Promise<Uint8Array>;
}

@@ -29,4 +29,4 @@ /**

import Errors from '../models/errors';
import FCMDetails from '../models/fcm-details';
import WorkerPageMessage from '../models/worker-page-message';
import FCMDetails from '../models/fcm-details';
var FCM_MSG = 'FCM_MSG';

@@ -81,4 +81,6 @@ var SWController = /** @class */ (function (_super) {

if (notificationDetails) {
var notificationTitle = notificationDetails.title || '';
return self.registration.showNotification(notificationTitle, notificationDetails);
var notificationTitle_1 = notificationDetails.title || '';
return _this.getSWRegistration_().then(function (reg) {
return reg.showNotification(notificationTitle_1, notificationDetails);
});
}

@@ -96,32 +98,33 @@ else if (_this.bgMessageHandler_) {

var _this = this;
var promiseChain = this.getToken().then(function (token) {
if (!token) {
// We can't resubscribe if we don't have an FCM token for this scope.
throw _this.errorFactory_.create(Errors.codes.NO_FCM_TOKEN_FOR_RESUBSCRIBE);
}
var tokenDetails = null;
var tokenManager = _this.getTokenManager();
return tokenManager
.getTokenDetailsFromToken(token)
.then(function (details) {
tokenDetails = details;
if (!tokenDetails) {
throw _this.errorFactory_.create(Errors.codes.INVALID_SAVED_TOKEN);
}
// Attempt to get a new subscription
return self.registration.pushManager.subscribe(FCMDetails.SUBSCRIPTION_OPTIONS);
var promiseChain = this.getSWRegistration_()
.then(function (registration) {
return registration.pushManager
.getSubscription()
.then(function (subscription) {
// TODO: Check if it's still valid
// TODO: If not, then update token
})
.then(function (newSubscription) {
// Send new subscription to FCM.
return tokenManager.subscribeToFCM(tokenDetails.fcmSenderId, newSubscription, tokenDetails.fcmPushSet);
})
.catch(function (err) {
// The best thing we can do is log this to the terminal so
// developers might notice the error.
return tokenManager.deleteToken(tokenDetails.fcmToken).then(function () {
throw _this.errorFactory_.create(Errors.codes.UNABLE_TO_RESUBSCRIBE, {
message: err
var tokenDetailsModel = _this.getTokenDetailsModel();
return tokenDetailsModel
.getTokenDetailsFromSWScope(registration.scope)
.then(function (tokenDetails) {
if (!tokenDetails) {
// This should rarely occure, but could if indexedDB
// is corrupted or wiped
throw err;
}
// Attempt to delete the token if we know it's bad
return _this.deleteToken(tokenDetails['fcmToken']).then(function () {
throw err;
});
});
});
})
.catch(function (err) {
throw _this.errorFactory_.create(Errors.codes.UNABLE_TO_RESUBSCRIBE, {
message: err
});
});

@@ -145,2 +148,6 @@ event.waitUntil(promiseChain);

var msgPayload = event.notification.data[FCM_MSG];
if (!msgPayload['notification']) {
// Nothing to do.
return;
}
var clickAction = msgPayload['notification']['click_action'];

@@ -157,3 +164,3 @@ if (!clickAction) {

}
return windowClient;
return windowClient.focus();
})

@@ -214,3 +221,3 @@ .then(function (windowClient) {

SWController.prototype.setBackgroundMessageHandler = function (callback) {
if (callback && typeof callback !== 'function') {
if (!callback || typeof callback !== 'function') {
throw this.errorFactory_.create(Errors.codes.BG_HANDLER_FUNCTION_EXPECTED);

@@ -229,3 +236,3 @@ }

// This at least handles whether to include trailing slashes or not
var parsedURL = new URL(url).href;
var parsedURL = new URL(url, self.location).href;
return self.clients

@@ -239,3 +246,3 @@ .matchAll({

for (var i = 0; i < clientList.length; i++) {
var parsedClientUrl = new URL(clientList[i].url).href;
var parsedClientUrl = new URL(clientList[i].url, self.location).href;
if (parsedClientUrl === parsedURL) {

@@ -247,5 +254,5 @@ suitableClient = clientList[i];

if (suitableClient) {
suitableClient.focus();
return suitableClient;
}
return null;
});

@@ -263,10 +270,9 @@ };

SWController.prototype.attemptToMessageClient_ = function (client, message) {
var _this = this;
return new Promise(function (resolve, reject) {
if (!client) {
return reject(_this.errorFactory_.create(Errors.codes.NO_WINDOW_CLIENT_TO_MSG));
}
client.postMessage(message);
resolve();
});
// NOTE: This returns a promise in case this API is abstracted later on to
// do additional work
if (!client) {
return Promise.reject(this.errorFactory_.create(Errors.codes.NO_WINDOW_CLIENT_TO_MSG));
}
client.postMessage(message);
return Promise.resolve();
};

@@ -318,2 +324,19 @@ /**

};
/**
* This will return the default VAPID key or the uint8array version of the
* public VAPID key provided by the developer.
*/
SWController.prototype.getPublicVapidKey_ = function () {
var _this = this;
return this.getSWRegistration_()
.then(function (swReg) {
return _this.getVapidDetailsModel().getVapidFromSWScope(swReg.scope);
})
.then(function (vapidKeyFromDatabase) {
if (vapidKeyFromDatabase === null) {
return FCMDetails.DEFAULT_PUBLIC_VAPID_KEY;
}
return vapidKeyFromDatabase;
});
};
return SWController;

@@ -320,0 +343,0 @@ }(ControllerInterface));

@@ -5,2 +5,3 @@ import { FirebaseMessaging } from '@firebase/messaging-types';

private registrationToUse_;
private publicVapidKeyToUse_;
private manifestCheckPromise_;

@@ -50,3 +51,10 @@ private messageObserver_;

/**
* This method allows a developer to override the default vapid key
* and instead use a custom VAPID public key.
* @export
* @param {!string} publicKey A URL safe base64 encoded string.
*/
usePublicVapidKey(publicKey: any): void;
/**
* @export
* @param {!firebase.Observer|function(*)} nextOrObserver An observer object

@@ -60,3 +68,3 @@ * or a function triggered on message.

*/
onMessage(nextOrObserver: any, optError: any, optCompleted: any): () => void;
onMessage(nextOrObserver: any, optError?: any, optCompleted?: any): () => void;
/**

@@ -91,2 +99,15 @@ * @export

/**
* This will return the default VAPID key or the uint8array version of the public VAPID key
* provided by the developer.
* @private
*/
getPublicVapidKey_(): Promise<Uint8Array>;
/**
* Gets a PushSubscription for the current user.
* @private
* @param {ServiceWorkerRegistration} registration
* @return {Promise<PushSubscription>}
*/
getPushSubscription_(swRegistration: any, publicVapidKey: any): any;
/**
* This method will set up a message listener to handle

@@ -93,0 +114,0 @@ * events from the service worker that should trigger

@@ -32,2 +32,4 @@ /**

import NOTIFICATION_PERMISSION from '../models/notification-permission';
import FCMDetails from '../models/fcm-details';
import base64ToArrayBuffer from '../helpers/base64-to-array-buffer';
import { createSubscribe } from '@firebase/util';

@@ -50,2 +52,32 @@ var WindowController = /** @class */ (function (_super) {

});
/**
* @private
* @type {ServiceWorkerRegistration}
*/
_this.registrationToUse_;
/**
* @private
* @type {Promise}
*/
_this.manifestCheckPromise_;
/**
* @private
* @type {firebase.Observer}
*/
_this.messageObserver_ = null;
/**
* @private {!firebase.Subscribe} The subscribe function to the onMessage
* observer.
*/
_this.onMessage_ = createSubscribe(function (observer) {
_this.messageObserver_ = observer;
});
/**
* @private
* @type {firebase.Observer}
*/
_this.tokenRefreshObserver_ = null;
_this.onTokenRefresh_ = createSubscribe(function (observer) {
_this.tokenRefreshObserver_ = observer;
});
_this.setupSWMessageListener_();

@@ -139,9 +171,3 @@ return _this;

// browsers stop support callbacks for promised version
var permissionPromise = Notification.requestPermission(function (result) {
if (permissionPromise) {
// Let the promise manage this
return;
}
managePermissionResult(result);
});
var permissionPromise = Notification.requestPermission(managePermissionResult);
if (permissionPromise) {

@@ -170,3 +196,22 @@ // Prefer the promise version as it's the future API.

/**
* This method allows a developer to override the default vapid key
* and instead use a custom VAPID public key.
* @export
* @param {!string} publicKey A URL safe base64 encoded string.
*/
WindowController.prototype.usePublicVapidKey = function (publicKey) {
if (typeof publicKey !== 'string') {
throw this.errorFactory_.create(Errors.codes.INVALID_PUBLIC_VAPID_KEY);
}
if (typeof this.publicVapidKeyToUse_ !== 'undefined') {
throw this.errorFactory_.create(Errors.codes.USE_PUBLIC_KEY_BEFORE_GET_TOKEN);
}
var parsedKey = base64ToArrayBuffer(publicKey);
if (parsedKey.length !== 65) {
throw this.errorFactory_.create(Errors.codes.PUBLIC_KEY_DECRYPTION_FAILED);
}
this.publicVapidKeyToUse_ = parsedKey;
};
/**
* @export
* @param {!firebase.Observer|function(*)} nextOrObserver An observer object

@@ -275,2 +320,33 @@ * or a function triggered on message.

/**
* This will return the default VAPID key or the uint8array version of the public VAPID key
* provided by the developer.
* @private
*/
WindowController.prototype.getPublicVapidKey_ = function () {
if (this.publicVapidKeyToUse_) {
return Promise.resolve(this.publicVapidKeyToUse_);
}
return Promise.resolve(FCMDetails.DEFAULT_PUBLIC_VAPID_KEY);
};
/**
* Gets a PushSubscription for the current user.
* @private
* @param {ServiceWorkerRegistration} registration
* @return {Promise<PushSubscription>}
*/
WindowController.prototype.getPushSubscription_ = function (swRegistration, publicVapidKey) {
// Check for existing subscription first
var subscription;
var fcmTokenDetails;
return swRegistration.pushManager.getSubscription().then(function (subscription) {
if (subscription) {
return subscription;
}
return swRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: publicVapidKey
});
});
};
/**
* This method will set up a message listener to handle

@@ -297,3 +373,5 @@ * events from the service worker that should trigger

var pushMessage = workerPageMessage[WorkerPageMessage.PARAMS.DATA];
_this.messageObserver_.next(pushMessage);
if (_this.messageObserver_) {
_this.messageObserver_.next(pushMessage);
}
break;

@@ -300,0 +378,0 @@ default:

import { ErrorFactory } from '@firebase/util';
export default class DBInterface {
private dbName_;
private DB_NAME_;
private dbVersion_;

@@ -5,0 +5,0 @@ private openDbPromise_;

@@ -26,3 +26,3 @@ /**

this.errorFactory_ = new ErrorFactory('messaging', 'Messaging', Errors.map);
this.dbName_ = dbName;
this.DB_NAME_ = dbName;
this.dbVersion_ = dbVersion;

@@ -43,3 +43,3 @@ this.openDbPromise_ = null;

this.openDbPromise_ = new Promise(function (resolve, reject) {
var request = indexedDB.open(_this.dbName_, _this.dbVersion_);
var request = indexedDB.open(_this.DB_NAME_, _this.dbVersion_);
request.onerror = function (event) {

@@ -52,4 +52,11 @@ reject(event.target.error);

request.onupgradeneeded = function (event) {
var db = event.target.result;
_this.onDBUpgrade(db);
try {
var db = event.target.result;
_this.onDBUpgrade(db);
}
catch (err) {
// close the database as it can't be used.
db.close();
reject(err);
}
};

@@ -56,0 +63,0 @@ });

@@ -20,2 +20,5 @@ declare const _default: {

TOKEN_SUBSCRIBE_NO_PUSH_SET: string;
TOKEN_UNSUBSCRIBE_FAILED: string;
TOKEN_UPDATE_FAILED: string;
TOKEN_UPDATE_NO_TOKEN: string;
USE_SW_BEFORE_GET_TOKEN: string;

@@ -37,2 +40,5 @@ INVALID_DELETE_TOKEN: string;

FAILED_DELETE_VAPID_KEY: string;
INVALID_PUBLIC_VAPID_KEY: string;
USE_PUBLIC_KEY_BEFORE_GET_TOKEN: string;
PUBLIC_KEY_DECRYPTION_FAILED: string;
};

@@ -39,0 +45,0 @@ map: {

@@ -35,2 +35,5 @@ /**

TOKEN_SUBSCRIBE_NO_PUSH_SET: 'token-subscribe-no-push-set',
TOKEN_UNSUBSCRIBE_FAILED: 'token-unsubscribe-failed',
TOKEN_UPDATE_FAILED: 'token-update-failed',
TOKEN_UPDATE_NO_TOKEN: 'token-update-no-token',
USE_SW_BEFORE_GET_TOKEN: 'use-sw-before-get-token',

@@ -51,3 +54,6 @@ INVALID_DELETE_TOKEN: 'invalid-delete-token',

BAD_PUSH_SET: 'bad-push-set',
FAILED_DELETE_VAPID_KEY: 'failed-delete-vapid-key'
FAILED_DELETE_VAPID_KEY: 'failed-delete-vapid-key',
INVALID_PUBLIC_VAPID_KEY: 'invalid-public-vapid-key',
USE_PUBLIC_KEY_BEFORE_GET_TOKEN: 'use-public-key-before-get-token',
PUBLIC_KEY_DECRYPTION_FAILED: 'public-vapid-key-decryption-failed'
};

@@ -75,2 +81,5 @@ var ERROR_MAP = (_a = {},

_a[CODES.TOKEN_SUBSCRIBE_NO_PUSH_SET] = 'FCM returned an invalid response ' + 'when getting an FCM token.',
_a[CODES.TOKEN_UNSUBSCRIBE_FAILED] = 'A problem occured while unsubscribing the ' + 'user from FCM: {$message}',
_a[CODES.TOKEN_UPDATE_FAILED] = 'A problem occured while updating the ' + 'user from FCM: {$message}',
_a[CODES.TOKEN_UPDATE_NO_TOKEN] = 'FCM returned no token when updating ' + 'the user to push.',
_a[CODES.USE_SW_BEFORE_GET_TOKEN] = 'You must call useServiceWorker() before ' +

@@ -99,3 +108,3 @@ 'calling getToken() to ensure your service worker is used.',

'least one character.',
_a[CODES.BAD_VAPID_KEY] = 'The public VAPID key must be a string with at ' + 'least one character.',
_a[CODES.BAD_VAPID_KEY] = 'The public VAPID key is not a Uint8Array with 65 bytes.',
_a[CODES.BAD_SUBSCRIPTION] = 'The subscription must be a valid ' + 'PushSubscription.',

@@ -107,2 +116,4 @@ _a[CODES.BAD_TOKEN] = 'The FCM Token used for storage / lookup was not ' +

_a[CODES.FAILED_DELETE_VAPID_KEY] = 'The VAPID key could not be deleted.',
_a[CODES.INVALID_PUBLIC_VAPID_KEY] = 'The public VAPID key must be a string.',
_a[CODES.PUBLIC_KEY_DECRYPTION_FAILED] = 'The public VAPID key did not equal ' + '65 bytes when decrypted.',
_a);

@@ -109,0 +120,0 @@ export default {

declare const _default: {
ENDPOINT: string;
APPLICATION_SERVER_KEY: number[];
SUBSCRIPTION_OPTIONS: {
DEFAULT_PUBLIC_VAPID_KEY: Uint8Array;
SUBSCRIPTION_DETAILS: {
userVisibleOnly: boolean;
applicationServerKey: Uint8Array;
};
ENDPOINT: string;
};
export default _default;

@@ -17,3 +17,3 @@ /**

'use strict';
var FCM_APPLICATION_SERVER_KEY = [
var DEFAULT_PUBLIC_VAPID_KEY = new Uint8Array([
0x04,

@@ -84,13 +84,14 @@ 0x33,

0x6e
];
]);
var SUBSCRIPTION_DETAILS = {
userVisibleOnly: true,
applicationServerKey: new Uint8Array(FCM_APPLICATION_SERVER_KEY)
applicationServerKey: DEFAULT_PUBLIC_VAPID_KEY
};
export default {
ENDPOINT: 'https://fcm.googleapis.com',
APPLICATION_SERVER_KEY: FCM_APPLICATION_SERVER_KEY,
SUBSCRIPTION_OPTIONS: SUBSCRIPTION_DETAILS
DEFAULT_PUBLIC_VAPID_KEY: DEFAULT_PUBLIC_VAPID_KEY,
SUBSCRIPTION_DETAILS: SUBSCRIPTION_DETAILS,
ENDPOINT: 'https://fcm.googleapis.com'
// ENDPOINT: 'https://jmt17.google.com'
};
//# sourceMappingURL=fcm-details.js.map
import DBInterface from './db-interface';
export default class TokenDetailsModel extends DBInterface {
constructor();
static readonly dbName: string;
static readonly DB_NAME: string;
/**

@@ -51,7 +51,6 @@ * @override

* method for deleting at a later date.
* @param {string} token Token to be deleted
* @return {Promise<Object>} Resolves once the FCM token details have been
* deleted and returns the deleted details.
*/
deleteToken(token: any): Promise<{}>;
deleteToken(token: string): Promise<{}>;
}

@@ -49,5 +49,5 @@ /**

function TokenDetailsModel() {
return _super.call(this, TokenDetailsModel.dbName, DB_VERSION) || this;
return _super.call(this, TokenDetailsModel.DB_NAME, DB_VERSION) || this;
}
Object.defineProperty(TokenDetailsModel, "dbName", {
Object.defineProperty(TokenDetailsModel, "DB_NAME", {
get: function () {

@@ -94,3 +94,4 @@ return 'fcm_token_details_db';

if (input.vapidKey) {
if (typeof input.vapidKey !== 'string' || input.vapidKey.length === 0) {
if (!(input.vapidKey instanceof Uint8Array) ||
input.vapidKey.length !== 65) {
return Promise.reject(this.errorFactory_.create(Errors.codes.BAD_VAPID_KEY));

@@ -228,3 +229,3 @@ }

swScope: swScope,
vapidKey: vapidKey,
vapidKey: arrayBufferToBase64(vapidKey),
endpoint: subscription.endpoint,

@@ -235,3 +236,4 @@ auth: arrayBufferToBase64(subscription['getKey']('auth')),

fcmToken: fcmToken,
fcmPushSet: fcmPushSet
fcmPushSet: fcmPushSet,
createTime: Date.now()
};

@@ -255,3 +257,2 @@ return new Promise(function (resolve, reject) {

* method for deleting at a later date.
* @param {string} token Token to be deleted
* @return {Promise<Object>} Resolves once the FCM token details have been

@@ -258,0 +259,0 @@ * deleted and returns the deleted details.

import DBInterface from './db-interface';
export default class VapidDetailsModel extends DBInterface {
constructor();
static readonly dbName: string;
static readonly DB_NAME: string;
/**

@@ -13,22 +13,14 @@ * @override

* in indexedDB.
* @param {string} swScope
* @return {Promise<string>} The vapid key associated with that scope.
*/
getVapidFromSWScope(swScope: any): Promise<{}>;
getVapidFromSWScope(swScope: string): Promise<Uint8Array>;
/**
* Save a vapid key against a swScope for later date.
* @param {string} swScope The service worker scope to be associated with
* this push subscription.
* @param {string} vapidKey The public vapid key to be associated with
* the swScope.
* @return {Promise<void>}
*/
saveVapidDetails(swScope: any, vapidKey: any): Promise<{}>;
saveVapidDetails(swScope: string, vapidKey: Uint8Array): Promise<void>;
/**
* This method deletes details of the current FCM VAPID key for a SW scope.
* @param {string} swScope Scope to be deleted
* @return {Promise<string>} Resolves once the scope / vapid details have been
* deleted and returns the deleted vapid key.
* Resolves once the scope/vapid details have been deleted and returns the
* deleted vapid key.
*/
deleteVapidDetails(swScope: any): Promise<{}>;
deleteVapidDetails(swScope: string): Promise<Uint8Array>;
}

@@ -31,8 +31,9 @@ /**

var DB_VERSION = 1;
var UNCOMPRESSED_PUBLIC_KEY_SIZE = 65;
var VapidDetailsModel = /** @class */ (function (_super) {
__extends(VapidDetailsModel, _super);
function VapidDetailsModel() {
return _super.call(this, VapidDetailsModel.dbName, DB_VERSION) || this;
return _super.call(this, VapidDetailsModel.DB_NAME, DB_VERSION) || this;
}
Object.defineProperty(VapidDetailsModel, "dbName", {
Object.defineProperty(VapidDetailsModel, "DB_NAME", {
get: function () {

@@ -56,4 +57,2 @@ return 'fcm_vapid_details_db';

* in indexedDB.
* @param {string} swScope
* @return {Promise<string>} The vapid key associated with that scope.
*/

@@ -69,7 +68,7 @@ VapidDetailsModel.prototype.getVapidFromSWScope = function (swScope) {

var scopeRequest = objectStore.get(swScope);
scopeRequest.onerror = function (event) {
reject(event.target.error);
scopeRequest.onerror = function () {
reject(scopeRequest.error);
};
scopeRequest.onsuccess = function (event) {
var result = event.target.result;
scopeRequest.onsuccess = function () {
var result = scopeRequest.result;
var vapidKey = null;

@@ -86,7 +85,2 @@ if (result) {

* Save a vapid key against a swScope for later date.
* @param {string} swScope The service worker scope to be associated with
* this push subscription.
* @param {string} vapidKey The public vapid key to be associated with
* the swScope.
* @return {Promise<void>}
*/

@@ -98,3 +92,3 @@ VapidDetailsModel.prototype.saveVapidDetails = function (swScope, vapidKey) {

}
if (typeof vapidKey !== 'string' || vapidKey.length === 0) {
if (vapidKey === null || vapidKey.length !== UNCOMPRESSED_PUBLIC_KEY_SIZE) {
return Promise.reject(this.errorFactory_.create(Errors.codes.BAD_VAPID_KEY));

@@ -111,6 +105,6 @@ }

var request = objectStore.put(details);
request.onerror = function (event) {
reject(event.target.error);
request.onerror = function () {
reject(request.error);
};
request.onsuccess = function (event) {
request.onsuccess = function () {
resolve();

@@ -123,5 +117,4 @@ };

* This method deletes details of the current FCM VAPID key for a SW scope.
* @param {string} swScope Scope to be deleted
* @return {Promise<string>} Resolves once the scope / vapid details have been
* deleted and returns the deleted vapid key.
* Resolves once the scope/vapid details have been deleted and returns the
* deleted vapid key.
*/

@@ -139,7 +132,7 @@ VapidDetailsModel.prototype.deleteVapidDetails = function (swScope) {

var request = objectStore.delete(swScope);
request.onerror = function (event) {
reject(event.target.error);
request.onerror = function () {
reject(request.error);
};
request.onsuccess = function (event) {
if (event.target.result === 0) {
request.onsuccess = function () {
if (request.result === 0) {
reject(_this.errorFactory_.create(Errors.codes.FAILED_DELETE_VAPID_KEY));

@@ -146,0 +139,0 @@ return;

{
"name": "@firebase/messaging",
"version": "0.1.9-canary.a1e346f",
"version": "0.1.9-canary.f173ad0",
"description": "",

@@ -16,7 +16,8 @@ "author": "Firebase <firebase-support@google.com> (https://firebase.google.com/)",

"peerDependencies": {
"@firebase/app": "0.1.8-canary.a1e346f"
"@firebase/app": "0.1.8-canary.f173ad0"
},
"dependencies": {
"@firebase/messaging-types": "0.1.1-canary.a1e346f",
"@firebase/util": "0.1.8-canary.a1e346f"
"@firebase/messaging-types": "0.1.1-canary.f173ad0",
"@firebase/util": "0.1.8-canary.f173ad0",
"lcov-result-merger": "^1.2.0"
},

@@ -23,0 +24,0 @@ "devDependencies": {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc