Skip to content

Commit eef0b61

Browse files
authored
Merge pull request #175 from web-push-libs/remove_old_standard
Remove support for the old encryption standard (retired in Firefox 45) and remove the old deprecated interface of the sendNotification function.
2 parents 92922b8 + 92005ed commit eef0b61

File tree

3 files changed

+35
-180
lines changed

3 files changed

+35
-180
lines changed

index.js

Lines changed: 6 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -55,35 +55,6 @@ function setGCMAPIKey(apiKey) {
5555
gcmAPIKey = apiKey;
5656
}
5757

58-
// Old standard, Firefox 44+.
59-
function encryptOld(userPublicKey, payload) {
60-
if (typeof payload === 'string' || payload instanceof String) {
61-
payload = new Buffer(payload);
62-
}
63-
var localCurve = crypto.createECDH('prime256v1');
64-
65-
var localPublicKey = localCurve.generateKeys();
66-
var localPrivateKey = localCurve.getPrivateKey();
67-
68-
var sharedSecret = localCurve.computeSecret(urlBase64.decode(userPublicKey));
69-
70-
var salt = urlBase64.encode(crypto.randomBytes(16));
71-
72-
ece.saveKey('webpushKey', sharedSecret);
73-
74-
var cipherText = ece.encrypt(payload, {
75-
keyid: 'webpushKey',
76-
salt: salt,
77-
padSize: 1, // use the aesgcm128 encoding until aesgcm is well supported
78-
});
79-
80-
return {
81-
localPublicKey: localPublicKey,
82-
salt: salt,
83-
cipherText: cipherText,
84-
};
85-
}
86-
8758
// New standard, Firefox 46+ and Chrome 50+.
8859
function encrypt(userPublicKey, userAuth, payload) {
8960
if (typeof payload === 'string' || payload instanceof String) {
@@ -117,18 +88,15 @@ function sendNotification(endpoint, params) {
11788
return new Promise(function(resolve, reject) {
11889
try {
11990
if (args.length === 0) {
120-
throw new Error('sendNotification requires at least one argument, the endpoint URL');
91+
throw new Error('sendNotification requires at least one argument, the endpoint URL.');
12192
} else if (params && typeof params === 'object') {
12293
var TTL = params.TTL;
12394
var userPublicKey = params.userPublicKey;
12495
var userAuth = params.userAuth;
12596
var payload = params.payload;
12697
var vapid = params.vapid;
12798
} else if (args.length !== 1) {
128-
var TTL = args[1];
129-
var userPublicKey = args[2];
130-
var payload = args[3];
131-
console.warn('You are using the old, deprecated, interface of the `sendNotification` function.'.bold.red);
99+
throw new Error('You are using the old, deprecated, interface of the `sendNotification` function.');
132100
}
133101

134102
if (userPublicKey) {
@@ -162,28 +130,15 @@ function sendNotification(endpoint, params) {
162130

163131
var requestPayload;
164132
if (typeof payload !== 'undefined') {
165-
var encrypted;
166-
var encodingHeader;
167-
var cryptoHeaderName;
168-
if (userAuth) {
169-
// Use the new standard if userAuth is defined (Firefox 46+ and Chrome 50+).
170-
encrypted = encrypt(userPublicKey, userAuth, payload);
171-
encodingHeader = 'aesgcm';
172-
cryptoHeaderName = 'Crypto-Key';
173-
} else {
174-
// Use the old standard if userAuth isn't defined (up to Firefox 45).
175-
encrypted = encryptOld(userPublicKey, payload);
176-
encodingHeader = 'aesgcm128';
177-
cryptoHeaderName = 'Encryption-Key';
178-
}
133+
var encrypted = encrypt(userPublicKey, userAuth, payload);
179134

180135
options.headers = {
181136
'Content-Type': 'application/octet-stream',
182-
'Content-Encoding': encodingHeader,
137+
'Content-Encoding': 'aesgcm',
183138
'Encryption': 'keyid=p256dh;salt=' + encrypted.salt,
184139
};
185140

186-
options.headers[cryptoHeaderName] = 'keyid=p256dh;dh=' + urlBase64.encode(encrypted.localPublicKey);
141+
options.headers['Crypto-Key'] = 'keyid=p256dh;dh=' + urlBase64.encode(encrypted.localPublicKey);
187142

188143
requestPayload = encrypted.cipherText;
189144
}
@@ -210,10 +165,8 @@ function sendNotification(endpoint, params) {
210165
options.headers['Content-Type'] = 'application/json';
211166
}
212167

213-
if (vapid && !isGCM && (typeof payload === 'undefined' || 'Crypto-Key' in options.headers)) {
168+
if (vapid && !isGCM) {
214169
// VAPID isn't supported by GCM.
215-
// We also can't use it when there's a payload on Firefox 45, because
216-
// Firefox 45 uses the old standard with Encryption-Key.
217170

218171
var header = {
219172
typ: 'JWT',
@@ -285,7 +238,6 @@ function sendNotification(endpoint, params) {
285238
}
286239

287240
module.exports = {
288-
encryptOld: encryptOld,
289241
encrypt: encrypt,
290242
sendNotification: sendNotification,
291243
setGCMAPIKey: setGCMAPIKey,

test/testEncryptOld.js

Lines changed: 0 additions & 38 deletions
This file was deleted.

test/testSendNotification.js

Lines changed: 29 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ suite('sendNotification', function() {
2929

3030
var userPublicKey = userCurve.generateKeys();
3131
var userPrivateKey = userCurve.getPrivateKey();
32-
33-
var intermediateUserAuth = crypto.randomBytes(12);
3432
var userAuth = crypto.randomBytes(16);
3533

3634
var vapidKeys = webPush.generateVAPIDKeys();
@@ -57,8 +55,6 @@ suite('sendNotification', function() {
5755
assert.equal(req.headers['ttl'], TTL, 'TTL header correct');
5856
}
5957

60-
var cryptoHeader = !!req.headers['encryption-key'] ? 'encryption-key' : 'crypto-key';
61-
6258
if (typeof message !== 'undefined') {
6359
assert(body.length > 0);
6460

@@ -68,39 +64,24 @@ suite('sendNotification', function() {
6864
if (!isGCM) {
6965
assert.equal(req.headers['content-type'], 'application/octet-stream', 'Content-Type header correct');
7066

71-
var keys = req.headers[cryptoHeader].split(',');
67+
var keys = req.headers['crypto-key'].split(',');
7268
var appServerPublicKey = keys.find(function(key) {
7369
return key.indexOf('keyid=p256dh;dh=') === 0;
7470
}).substring('keyid=p256dh;dh='.length);
7571

76-
if (cryptoHeader === 'encryption-key') {
77-
assert.equal(req.headers['content-encoding'], 'aesgcm128', 'Content-Encoding header correct');
78-
79-
var sharedSecret = userCurve.computeSecret(urlBase64.decode(appServerPublicKey));
80-
ece.saveKey('webpushKey', sharedSecret);
81-
82-
var decrypted = ece.decrypt(body, {
83-
keyid: 'webpushKey',
84-
salt: salt,
85-
padSize: 1,
86-
});
87-
} else if (cryptoHeader === 'crypto-key') {
88-
assert.equal(req.headers['content-encoding'], 'aesgcm', 'Content-Encoding header correct');
89-
90-
ece.saveKey('webpushKey', userCurve, 'P-256');
91-
92-
var decrypted = ece.decrypt(body, {
93-
keyid: 'webpushKey',
94-
dh: appServerPublicKey,
95-
salt: salt,
96-
authSecret: urlBase64.encode(userAuth),
97-
padSize: 2,
98-
});
99-
} else {
100-
assert(false, 'Invalid crypto header value');
101-
}
72+
assert.equal(req.headers['content-encoding'], 'aesgcm', 'Content-Encoding header correct');
73+
74+
ece.saveKey('webpushKey', userCurve, 'P-256');
75+
76+
var decrypted = ece.decrypt(body, {
77+
keyid: 'webpushKey',
78+
dh: appServerPublicKey,
79+
salt: salt,
80+
authSecret: urlBase64.encode(userAuth),
81+
padSize: 2,
82+
});
10283
} else {
103-
assert.equal(req.headers[cryptoHeader].indexOf('keyid=p256dh;dh='), 0, 'Encryption-Key header correct');
84+
assert.equal(req.headers['crypto-key'].indexOf('keyid=p256dh;dh='), 0, 'Crypto-Key header correct');
10485
assert.equal(req.headers['content-encoding'], 'aesgcm', 'Content-Encoding header correct');
10586
var appServerPublicKey = req.headers['crypto-key'].substring('keyid=p256dh;dh='.length);
10687

@@ -121,8 +102,7 @@ suite('sendNotification', function() {
121102
}
122103

123104
if (vapid) {
124-
assert.equal(cryptoHeader, 'crypto-key');
125-
var keys = req.headers[cryptoHeader].split(',');
105+
var keys = req.headers['crypto-key'].split(',');
126106
var vapidKey = keys.find(function(key) {
127107
return key.indexOf('p256ecdsa=') === 0;
128108
});
@@ -178,23 +158,7 @@ suite('sendNotification', function() {
178158
});
179159
}
180160

181-
test('send/receive string (old standard)', function() {
182-
return startServer('hello')
183-
.then(function() {
184-
return webPush.sendNotification('https://127.0.0.1:' + serverPort, {
185-
userPublicKey: urlBase64.encode(userPublicKey),
186-
payload: 'hello',
187-
});
188-
})
189-
.then(function(body) {
190-
assert(true, 'sendNotification promise resolved');
191-
assert.equal(body, 'ok');
192-
}, function(e) {
193-
assert(false, 'sendNotification promise rejected with: ' + e);
194-
});
195-
});
196-
197-
test('send/receive string (new standard)', function() {
161+
test('send/receive string', function() {
198162
return startServer('hello')
199163
.then(function() {
200164
return webPush.sendNotification('https://127.0.0.1:' + serverPort, {
@@ -233,6 +197,7 @@ suite('sendNotification', function() {
233197
.then(function() {
234198
return webPush.sendNotification('https://127.0.0.1:' + serverPort, {
235199
userPublicKey: urlBase64.encode(userPublicKey),
200+
userAuth: urlBase64.encode(userAuth),
236201
payload: new Buffer('hello'),
237202
});
238203
})
@@ -248,6 +213,7 @@ suite('sendNotification', function() {
248213
.then(function() {
249214
return webPush.sendNotification('https://127.0.0.1:' + serverPort, {
250215
userPublicKey: urlBase64.encode(userPublicKey),
216+
userAuth: urlBase64.encode(userAuth),
251217
payload: '😁',
252218
});
253219
})
@@ -265,6 +231,7 @@ suite('sendNotification', function() {
265231
.then(function() {
266232
return webPush.sendNotification('https://127.0.0.1:' + serverPort, {
267233
userPublicKey: urlBase64.encode(userPublicKey),
234+
userAuth: urlBase64.encode(userAuth),
268235
payload: '',
269236
});
270237
})
@@ -320,6 +287,7 @@ suite('sendNotification', function() {
320287
return webPush.sendNotification('https://127.0.0.1:' + serverPort, {
321288
TTL: 5,
322289
userPublicKey: urlBase64.encode(userPublicKey),
290+
userAuth: urlBase64.encode(userAuth),
323291
payload: 'hello',
324292
});
325293
})
@@ -479,53 +447,24 @@ suite('sendNotification', function() {
479447
});
480448

481449
test('TTL with old interface', function() {
482-
return startServer(undefined, 5)
483-
.then(function() {
484-
return webPush.sendNotification('https://127.0.0.1:' + serverPort, 5);
485-
})
450+
return webPush.sendNotification('https://127.0.0.1:' + serverPort, 5)
486451
.then(function(body) {
487-
assert(true, 'sendNotification promise resolved');
452+
assert(false, 'sendNotification promise resolved');
488453
}, function() {
489-
assert(false, 'sendNotification promise rejected');
454+
assert(true, 'sendNotification promise rejected');
490455
});
491456
});
492457

493458
test('payload with old interface', function() {
494-
return startServer('hello', 0)
495-
.then(function() {
496-
return webPush.sendNotification('https://127.0.0.1:' + serverPort, 0, urlBase64.encode(userPublicKey), 'hello');
497-
})
459+
return webPush.sendNotification('https://127.0.0.1:' + serverPort, 0, urlBase64.encode(userPublicKey), 'hello')
498460
.then(function(body) {
499-
assert(true, 'sendNotification promise resolved');
500-
assert.equal(body, 'ok');
461+
assert(false, 'sendNotification promise resolved');
501462
}, function() {
502-
assert(false, 'sendNotification promise rejected');
503-
});
504-
});
505-
506-
test('send notification with message (old standard) with vapid', function() {
507-
return startServer('hello', undefined, undefined, undefined, false)
508-
.then(function() {
509-
return webPush.sendNotification('https://127.0.0.1:' + serverPort, {
510-
userPublicKey: urlBase64.encode(userPublicKey),
511-
payload: 'hello',
512-
vapid: {
513-
audience: 'https://www.mozilla.org/',
514-
subject: 'mailto:[email protected]',
515-
privateKey: vapidKeys.privateKey,
516-
publicKey: vapidKeys.publicKey,
517-
},
518-
});
519-
})
520-
.then(function(body) {
521-
assert(true, 'sendNotification promise resolved');
522-
assert.equal(body, 'ok');
523-
}, function(e) {
524-
assert(false, 'sendNotification promise rejected with ' + e);
463+
assert(true, 'sendNotification promise rejected');
525464
});
526465
});
527466

528-
test('send notification with message (new standard) with vapid', function() {
467+
test('send notification with message with vapid', function() {
529468
return startServer('hello', undefined, undefined, undefined, true)
530469
.then(function() {
531470
return webPush.sendNotification('https://127.0.0.1:' + serverPort, {
@@ -561,11 +500,13 @@ suite('sendNotification', function() {
561500

562501
return startServer(undefined, undefined, 200, true)
563502
.then(function() {
564-
return webPush.sendNotification('https://android.googleapis.com/gcm/send/someSubscriptionID', 5, undefined, undefined, {
503+
return webPush.sendNotification('https://android.googleapis.com/gcm/send/someSubscriptionID', {
504+
vapid: {
565505
audience: 'https://www.mozilla.org/',
566506
subject: 'mailto:[email protected]',
567507
privateKey: vapidKeys.privateKey,
568508
publicKey: vapidKeys.publicKey,
509+
}
569510
});
570511
})
571512
.then(function(body) {

0 commit comments

Comments
 (0)