test_notification_data.js (8585B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 let db; 7 let userAgentID = "f5b47f8d-771f-4ea3-b999-91c135f8766d"; 8 9 function run_test() { 10 do_get_profile(); 11 setPrefs({ 12 userAgentID, 13 }); 14 run_next_test(); 15 } 16 17 function putRecord(channelID, scope, publicKey, privateKey, authSecret) { 18 return db.put({ 19 channelID, 20 pushEndpoint: "https://example.org/push/" + channelID, 21 scope, 22 pushCount: 0, 23 lastPush: 0, 24 originAttributes: "", 25 quota: Infinity, 26 systemRecord: true, 27 p256dhPublicKey: ChromeUtils.base64URLDecode(publicKey, { 28 padding: "reject", 29 }), 30 p256dhPrivateKey: privateKey, 31 authenticationSecret: ChromeUtils.base64URLDecode(authSecret, { 32 padding: "reject", 33 }), 34 }); 35 } 36 37 let ackDone; 38 let server; 39 add_task(async function test_notification_ack_data_setup() { 40 db = PushServiceWebSocket.newPushDB(); 41 registerCleanupFunction(() => { 42 return db.drop().then(_ => db.close()); 43 }); 44 45 await putRecord( 46 "subscription1", 47 "https://example.com/page/1", 48 "BPCd4gNQkjwRah61LpdALdzZKLLnU5UAwDztQ5_h0QsT26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA", 49 { 50 crv: "P-256", 51 d: "1jUPhzVsRkzV0vIzwL4ZEsOlKdNOWm7TmaTfzitJkgM", 52 ext: true, 53 key_ops: ["deriveBits"], 54 kty: "EC", 55 x: "8J3iA1CSPBFqHrUul0At3NkosudTlQDAPO1Dn-HRCxM", 56 y: "26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA", 57 }, 58 "c_sGN6uCv9Hu7JOQT34jAQ" 59 ); 60 await putRecord( 61 "subscription2", 62 "https://example.com/page/2", 63 "BPnWyUo7yMnuMlyKtERuLfWE8a09dtdjHSW2lpC9_BqR5TZ1rK8Ldih6ljyxVwnBA-nygQHGRpEmu1jV5K8437E", 64 { 65 crv: "P-256", 66 d: "lFm4nPsUKYgNGBJb5nXXKxl8bspCSp0bAhCYxbveqT4", 67 ext: true, 68 key_ops: ["deriveBits"], 69 kty: "EC", 70 x: "-dbJSjvIye4yXIq0RG4t9YTxrT1212MdJbaWkL38GpE", 71 y: "5TZ1rK8Ldih6ljyxVwnBA-nygQHGRpEmu1jV5K8437E", 72 }, 73 "t3P246Gj9vjKDHHRYaY6hw" 74 ); 75 await putRecord( 76 "subscription3", 77 "https://example.com/page/3", 78 "BDhUHITSeVrWYybFnb7ylVTCDDLPdQWMpf8gXhcWwvaaJa6n3YH8TOcH8narDF6t8mKVvg2ioLW-8MH5O4dzGcI", 79 { 80 crv: "P-256", 81 d: "Q1_SE1NySTYzjbqgWwPgrYh7XRg3adqZLkQPsy319G8", 82 ext: true, 83 key_ops: ["deriveBits"], 84 kty: "EC", 85 x: "OFQchNJ5WtZjJsWdvvKVVMIMMs91BYyl_yBeFxbC9po", 86 y: "Ja6n3YH8TOcH8narDF6t8mKVvg2ioLW-8MH5O4dzGcI", 87 }, 88 "E0qiXGWvFSR0PS352ES1_Q" 89 ); 90 91 let setupDone; 92 let setupDonePromise = new Promise(r => (setupDone = r)); 93 94 PushService.init({ 95 serverURI: "wss://push.example.org/", 96 db, 97 makeWebSocket(uri) { 98 return new MockWebSocket(uri, { 99 onHello(request) { 100 equal( 101 request.uaid, 102 userAgentID, 103 "Should send matching device IDs in handshake" 104 ); 105 this.serverSendMsg( 106 JSON.stringify({ 107 messageType: "hello", 108 uaid: userAgentID, 109 status: 200, 110 use_webpush: true, 111 }) 112 ); 113 server = this; 114 setupDone(); 115 }, 116 onACK(request) { 117 if (ackDone) { 118 ackDone(request); 119 } 120 }, 121 }); 122 }, 123 }); 124 await setupDonePromise; 125 }); 126 127 add_task(async function test_notification_ack_data() { 128 let allTestData = [ 129 { 130 channelID: "subscription1", 131 version: "v1", 132 send: { 133 headers: { 134 encryption_key: 135 'keyid="notification1"; dh="BO_tgGm-yvYAGLeRe16AvhzaUcpYRiqgsGOlXpt0DRWDRGGdzVLGlEVJMygqAUECarLnxCiAOHTP_znkedrlWoU"', 136 encryption: 'keyid="notification1";salt="uAZaiXpOSfOLJxtOCZ09dA"', 137 encoding: "aesgcm128", 138 }, 139 data: "NwrrOWPxLE8Sv5Rr0Kep7n0-r_j3rsYrUw_CXPo", 140 version: "v1", 141 }, 142 ackCode: 101, 143 receive: null, 144 }, 145 { 146 channelID: "subscription2", 147 version: "v2", 148 send: { 149 headers: { 150 encryption_key: 151 'keyid="notification2"; dh="BKVdQcgfncpNyNWsGrbecX0zq3eHIlHu5XbCGmVcxPnRSbhjrA6GyBIeGdqsUL69j5Z2CvbZd-9z1UBH0akUnGQ"', 152 encryption: 'keyid="notification2";salt="vFn3t3M_k42zHBdpch3VRw"', 153 encoding: "aesgcm128", 154 }, 155 data: "Zt9dEdqgHlyAL_l83385aEtb98ZBilz5tgnGgmwEsl5AOCNgesUUJ4p9qUU", 156 }, 157 ackCode: 101, 158 receive: null, 159 }, 160 { 161 channelID: "subscription3", 162 version: "v3", 163 send: { 164 headers: { 165 encryption_key: 166 'keyid="notification3";dh="BD3xV_ACT8r6hdIYES3BJj1qhz9wyv7MBrG9vM2UCnjPzwE_YFVpkD-SGqE-BR2--0M-Yf31wctwNsO1qjBUeMg"', 167 encryption: 168 'keyid="notification3"; salt="DFq188piWU7osPBgqn4Nlg"; rs=24', 169 encoding: "aesgcm128", 170 }, 171 data: "LKru3ZzxBZuAxYtsaCfaj_fehkrIvqbVd1iSwnwAUgnL-cTeDD-83blxHXTq7r0z9ydTdMtC3UjAcWi8LMnfY-BFzi0qJAjGYIikDA", 172 }, 173 ackCode: 101, 174 receive: null, 175 }, 176 // A message encoded with `aesgcm` (2 bytes of padding, authenticated). 177 { 178 channelID: "subscription1", 179 version: "v5", 180 send: { 181 headers: { 182 crypto_key: 183 'keyid=v4;dh="BMh_vsnqu79ZZkMTYkxl4gWDLdPSGE72Lr4w2hksSFW398xCMJszjzdblAWXyhSwakRNEU_GopAm4UGzyMVR83w"', 184 encryption: 'keyid="v4";salt="C14Wb7rQTlXzrgcPHtaUzw"', 185 encoding: "aesgcm", 186 }, 187 data: "pus4kUaBWzraH34M-d_oN8e0LPpF_X6acx695AMXovDe", 188 }, 189 ackCode: 100, 190 receive: { 191 scope: "https://example.com/page/1", 192 data: "Another message", 193 }, 194 }, 195 // A message with 17 bytes of padding and rs of 24 196 { 197 channelID: "subscription2", 198 version: "v5", 199 send: { 200 headers: { 201 crypto_key: 202 'keyid="v5"; dh="BOp-DpyR9eLY5Ci11_loIFqeHzWfc_0evJmq7N8NKzgp60UAMMM06XIi2VZp2_TSdw1omk7E19SyeCCwRp76E-U"', 203 encryption: 'keyid=v5;salt="TvjOou1TqJOQY_ZsOYV3Ww";rs=24', 204 encoding: "aesgcm", 205 }, 206 data: "rG9WYQ2ZwUgfj_tMlZ0vcIaNpBN05FW-9RUBZAM-UUZf0_9eGpuENBpUDAw3mFmd2XJpmvPvAtLVs54l3rGwg1o", 207 }, 208 ackCode: 100, 209 receive: { 210 scope: "https://example.com/page/2", 211 data: "Some message", 212 }, 213 }, 214 // A message without key identifiers. 215 { 216 channelID: "subscription3", 217 version: "v6", 218 send: { 219 headers: { 220 crypto_key: 221 'dh="BEEjwWbF5jZKCgW0kmUWgG-wNcRvaa9_3zZElHAF8przHwd4cp5_kQsc-IMNZcVA0iUix31jxuMOytU-5DwWtyQ"', 222 encryption: "salt=aAQcr2khAksgNspPiFEqiQ", 223 encoding: "aesgcm", 224 }, 225 data: "pEYgefdI-7L46CYn5dR9TIy2AXGxe07zxclbhstY", 226 }, 227 ackCode: 100, 228 receive: { 229 scope: "https://example.com/page/3", 230 data: "Some message", 231 }, 232 }, 233 // A malformed encrypted message. 234 { 235 channelID: "subscription3", 236 version: "v7", 237 send: { 238 headers: { 239 crypto_key: "dh=AAAAAAAA", 240 encryption: "salt=AAAAAAAA", 241 }, 242 data: "AAAAAAAA", 243 }, 244 ackCode: 101, 245 receive: null, 246 }, 247 ]; 248 249 let sendAndReceive = testData => { 250 let messageReceived = testData.receive 251 ? promiseObserverNotification( 252 PushServiceComponent.pushTopic, 253 (subject, data) => { 254 let notification = subject.QueryInterface(Ci.nsIPushMessage).data; 255 equal( 256 notification.text(), 257 testData.receive.data, 258 "Check data for notification " + testData.version 259 ); 260 equal( 261 data, 262 testData.receive.scope, 263 "Check scope for notification " + testData.version 264 ); 265 return true; 266 } 267 ) 268 : Promise.resolve(); 269 270 let ackReceived = new Promise(resolve => (ackDone = resolve)).then( 271 ackData => { 272 deepEqual( 273 { 274 messageType: "ack", 275 updates: [ 276 { 277 channelID: testData.channelID, 278 version: testData.version, 279 code: testData.ackCode, 280 }, 281 ], 282 }, 283 ackData, 284 "Check updates for acknowledgment " + testData.version 285 ); 286 } 287 ); 288 289 let msg = JSON.parse(JSON.stringify(testData.send)); 290 msg.messageType = "notification"; 291 msg.channelID = testData.channelID; 292 msg.version = testData.version; 293 server.serverSendMsg(JSON.stringify(msg)); 294 295 return Promise.all([messageReceived, ackReceived]); 296 }; 297 298 await allTestData.reduce((p, testData) => { 299 return p.then(_ => sendAndReceive(testData)); 300 }, Promise.resolve()); 301 });