485 lines
23 KiB
JavaScript
485 lines
23 KiB
JavaScript
|
/*! firebase-admin v11.0.1 */
|
||
|
"use strict";
|
||
|
/*!
|
||
|
* Copyright 2020 Google Inc.
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||
|
exports.validateMessage = exports.BLACKLISTED_OPTIONS_KEYS = exports.BLACKLISTED_DATA_PAYLOAD_KEYS = void 0;
|
||
|
const index_1 = require("../utils/index");
|
||
|
const error_1 = require("../utils/error");
|
||
|
const validator = require("../utils/validator");
|
||
|
// Keys which are not allowed in the messaging data payload object.
|
||
|
exports.BLACKLISTED_DATA_PAYLOAD_KEYS = ['from'];
|
||
|
// Keys which are not allowed in the messaging options object.
|
||
|
exports.BLACKLISTED_OPTIONS_KEYS = [
|
||
|
'condition', 'data', 'notification', 'registrationIds', 'registration_ids', 'to',
|
||
|
];
|
||
|
/**
|
||
|
* Checks if the given Message object is valid. Recursively validates all the child objects
|
||
|
* included in the message (android, apns, data etc.). If successful, transforms the message
|
||
|
* in place by renaming the keys to what's expected by the remote FCM service.
|
||
|
*
|
||
|
* @param {Message} Message An object to be validated.
|
||
|
*/
|
||
|
function validateMessage(message) {
|
||
|
if (!validator.isNonNullObject(message)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'Message must be a non-null object');
|
||
|
}
|
||
|
const anyMessage = message;
|
||
|
if (anyMessage.topic) {
|
||
|
// If the topic name is prefixed, remove it.
|
||
|
if (anyMessage.topic.startsWith('/topics/')) {
|
||
|
anyMessage.topic = anyMessage.topic.replace(/^\/topics\//, '');
|
||
|
}
|
||
|
// Checks for illegal characters and empty string.
|
||
|
if (!/^[a-zA-Z0-9-_.~%]+$/.test(anyMessage.topic)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'Malformed topic name');
|
||
|
}
|
||
|
}
|
||
|
const targets = [anyMessage.token, anyMessage.topic, anyMessage.condition];
|
||
|
if (targets.filter((v) => validator.isNonEmptyString(v)).length !== 1) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'Exactly one of topic, token or condition is required');
|
||
|
}
|
||
|
validateStringMap(message.data, 'data');
|
||
|
validateAndroidConfig(message.android);
|
||
|
validateWebpushConfig(message.webpush);
|
||
|
validateApnsConfig(message.apns);
|
||
|
validateFcmOptions(message.fcmOptions);
|
||
|
validateNotification(message.notification);
|
||
|
}
|
||
|
exports.validateMessage = validateMessage;
|
||
|
/**
|
||
|
* Checks if the given object only contains strings as child values.
|
||
|
*
|
||
|
* @param {object} map An object to be validated.
|
||
|
* @param {string} label A label to be included in the errors thrown.
|
||
|
*/
|
||
|
function validateStringMap(map, label) {
|
||
|
if (typeof map === 'undefined') {
|
||
|
return;
|
||
|
}
|
||
|
else if (!validator.isNonNullObject(map)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, `${label} must be a non-null object`);
|
||
|
}
|
||
|
Object.keys(map).forEach((key) => {
|
||
|
if (!validator.isString(map[key])) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, `${label} must only contain string values`);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
/**
|
||
|
* Checks if the given WebpushConfig object is valid. The object must have valid headers and data.
|
||
|
*
|
||
|
* @param {WebpushConfig} config An object to be validated.
|
||
|
*/
|
||
|
function validateWebpushConfig(config) {
|
||
|
if (typeof config === 'undefined') {
|
||
|
return;
|
||
|
}
|
||
|
else if (!validator.isNonNullObject(config)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'webpush must be a non-null object');
|
||
|
}
|
||
|
validateStringMap(config.headers, 'webpush.headers');
|
||
|
validateStringMap(config.data, 'webpush.data');
|
||
|
}
|
||
|
/**
|
||
|
* Checks if the given ApnsConfig object is valid. The object must have valid headers and a
|
||
|
* payload.
|
||
|
*
|
||
|
* @param {ApnsConfig} config An object to be validated.
|
||
|
*/
|
||
|
function validateApnsConfig(config) {
|
||
|
if (typeof config === 'undefined') {
|
||
|
return;
|
||
|
}
|
||
|
else if (!validator.isNonNullObject(config)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'apns must be a non-null object');
|
||
|
}
|
||
|
validateStringMap(config.headers, 'apns.headers');
|
||
|
validateApnsPayload(config.payload);
|
||
|
validateApnsFcmOptions(config.fcmOptions);
|
||
|
}
|
||
|
/**
|
||
|
* Checks if the given ApnsFcmOptions object is valid.
|
||
|
*
|
||
|
* @param {ApnsFcmOptions} fcmOptions An object to be validated.
|
||
|
*/
|
||
|
function validateApnsFcmOptions(fcmOptions) {
|
||
|
if (typeof fcmOptions === 'undefined') {
|
||
|
return;
|
||
|
}
|
||
|
else if (!validator.isNonNullObject(fcmOptions)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'fcmOptions must be a non-null object');
|
||
|
}
|
||
|
if (typeof fcmOptions.imageUrl !== 'undefined' &&
|
||
|
!validator.isURL(fcmOptions.imageUrl)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'imageUrl must be a valid URL string');
|
||
|
}
|
||
|
if (typeof fcmOptions.analyticsLabel !== 'undefined' && !validator.isString(fcmOptions.analyticsLabel)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'analyticsLabel must be a string value');
|
||
|
}
|
||
|
const propertyMappings = {
|
||
|
imageUrl: 'image',
|
||
|
};
|
||
|
Object.keys(propertyMappings).forEach((key) => {
|
||
|
if (key in fcmOptions && propertyMappings[key] in fcmOptions) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, `Multiple specifications for ${key} in ApnsFcmOptions`);
|
||
|
}
|
||
|
});
|
||
|
(0, index_1.renameProperties)(fcmOptions, propertyMappings);
|
||
|
}
|
||
|
/**
|
||
|
* Checks if the given FcmOptions object is valid.
|
||
|
*
|
||
|
* @param {FcmOptions} fcmOptions An object to be validated.
|
||
|
*/
|
||
|
function validateFcmOptions(fcmOptions) {
|
||
|
if (typeof fcmOptions === 'undefined') {
|
||
|
return;
|
||
|
}
|
||
|
else if (!validator.isNonNullObject(fcmOptions)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'fcmOptions must be a non-null object');
|
||
|
}
|
||
|
if (typeof fcmOptions.analyticsLabel !== 'undefined' && !validator.isString(fcmOptions.analyticsLabel)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'analyticsLabel must be a string value');
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* Checks if the given Notification object is valid.
|
||
|
*
|
||
|
* @param {Notification} notification An object to be validated.
|
||
|
*/
|
||
|
function validateNotification(notification) {
|
||
|
if (typeof notification === 'undefined') {
|
||
|
return;
|
||
|
}
|
||
|
else if (!validator.isNonNullObject(notification)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'notification must be a non-null object');
|
||
|
}
|
||
|
if (typeof notification.imageUrl !== 'undefined' && !validator.isURL(notification.imageUrl)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'notification.imageUrl must be a valid URL string');
|
||
|
}
|
||
|
const propertyMappings = {
|
||
|
imageUrl: 'image',
|
||
|
};
|
||
|
Object.keys(propertyMappings).forEach((key) => {
|
||
|
if (key in notification && propertyMappings[key] in notification) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, `Multiple specifications for ${key} in Notification`);
|
||
|
}
|
||
|
});
|
||
|
(0, index_1.renameProperties)(notification, propertyMappings);
|
||
|
}
|
||
|
/**
|
||
|
* Checks if the given ApnsPayload object is valid. The object must have a valid aps value.
|
||
|
*
|
||
|
* @param {ApnsPayload} payload An object to be validated.
|
||
|
*/
|
||
|
function validateApnsPayload(payload) {
|
||
|
if (typeof payload === 'undefined') {
|
||
|
return;
|
||
|
}
|
||
|
else if (!validator.isNonNullObject(payload)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'apns.payload must be a non-null object');
|
||
|
}
|
||
|
validateAps(payload.aps);
|
||
|
}
|
||
|
/**
|
||
|
* Checks if the given Aps object is valid. The object must have a valid alert. If the validation
|
||
|
* is successful, transforms the input object by renaming the keys to valid APNS payload keys.
|
||
|
*
|
||
|
* @param {Aps} aps An object to be validated.
|
||
|
*/
|
||
|
function validateAps(aps) {
|
||
|
if (typeof aps === 'undefined') {
|
||
|
return;
|
||
|
}
|
||
|
else if (!validator.isNonNullObject(aps)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'apns.payload.aps must be a non-null object');
|
||
|
}
|
||
|
validateApsAlert(aps.alert);
|
||
|
validateApsSound(aps.sound);
|
||
|
const propertyMappings = {
|
||
|
contentAvailable: 'content-available',
|
||
|
mutableContent: 'mutable-content',
|
||
|
threadId: 'thread-id',
|
||
|
};
|
||
|
Object.keys(propertyMappings).forEach((key) => {
|
||
|
if (key in aps && propertyMappings[key] in aps) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, `Multiple specifications for ${key} in Aps`);
|
||
|
}
|
||
|
});
|
||
|
(0, index_1.renameProperties)(aps, propertyMappings);
|
||
|
const contentAvailable = aps['content-available'];
|
||
|
if (typeof contentAvailable !== 'undefined' && contentAvailable !== 1) {
|
||
|
if (contentAvailable === true) {
|
||
|
aps['content-available'] = 1;
|
||
|
}
|
||
|
else {
|
||
|
delete aps['content-available'];
|
||
|
}
|
||
|
}
|
||
|
const mutableContent = aps['mutable-content'];
|
||
|
if (typeof mutableContent !== 'undefined' && mutableContent !== 1) {
|
||
|
if (mutableContent === true) {
|
||
|
aps['mutable-content'] = 1;
|
||
|
}
|
||
|
else {
|
||
|
delete aps['mutable-content'];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
function validateApsSound(sound) {
|
||
|
if (typeof sound === 'undefined' || validator.isNonEmptyString(sound)) {
|
||
|
return;
|
||
|
}
|
||
|
else if (!validator.isNonNullObject(sound)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'apns.payload.aps.sound must be a non-empty string or a non-null object');
|
||
|
}
|
||
|
if (!validator.isNonEmptyString(sound.name)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'apns.payload.aps.sound.name must be a non-empty string');
|
||
|
}
|
||
|
const volume = sound.volume;
|
||
|
if (typeof volume !== 'undefined') {
|
||
|
if (!validator.isNumber(volume)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'apns.payload.aps.sound.volume must be a number');
|
||
|
}
|
||
|
if (volume < 0 || volume > 1) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'apns.payload.aps.sound.volume must be in the interval [0, 1]');
|
||
|
}
|
||
|
}
|
||
|
const soundObject = sound;
|
||
|
const key = 'critical';
|
||
|
const critical = soundObject[key];
|
||
|
if (typeof critical !== 'undefined' && critical !== 1) {
|
||
|
if (critical === true) {
|
||
|
soundObject[key] = 1;
|
||
|
}
|
||
|
else {
|
||
|
delete soundObject[key];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* Checks if the given alert object is valid. Alert could be a string or a complex object.
|
||
|
* If specified as an object, it must have valid localization parameters. If successful, transforms
|
||
|
* the input object by renaming the keys to valid APNS payload keys.
|
||
|
*
|
||
|
* @param {string | ApsAlert} alert An alert string or an object to be validated.
|
||
|
*/
|
||
|
function validateApsAlert(alert) {
|
||
|
if (typeof alert === 'undefined' || validator.isString(alert)) {
|
||
|
return;
|
||
|
}
|
||
|
else if (!validator.isNonNullObject(alert)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'apns.payload.aps.alert must be a string or a non-null object');
|
||
|
}
|
||
|
const apsAlert = alert;
|
||
|
if (validator.isNonEmptyArray(apsAlert.locArgs) &&
|
||
|
!validator.isNonEmptyString(apsAlert.locKey)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'apns.payload.aps.alert.locKey is required when specifying locArgs');
|
||
|
}
|
||
|
if (validator.isNonEmptyArray(apsAlert.titleLocArgs) &&
|
||
|
!validator.isNonEmptyString(apsAlert.titleLocKey)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'apns.payload.aps.alert.titleLocKey is required when specifying titleLocArgs');
|
||
|
}
|
||
|
if (validator.isNonEmptyArray(apsAlert.subtitleLocArgs) &&
|
||
|
!validator.isNonEmptyString(apsAlert.subtitleLocKey)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'apns.payload.aps.alert.subtitleLocKey is required when specifying subtitleLocArgs');
|
||
|
}
|
||
|
const propertyMappings = {
|
||
|
locKey: 'loc-key',
|
||
|
locArgs: 'loc-args',
|
||
|
titleLocKey: 'title-loc-key',
|
||
|
titleLocArgs: 'title-loc-args',
|
||
|
subtitleLocKey: 'subtitle-loc-key',
|
||
|
subtitleLocArgs: 'subtitle-loc-args',
|
||
|
actionLocKey: 'action-loc-key',
|
||
|
launchImage: 'launch-image',
|
||
|
};
|
||
|
(0, index_1.renameProperties)(apsAlert, propertyMappings);
|
||
|
}
|
||
|
/**
|
||
|
* Checks if the given AndroidConfig object is valid. The object must have valid ttl, data,
|
||
|
* and notification fields. If successful, transforms the input object by renaming keys to valid
|
||
|
* Android keys. Also transforms the ttl value to the format expected by FCM service.
|
||
|
*
|
||
|
* @param config - An object to be validated.
|
||
|
*/
|
||
|
function validateAndroidConfig(config) {
|
||
|
if (typeof config === 'undefined') {
|
||
|
return;
|
||
|
}
|
||
|
else if (!validator.isNonNullObject(config)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'android must be a non-null object');
|
||
|
}
|
||
|
if (typeof config.ttl !== 'undefined') {
|
||
|
if (!validator.isNumber(config.ttl) || config.ttl < 0) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'TTL must be a non-negative duration in milliseconds');
|
||
|
}
|
||
|
const duration = (0, index_1.transformMillisecondsToSecondsString)(config.ttl);
|
||
|
config.ttl = duration;
|
||
|
}
|
||
|
validateStringMap(config.data, 'android.data');
|
||
|
validateAndroidNotification(config.notification);
|
||
|
validateAndroidFcmOptions(config.fcmOptions);
|
||
|
const propertyMappings = {
|
||
|
collapseKey: 'collapse_key',
|
||
|
restrictedPackageName: 'restricted_package_name',
|
||
|
};
|
||
|
(0, index_1.renameProperties)(config, propertyMappings);
|
||
|
}
|
||
|
/**
|
||
|
* Checks if the given AndroidNotification object is valid. The object must have valid color and
|
||
|
* localization parameters. If successful, transforms the input object by renaming keys to valid
|
||
|
* Android keys.
|
||
|
*
|
||
|
* @param {AndroidNotification} notification An object to be validated.
|
||
|
*/
|
||
|
function validateAndroidNotification(notification) {
|
||
|
if (typeof notification === 'undefined') {
|
||
|
return;
|
||
|
}
|
||
|
else if (!validator.isNonNullObject(notification)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'android.notification must be a non-null object');
|
||
|
}
|
||
|
if (typeof notification.color !== 'undefined' && !/^#[0-9a-fA-F]{6}$/.test(notification.color)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'android.notification.color must be in the form #RRGGBB');
|
||
|
}
|
||
|
if (validator.isNonEmptyArray(notification.bodyLocArgs) &&
|
||
|
!validator.isNonEmptyString(notification.bodyLocKey)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'android.notification.bodyLocKey is required when specifying bodyLocArgs');
|
||
|
}
|
||
|
if (validator.isNonEmptyArray(notification.titleLocArgs) &&
|
||
|
!validator.isNonEmptyString(notification.titleLocKey)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'android.notification.titleLocKey is required when specifying titleLocArgs');
|
||
|
}
|
||
|
if (typeof notification.imageUrl !== 'undefined' &&
|
||
|
!validator.isURL(notification.imageUrl)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'android.notification.imageUrl must be a valid URL string');
|
||
|
}
|
||
|
if (typeof notification.eventTimestamp !== 'undefined') {
|
||
|
if (!(notification.eventTimestamp instanceof Date)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'android.notification.eventTimestamp must be a valid `Date` object');
|
||
|
}
|
||
|
// Convert timestamp to RFC3339 UTC "Zulu" format, example "2014-10-02T15:01:23.045123456Z"
|
||
|
const zuluTimestamp = notification.eventTimestamp.toISOString();
|
||
|
notification.eventTimestamp = zuluTimestamp;
|
||
|
}
|
||
|
if (typeof notification.vibrateTimingsMillis !== 'undefined') {
|
||
|
if (!validator.isNonEmptyArray(notification.vibrateTimingsMillis)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'android.notification.vibrateTimingsMillis must be a non-empty array of numbers');
|
||
|
}
|
||
|
const vibrateTimings = [];
|
||
|
notification.vibrateTimingsMillis.forEach((value) => {
|
||
|
if (!validator.isNumber(value) || value < 0) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'android.notification.vibrateTimingsMillis must be non-negative durations in milliseconds');
|
||
|
}
|
||
|
const duration = (0, index_1.transformMillisecondsToSecondsString)(value);
|
||
|
vibrateTimings.push(duration);
|
||
|
});
|
||
|
notification.vibrateTimingsMillis = vibrateTimings;
|
||
|
}
|
||
|
if (typeof notification.priority !== 'undefined') {
|
||
|
const priority = 'PRIORITY_' + notification.priority.toUpperCase();
|
||
|
notification.priority = priority;
|
||
|
}
|
||
|
if (typeof notification.visibility !== 'undefined') {
|
||
|
const visibility = notification.visibility.toUpperCase();
|
||
|
notification.visibility = visibility;
|
||
|
}
|
||
|
validateLightSettings(notification.lightSettings);
|
||
|
const propertyMappings = {
|
||
|
clickAction: 'click_action',
|
||
|
bodyLocKey: 'body_loc_key',
|
||
|
bodyLocArgs: 'body_loc_args',
|
||
|
titleLocKey: 'title_loc_key',
|
||
|
titleLocArgs: 'title_loc_args',
|
||
|
channelId: 'channel_id',
|
||
|
imageUrl: 'image',
|
||
|
eventTimestamp: 'event_time',
|
||
|
localOnly: 'local_only',
|
||
|
priority: 'notification_priority',
|
||
|
vibrateTimingsMillis: 'vibrate_timings',
|
||
|
defaultVibrateTimings: 'default_vibrate_timings',
|
||
|
defaultSound: 'default_sound',
|
||
|
lightSettings: 'light_settings',
|
||
|
defaultLightSettings: 'default_light_settings',
|
||
|
notificationCount: 'notification_count',
|
||
|
};
|
||
|
(0, index_1.renameProperties)(notification, propertyMappings);
|
||
|
}
|
||
|
/**
|
||
|
* Checks if the given LightSettings object is valid. The object must have valid color and
|
||
|
* light on/off duration parameters. If successful, transforms the input object by renaming
|
||
|
* keys to valid Android keys.
|
||
|
*
|
||
|
* @param {LightSettings} lightSettings An object to be validated.
|
||
|
*/
|
||
|
function validateLightSettings(lightSettings) {
|
||
|
if (typeof lightSettings === 'undefined') {
|
||
|
return;
|
||
|
}
|
||
|
else if (!validator.isNonNullObject(lightSettings)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'android.notification.lightSettings must be a non-null object');
|
||
|
}
|
||
|
if (!validator.isNumber(lightSettings.lightOnDurationMillis) || lightSettings.lightOnDurationMillis < 0) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'android.notification.lightSettings.lightOnDurationMillis must be a non-negative duration in milliseconds');
|
||
|
}
|
||
|
const durationOn = (0, index_1.transformMillisecondsToSecondsString)(lightSettings.lightOnDurationMillis);
|
||
|
lightSettings.lightOnDurationMillis = durationOn;
|
||
|
if (!validator.isNumber(lightSettings.lightOffDurationMillis) || lightSettings.lightOffDurationMillis < 0) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'android.notification.lightSettings.lightOffDurationMillis must be a non-negative duration in milliseconds');
|
||
|
}
|
||
|
const durationOff = (0, index_1.transformMillisecondsToSecondsString)(lightSettings.lightOffDurationMillis);
|
||
|
lightSettings.lightOffDurationMillis = durationOff;
|
||
|
if (!validator.isString(lightSettings.color) ||
|
||
|
(!/^#[0-9a-fA-F]{6}$/.test(lightSettings.color) && !/^#[0-9a-fA-F]{8}$/.test(lightSettings.color))) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'android.notification.lightSettings.color must be in the form #RRGGBB or #RRGGBBAA format');
|
||
|
}
|
||
|
const colorString = lightSettings.color.length === 7 ? lightSettings.color + 'FF' : lightSettings.color;
|
||
|
const rgb = /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/i.exec(colorString);
|
||
|
if (!rgb || rgb.length < 4) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INTERNAL_ERROR, 'regex to extract rgba values from ' + colorString + ' failed.');
|
||
|
}
|
||
|
const color = {
|
||
|
red: parseInt(rgb[1], 16) / 255.0,
|
||
|
green: parseInt(rgb[2], 16) / 255.0,
|
||
|
blue: parseInt(rgb[3], 16) / 255.0,
|
||
|
alpha: parseInt(rgb[4], 16) / 255.0,
|
||
|
};
|
||
|
lightSettings.color = color;
|
||
|
const propertyMappings = {
|
||
|
lightOnDurationMillis: 'light_on_duration',
|
||
|
lightOffDurationMillis: 'light_off_duration',
|
||
|
};
|
||
|
(0, index_1.renameProperties)(lightSettings, propertyMappings);
|
||
|
}
|
||
|
/**
|
||
|
* Checks if the given AndroidFcmOptions object is valid.
|
||
|
*
|
||
|
* @param {AndroidFcmOptions} fcmOptions An object to be validated.
|
||
|
*/
|
||
|
function validateAndroidFcmOptions(fcmOptions) {
|
||
|
if (typeof fcmOptions === 'undefined') {
|
||
|
return;
|
||
|
}
|
||
|
else if (!validator.isNonNullObject(fcmOptions)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'fcmOptions must be a non-null object');
|
||
|
}
|
||
|
if (typeof fcmOptions.analyticsLabel !== 'undefined' && !validator.isString(fcmOptions.analyticsLabel)) {
|
||
|
throw new error_1.FirebaseMessagingError(error_1.MessagingClientErrorCode.INVALID_PAYLOAD, 'analyticsLabel must be a string value');
|
||
|
}
|
||
|
}
|