Skip to content

Commit 735f7c7

Browse files
authored
Feed pushManger with Uint8Array VapidKey (#2809)
* Feed pushManger with Uint8Array VapidKey Since Chrome <= 75 doesn't support base64-encoded VAPID key. For backward compatibility, VAPID key submitted to pushManager#subscribe must be of type Uint8Array.
1 parent 049118a commit 735f7c7

8 files changed

+107
-74
lines changed

packages/messaging/src/core/token-management.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import * as apiModule from './api';
2929
import { Stub } from '../testing/sinon-types';
3030
import { getFakeTokenDetails } from '../testing/fakes/token-details';
3131
import { TokenDetails, SubscriptionOptions } from '../interfaces/token-details';
32-
import { arrayToBase64 } from '../helpers/array-to-base64';
32+
import { arrayToBase64} from '../helpers/array-base64-translator';
3333

3434
describe('Token Management', () => {
3535
let tokenDetails: TokenDetails;

packages/messaging/src/core/token-management.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { dbGet, dbSet, dbRemove } from '../helpers/idb-manager';
1919
import { FirebaseInternalDependencies } from '../interfaces/internal-dependencies';
2020
import { TokenDetails, SubscriptionOptions } from '../interfaces/token-details';
2121
import { requestUpdateToken, requestGetToken, requestDeleteToken } from './api';
22-
import { arrayToBase64 } from '../helpers/array-to-base64';
22+
import { arrayToBase64, base64ToArray} from '../helpers/array-base64-translator';
2323
import { ERROR_FACTORY, ErrorCode } from '../util/errors';
2424

2525
/** UpdateRegistration will be called once every week. */
@@ -158,7 +158,9 @@ async function getPushSubscription(
158158
}
159159
return swRegistration.pushManager.subscribe({
160160
userVisibleOnly: true,
161-
applicationServerKey: vapidKey
161+
// Chrome <= 75 doesn't support base64-encoded VAPID key. For backward compatibility, VAPID key
162+
// submitted to pushManager#subscribe must be of type Uint8Array.
163+
applicationServerKey: base64ToArray(vapidKey)
162164
});
163165
}
164166

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/**
2+
* @license
3+
* Copyright 2017 Google Inc.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import { arrayToBase64, base64ToArray } from './array-base64-translator';
19+
import { expect } from 'chai';
20+
import '../testing/setup';
21+
22+
// prettier-ignore
23+
const TEST_P256_ARRAY = new Uint8Array([
24+
4, 181, 98, 240, 48, 62, 75, 119, 193, 227, 154, 69, 250, 216, 53, 110,
25+
157, 120, 62, 76, 213, 249, 11, 62, 12, 19, 149, 36, 5, 82, 140, 37, 141,
26+
134, 132, 98, 87, 152, 175, 98, 53, 83, 196, 242, 202, 155, 19, 173, 157,
27+
216, 45, 147, 20, 12, 151, 160, 147, 159, 205, 219, 75, 133, 156, 129, 152
28+
]);
29+
const TEST_P256_BASE64 = 'BLVi8DA-S3fB45pF-tg1bp14PkzV-Qs-DBOVJAVSjCWNhoRi' +
30+
'V5ivYjVTxPLKmxOtndgtkxQMl6CTn83bS4WcgZg';
31+
32+
// prettier-ignore
33+
const TEST_AUTH_ARRAY = new Uint8Array([
34+
255, 237, 107, 177, 171, 78, 84, 131, 221, 231, 87, 188, 22, 232, 71, 15
35+
]);
36+
const TEST_AUTH_BASE64 = '_-1rsatOVIPd51e8FuhHDw';
37+
38+
// prettier-ignore
39+
const TEST_VAPID_ARRAY = new Uint8Array([4, 48, 191, 217, 11, 218, 74, 124, 103, 143, 63, 182, 203,
40+
91, 0, 68, 221, 68, 172, 74, 89, 133, 198, 252, 145, 164, 136, 243, 186, 75, 198, 32, 45, 64, 240,
41+
120, 141, 173, 240, 131, 253, 83, 209, 193, 129, 50, 155, 126, 189, 23, 127, 232, 109, 75, 101,
42+
229, 92, 85, 137, 80, 121, 35, 229, 118, 207]);
43+
const TEST_VAPID_BASE64 = 'BDC_2QvaSnxnjz-2y1sARN1ErEpZhcb8kaSI87pLxiAtQPB4ja3wg_1T0cGBMpt' +
44+
'-vRd_6G1LZeVcVYlQeSPlds8';
45+
46+
47+
describe('arrayToBase64', () => {
48+
it('array to base64 translation succeed', () => {
49+
expect(arrayToBase64(TEST_P256_ARRAY)).to.equal(TEST_P256_BASE64);
50+
expect(arrayToBase64(TEST_AUTH_ARRAY)).to.equal(TEST_AUTH_BASE64);
51+
expect(arrayToBase64(TEST_VAPID_ARRAY)).to.equal(TEST_VAPID_BASE64);
52+
});
53+
});
54+
55+
describe('base64ToArray', () => {
56+
it('base64 to array translation succeed', () => {
57+
expect(isEqual(base64ToArray(TEST_P256_BASE64), TEST_P256_ARRAY)).to.equal(true);
58+
expect(isEqual(base64ToArray(TEST_AUTH_BASE64), TEST_AUTH_ARRAY)).to.equal(true);
59+
expect(isEqual(base64ToArray(TEST_VAPID_BASE64), TEST_VAPID_ARRAY)).to.equal(true);
60+
});
61+
});
62+
63+
function isEqual(a: Uint8Array, b: Uint8Array): boolean {
64+
if (a.length !== b.length) {
65+
return false;
66+
}
67+
68+
for (let i = 0; i < a.length; i++) {
69+
if (a[i] !== b[i]) {
70+
return false;
71+
}
72+
}
73+
74+
return true;
75+
}

packages/messaging/src/helpers/array-to-base64.ts renamed to packages/messaging/src/helpers/array-base64-translator.ts

+15
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,18 @@ export function arrayToBase64(array: Uint8Array | ArrayBuffer): string {
2323
.replace(/\+/g, '-')
2424
.replace(/\//g, '_');
2525
}
26+
27+
export function base64ToArray(base64String: string): Uint8Array {
28+
const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
29+
const base64 = (base64String + padding)
30+
.replace(/\-/g, '+')
31+
.replace(/_/g, '/');
32+
33+
const rawData = atob(base64);
34+
const outputArray = new Uint8Array(rawData.length);
35+
36+
for (let i = 0; i < rawData.length; ++i) {
37+
outputArray[i] = rawData.charCodeAt(i);
38+
}
39+
return outputArray;
40+
}

packages/messaging/src/helpers/array-to-base64.test.ts

-45
This file was deleted.

packages/messaging/src/helpers/migrate-old-database.test.ts

+10-24
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
} from './migrate-old-database';
2727
import { FakePushSubscription } from '../testing/fakes/service-worker';
2828
import { getFakeTokenDetails } from '../testing/fakes/token-details';
29+
import { base64ToArray} from './array-base64-translator';
2930

3031
describe('migrateOldDb', () => {
3132
it("does nothing if old DB didn't exist", async () => {
@@ -49,7 +50,7 @@ describe('migrateOldDb', () => {
4950
const v2TokenDetails: V2TokenDetails = {
5051
fcmToken: 'token-value',
5152
swScope: '/scope-value',
52-
vapidKey: base64ToArrayBuffer('dmFwaWQta2V5LXZhbHVl'),
53+
vapidKey: base64ToArray('dmFwaWQta2V5LXZhbHVl'),
5354
fcmSenderId: '1234567890',
5455
fcmPushSet: '7654321',
5556
auth: 'YXV0aC12YWx1ZQ',
@@ -87,7 +88,7 @@ describe('migrateOldDb', () => {
8788
const v2TokenDetails: V2TokenDetails = {
8889
fcmToken: 'token-value',
8990
swScope: '/scope-value',
90-
vapidKey: base64ToArrayBuffer('dmFwaWQta2V5LXZhbHVl'),
91+
vapidKey: base64ToArray('dmFwaWQta2V5LXZhbHVl'),
9192
fcmSenderId: '1234567890',
9293
fcmPushSet: '7654321',
9394
subscription: new FakePushSubscription()
@@ -105,11 +106,11 @@ describe('migrateOldDb', () => {
105106
createTime: 1234567890,
106107
fcmToken: 'token-value',
107108
swScope: '/scope-value',
108-
vapidKey: base64ToArrayBuffer('dmFwaWQta2V5LXZhbHVl'),
109+
vapidKey: base64ToArray('dmFwaWQta2V5LXZhbHVl'),
109110
fcmSenderId: '1234567890',
110111
fcmPushSet: '7654321',
111-
auth: base64ToArrayBuffer('YXV0aC12YWx1ZQ'),
112-
p256dh: base64ToArrayBuffer('cDI1Ni12YWx1ZQ'),
112+
auth: base64ToArray('YXV0aC12YWx1ZQ'),
113+
p256dh: base64ToArray('cDI1Ni12YWx1ZQ'),
113114
endpoint: 'https://example.org'
114115
};
115116

@@ -143,10 +144,10 @@ describe('migrateOldDb', () => {
143144
createTime: 1234567890,
144145
fcmToken: 'token-value',
145146
swScope: '/scope-value',
146-
vapidKey: base64ToArrayBuffer('dmFwaWQta2V5LXZhbHVl'),
147+
vapidKey: base64ToArray('dmFwaWQta2V5LXZhbHVl'),
147148
fcmSenderId: '1234567890',
148-
auth: base64ToArrayBuffer('YXV0aC12YWx1ZQ'),
149-
p256dh: base64ToArrayBuffer('cDI1Ni12YWx1ZQ'),
149+
auth: base64ToArray('YXV0aC12YWx1ZQ'),
150+
p256dh: base64ToArray('cDI1Ni12YWx1ZQ'),
150151
endpoint: 'https://example.org'
151152
};
152153

@@ -198,19 +199,4 @@ async function put(version: number, value: object): Promise<void> {
198199
} finally {
199200
db.close();
200201
}
201-
}
202-
203-
function base64ToArrayBuffer(base64String: string): Uint8Array {
204-
const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
205-
const base64 = (base64String + padding)
206-
.replace(/\-/g, '+')
207-
.replace(/_/g, '/');
208-
209-
const rawData = atob(base64);
210-
const outputArray = new Uint8Array(rawData.length);
211-
212-
for (let i = 0; i < rawData.length; ++i) {
213-
outputArray[i] = rawData.charCodeAt(i);
214-
}
215-
return outputArray;
216-
}
202+
}

packages/messaging/src/helpers/migrate-old-database.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
import { openDb, deleteDb } from 'idb';
1919
import { TokenDetails } from '../interfaces/token-details';
20-
import { arrayToBase64 } from './array-to-base64';
20+
import { arrayToBase64 } from './array-base64-translator';
2121

2222
// https://github.com/firebase/firebase-js-sdk/blob/7857c212f944a2a9eb421fd4cb7370181bc034b5/packages/messaging/src/interfaces/token-details.ts
2323
export interface V2TokenDetails {

packages/messaging/src/testing/fakes/token-details.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
import { TokenDetails } from '../../interfaces/token-details';
1919
import { FakePushSubscription } from './service-worker';
20-
import { arrayToBase64 } from '../../helpers/array-to-base64';
20+
import { arrayToBase64 } from '../../helpers/array-base64-translator';
2121

2222
export function getFakeTokenDetails(): TokenDetails {
2323
const subscription = new FakePushSubscription();

0 commit comments

Comments
 (0)