tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

push-event.https.any.js (3988B)


      1 // META: global=window-module
      2 // META: script=/resources/testdriver.js
      3 // META: script=/resources/testdriver-vendor.js
      4 // META: script=/notifications/resources/helpers.js
      5 // META: variant=?includeAppServerKey=true
      6 // META: variant=?includeAppServerKey=false
      7 
      8 import { encrypt } from "./resources/helpers.js"
      9 import { createVapid } from "./resources/vapid.js";
     10 
     11 const includeAppServerKey = new URL(location.href).searchParams.get("includeAppServerKey") === "true";
     12 let registration;
     13 
     14 async function subscribe(t) {
     15  if (includeAppServerKey) {
     16    const vapid = await createVapid();
     17    const subscription = await registration.pushManager.subscribe({
     18      applicationServerKey: vapid.publicKey
     19    });
     20    t.add_cleanup(() => subscription.unsubscribe());
     21    return { vapid, subscription };
     22  }
     23 
     24  // without key
     25  try {
     26    const subscription = await registration.pushManager.subscribe();
     27    t.add_cleanup(() => subscription.unsubscribe());
     28    return { subscription };
     29  } catch (err) {
     30    if (err.name === "NotSupportedError") {
     31      // happens if and only if applicationServerKey omission is disallowed,
     32      // which is permitted per the spec. Throwing OptionalFeatureUnsupportedError marks the
     33      // result as PRECONDITION_FAILED.
     34      //
     35      // https://w3c.github.io/push-api/#subscribe-method
     36      // If the options argument does not include a non-null value for the applicationServerKey
     37      // member, and the push service requires one to be given, queue a global task on the
     38      // networking task source using global to reject promise with a "NotSupportedError"
     39      // DOMException.
     40      throw new OptionalFeatureUnsupportedError(description);
     41    } else {
     42      throw err;
     43    }
     44  }
     45 }
     46 
     47 async function pushMessage(subscription, { vapid, message }) {
     48  const result = !message
     49    ? { headers: { TTL: 15 } }
     50    : await encrypt(
     51      message,
     52      subscription.getKey("p256dh"),
     53      subscription.getKey("auth")
     54    );
     55 
     56  if (includeAppServerKey) {
     57    result.headers.Authorization = await vapid.generateAuthHeader(
     58      new URL(subscription.endpoint).origin
     59    );
     60  }
     61 
     62  const promise = new Promise(r => {
     63    navigator.serviceWorker.addEventListener("message", r, { once: true })
     64  });
     65 
     66  await fetch(subscription.endpoint, {
     67    method: "post",
     68    ...result
     69  });
     70 
     71  return (await promise).data;
     72 }
     73 
     74 promise_setup(async () => {
     75  await trySettingPermission("granted");
     76  registration = await prepareActiveServiceWorker("push-sw.js");
     77 });
     78 
     79 promise_test(async (t) => {
     80  const { vapid, subscription } = await subscribe(t);
     81 
     82  const event = await pushMessage(subscription, { vapid });
     83 
     84  assert_equals(event.constructor, "PushEvent");
     85  assert_equals(event.data, null);
     86 }, "Posting to the push endpoint should fire push event on the service worker");
     87 
     88 const entries = [
     89  { isJSON: false, message: new TextEncoder().encode("Hello") },
     90  { isJSON: false, message: new Uint8Array([226, 130, 40, 240, 40, 140, 188]) },
     91  { isJSON: true, message: new TextEncoder().encode(JSON.stringify({ hello: "world" })) },
     92  { isJSON: false, message: new Uint8Array() },
     93  { isJSON: false, message: new Uint8Array([0x48, 0x69, 0x21, 0x20, 0xf0, 0x9f, 0x91, 0x80]) },
     94 ];
     95 
     96 for (const { isJSON, message } of entries) {
     97  promise_test(async (t) => {
     98    const { vapid, subscription } = await subscribe(t);
     99 
    100    const event = await pushMessage(subscription, { vapid, message });
    101 
    102    assert_equals(event.constructor, "PushEvent");
    103    assert_array_equals(new Uint8Array(event.data.arrayBuffer), message);
    104    assert_array_equals(new Uint8Array(await event.data.blob.arrayBuffer()), message);
    105    assert_equals(event.data.text, new TextDecoder().decode(message));
    106 
    107    assert_equals(event.data.json.ok, isJSON);
    108    if (isJSON) {
    109      assert_array_equals(
    110        new TextEncoder().encode(JSON.stringify(event.data.json.value)),
    111        message
    112      );
    113    }
    114 
    115  }, `Posting to the push endpoint with encrypted data ${message} should fire push event on the service worker`);
    116 }