tor-browser

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

test_push_service.js (11160B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 // Tests for the FxA push service.
      7 
      8 /* eslint-disable mozilla/use-chromeutils-generateqi */
      9 
     10 const {
     11  FXA_PUSH_SCOPE_ACCOUNT_UPDATE,
     12  ONLOGOUT_NOTIFICATION,
     13  ON_ACCOUNT_DESTROYED_NOTIFICATION,
     14  ON_DEVICE_CONNECTED_NOTIFICATION,
     15  ON_DEVICE_DISCONNECTED_NOTIFICATION,
     16  ON_PASSWORD_CHANGED_NOTIFICATION,
     17  ON_PASSWORD_RESET_NOTIFICATION,
     18  ON_PROFILE_CHANGE_NOTIFICATION,
     19  ON_PROFILE_UPDATED_NOTIFICATION,
     20  ON_VERIFY_LOGIN_NOTIFICATION,
     21  log,
     22 } = ChromeUtils.importESModule(
     23  "resource://gre/modules/FxAccountsCommon.sys.mjs"
     24 );
     25 
     26 const { FxAccountsPushService } = ChromeUtils.importESModule(
     27  "resource://gre/modules/FxAccountsPush.sys.mjs"
     28 );
     29 
     30 XPCOMUtils.defineLazyServiceGetter(
     31  this,
     32  "PushService",
     33  "@mozilla.org/push/Service;1",
     34  Ci.nsIPushService
     35 );
     36 
     37 initTestLogging("Trace");
     38 log.level = Log.Level.Trace;
     39 
     40 const MOCK_ENDPOINT = "http://mochi.test:8888";
     41 
     42 // tests do not allow external connections, mock the PushService
     43 let mockPushService = {
     44  pushTopic: PushService.pushTopic,
     45  subscriptionChangeTopic: PushService.subscriptionChangeTopic,
     46  subscribe(scope, principal, cb) {
     47    cb(Cr.NS_OK, {
     48      endpoint: MOCK_ENDPOINT,
     49    });
     50  },
     51  unsubscribe(scope, principal, cb) {
     52    cb(Cr.NS_OK, true);
     53  },
     54 };
     55 
     56 let mockFxAccounts = {
     57  checkVerificationStatus() {},
     58  updateDeviceRegistration() {},
     59 };
     60 
     61 let mockLog = {
     62  trace() {},
     63  debug() {},
     64  warn() {},
     65  error() {},
     66 };
     67 
     68 add_task(async function initialize() {
     69  let pushService = new FxAccountsPushService();
     70  equal(pushService.initialize(), false);
     71 });
     72 
     73 add_task(async function registerPushEndpointSuccess() {
     74  let pushService = new FxAccountsPushService({
     75    pushService: mockPushService,
     76    fxai: mockFxAccounts,
     77  });
     78 
     79  let subscription = await pushService.registerPushEndpoint();
     80  equal(subscription.endpoint, MOCK_ENDPOINT);
     81 });
     82 
     83 add_task(async function registerPushEndpointFailure() {
     84  let failPushService = Object.assign(mockPushService, {
     85    subscribe(scope, principal, cb) {
     86      cb(Cr.NS_ERROR_ABORT);
     87    },
     88  });
     89 
     90  let pushService = new FxAccountsPushService({
     91    pushService: failPushService,
     92    fxai: mockFxAccounts,
     93  });
     94 
     95  let subscription = await pushService.registerPushEndpoint();
     96  equal(subscription, null);
     97 });
     98 
     99 add_task(async function unsubscribeSuccess() {
    100  let pushService = new FxAccountsPushService({
    101    pushService: mockPushService,
    102    fxai: mockFxAccounts,
    103  });
    104 
    105  let result = await pushService.unsubscribe();
    106  equal(result, true);
    107 });
    108 
    109 add_task(async function unsubscribeFailure() {
    110  let failPushService = Object.assign(mockPushService, {
    111    unsubscribe(scope, principal, cb) {
    112      cb(Cr.NS_ERROR_ABORT);
    113    },
    114  });
    115 
    116  let pushService = new FxAccountsPushService({
    117    pushService: failPushService,
    118    fxai: mockFxAccounts,
    119  });
    120 
    121  let result = await pushService.unsubscribe();
    122  equal(result, null);
    123 });
    124 
    125 add_test(function observeLogout() {
    126  let customLog = Object.assign(mockLog, {
    127    trace(msg) {
    128      if (msg === "FxAccountsPushService unsubscribe") {
    129        // logout means we unsubscribe
    130        run_next_test();
    131      }
    132    },
    133  });
    134 
    135  let pushService = new FxAccountsPushService({
    136    pushService: mockPushService,
    137    log: customLog,
    138  });
    139 
    140  pushService.observe(null, ONLOGOUT_NOTIFICATION);
    141 });
    142 
    143 add_test(function observePushTopicDeviceConnected() {
    144  let msg = {
    145    data: {
    146      json: () => ({
    147        command: ON_DEVICE_CONNECTED_NOTIFICATION,
    148        data: {
    149          deviceName: "My phone",
    150        },
    151      }),
    152    },
    153    QueryInterface() {
    154      return this;
    155    },
    156  };
    157  let obs = (subject, topic) => {
    158    Services.obs.removeObserver(obs, topic);
    159    run_next_test();
    160  };
    161  Services.obs.addObserver(obs, ON_DEVICE_CONNECTED_NOTIFICATION);
    162 
    163  let pushService = new FxAccountsPushService({
    164    pushService: mockPushService,
    165    fxai: mockFxAccounts,
    166  });
    167 
    168  pushService.observe(
    169    msg,
    170    mockPushService.pushTopic,
    171    FXA_PUSH_SCOPE_ACCOUNT_UPDATE
    172  );
    173 });
    174 
    175 add_task(async function observePushTopicDeviceDisconnected_current_device() {
    176  const deviceId = "bogusid";
    177  let msg = {
    178    data: {
    179      json: () => ({
    180        command: ON_DEVICE_DISCONNECTED_NOTIFICATION,
    181        data: {
    182          id: deviceId,
    183        },
    184      }),
    185    },
    186    QueryInterface() {
    187      return this;
    188    },
    189  };
    190 
    191  let signoutCalled = false;
    192  let { FxAccounts } = ChromeUtils.importESModule(
    193    "resource://gre/modules/FxAccounts.sys.mjs"
    194  );
    195  const fxAccountsMock = new FxAccounts({
    196    newAccountState() {
    197      return {
    198        async getUserAccountData() {
    199          return { device: { id: deviceId } };
    200        },
    201      };
    202    },
    203    signOut() {
    204      signoutCalled = true;
    205    },
    206  })._internal;
    207 
    208  const deviceDisconnectedNotificationObserved = new Promise(resolve => {
    209    Services.obs.addObserver(function obs(subject, topic, data) {
    210      Services.obs.removeObserver(obs, topic);
    211      equal(data, JSON.stringify({ isLocalDevice: true }));
    212      resolve();
    213    }, ON_DEVICE_DISCONNECTED_NOTIFICATION);
    214  });
    215 
    216  let pushService = new FxAccountsPushService({
    217    pushService: mockPushService,
    218    fxai: fxAccountsMock,
    219  });
    220 
    221  pushService.observe(
    222    msg,
    223    mockPushService.pushTopic,
    224    FXA_PUSH_SCOPE_ACCOUNT_UPDATE
    225  );
    226 
    227  await deviceDisconnectedNotificationObserved;
    228  ok(signoutCalled);
    229 });
    230 
    231 add_task(async function observePushTopicDeviceDisconnected_another_device() {
    232  const deviceId = "bogusid";
    233  let msg = {
    234    data: {
    235      json: () => ({
    236        command: ON_DEVICE_DISCONNECTED_NOTIFICATION,
    237        data: {
    238          id: deviceId,
    239        },
    240      }),
    241    },
    242    QueryInterface() {
    243      return this;
    244    },
    245  };
    246 
    247  let signoutCalled = false;
    248  let { FxAccounts } = ChromeUtils.importESModule(
    249    "resource://gre/modules/FxAccounts.sys.mjs"
    250  );
    251  const fxAccountsMock = new FxAccounts({
    252    newAccountState() {
    253      return {
    254        async getUserAccountData() {
    255          return { device: { id: "thelocaldevice" } };
    256        },
    257      };
    258    },
    259    signOut() {
    260      signoutCalled = true;
    261    },
    262  })._internal;
    263 
    264  const deviceDisconnectedNotificationObserved = new Promise(resolve => {
    265    Services.obs.addObserver(function obs(subject, topic, data) {
    266      Services.obs.removeObserver(obs, topic);
    267      equal(data, JSON.stringify({ isLocalDevice: false }));
    268      resolve();
    269    }, ON_DEVICE_DISCONNECTED_NOTIFICATION);
    270  });
    271 
    272  let pushService = new FxAccountsPushService({
    273    pushService: mockPushService,
    274    fxai: fxAccountsMock,
    275  });
    276 
    277  pushService.observe(
    278    msg,
    279    mockPushService.pushTopic,
    280    FXA_PUSH_SCOPE_ACCOUNT_UPDATE
    281  );
    282 
    283  await deviceDisconnectedNotificationObserved;
    284  ok(!signoutCalled);
    285 });
    286 
    287 add_test(function observePushTopicAccountDestroyed() {
    288  const uid = "bogusuid";
    289  let msg = {
    290    data: {
    291      json: () => ({
    292        command: ON_ACCOUNT_DESTROYED_NOTIFICATION,
    293        data: {
    294          uid,
    295        },
    296      }),
    297    },
    298    QueryInterface() {
    299      return this;
    300    },
    301  };
    302  let customAccounts = Object.assign(mockFxAccounts, {
    303    _handleAccountDestroyed() {
    304      // checking verification status on push messages without data
    305      run_next_test();
    306    },
    307  });
    308 
    309  let pushService = new FxAccountsPushService({
    310    pushService: mockPushService,
    311    fxai: customAccounts,
    312  });
    313 
    314  pushService.observe(
    315    msg,
    316    mockPushService.pushTopic,
    317    FXA_PUSH_SCOPE_ACCOUNT_UPDATE
    318  );
    319 });
    320 
    321 add_test(function observePushTopicVerifyLogin() {
    322  let url = "http://localhost/newLogin";
    323  let title = "bogustitle";
    324  let body = "bogusbody";
    325  let msg = {
    326    data: {
    327      json: () => ({
    328        command: ON_VERIFY_LOGIN_NOTIFICATION,
    329        data: {
    330          body,
    331          title,
    332          url,
    333        },
    334      }),
    335    },
    336    QueryInterface() {
    337      return this;
    338    },
    339  };
    340  let obs = (subject, topic, data) => {
    341    Services.obs.removeObserver(obs, topic);
    342    Assert.equal(data, JSON.stringify(msg.data.json().data));
    343    run_next_test();
    344  };
    345  Services.obs.addObserver(obs, ON_VERIFY_LOGIN_NOTIFICATION);
    346 
    347  let pushService = new FxAccountsPushService({
    348    pushService: mockPushService,
    349    fxai: mockFxAccounts,
    350  });
    351 
    352  pushService.observe(
    353    msg,
    354    mockPushService.pushTopic,
    355    FXA_PUSH_SCOPE_ACCOUNT_UPDATE
    356  );
    357 });
    358 
    359 add_test(function observePushTopicProfileUpdated() {
    360  let msg = {
    361    data: {
    362      json: () => ({
    363        command: ON_PROFILE_UPDATED_NOTIFICATION,
    364      }),
    365    },
    366    QueryInterface() {
    367      return this;
    368    },
    369  };
    370  let obs = (subject, topic) => {
    371    Services.obs.removeObserver(obs, topic);
    372    run_next_test();
    373  };
    374  Services.obs.addObserver(obs, ON_PROFILE_CHANGE_NOTIFICATION);
    375 
    376  let pushService = new FxAccountsPushService({
    377    pushService: mockPushService,
    378    fxai: mockFxAccounts,
    379  });
    380 
    381  pushService.observe(
    382    msg,
    383    mockPushService.pushTopic,
    384    FXA_PUSH_SCOPE_ACCOUNT_UPDATE
    385  );
    386 });
    387 
    388 add_test(function observePushTopicPasswordChanged() {
    389  let msg = {
    390    data: {
    391      json: () => ({
    392        command: ON_PASSWORD_CHANGED_NOTIFICATION,
    393      }),
    394    },
    395    QueryInterface() {
    396      return this;
    397    },
    398  };
    399 
    400  let pushService = new FxAccountsPushService({
    401    pushService: mockPushService,
    402  });
    403 
    404  pushService._onPasswordChanged = function () {
    405    run_next_test();
    406  };
    407 
    408  pushService.observe(
    409    msg,
    410    mockPushService.pushTopic,
    411    FXA_PUSH_SCOPE_ACCOUNT_UPDATE
    412  );
    413 });
    414 
    415 add_test(function observePushTopicPasswordReset() {
    416  let msg = {
    417    data: {
    418      json: () => ({
    419        command: ON_PASSWORD_RESET_NOTIFICATION,
    420      }),
    421    },
    422    QueryInterface() {
    423      return this;
    424    },
    425  };
    426 
    427  let pushService = new FxAccountsPushService({
    428    pushService: mockPushService,
    429  });
    430 
    431  pushService._onPasswordChanged = function () {
    432    run_next_test();
    433  };
    434 
    435  pushService.observe(
    436    msg,
    437    mockPushService.pushTopic,
    438    FXA_PUSH_SCOPE_ACCOUNT_UPDATE
    439  );
    440 });
    441 
    442 add_task(async function commandReceived() {
    443  let msg = {
    444    data: {
    445      json: () => ({
    446        command: "fxaccounts:command_received",
    447        data: {
    448          url: "https://api.accounts.firefox.com/auth/v1/account/device/commands?index=42&limit=1",
    449        },
    450      }),
    451    },
    452    QueryInterface() {
    453      return this;
    454    },
    455  };
    456 
    457  let fxAccountsMock = {};
    458  const promiseConsumeRemoteMessagesCalled = new Promise(res => {
    459    fxAccountsMock.commands = {
    460      pollDeviceCommands() {
    461        res();
    462      },
    463    };
    464  });
    465 
    466  let pushService = new FxAccountsPushService({
    467    pushService: mockPushService,
    468    fxai: fxAccountsMock,
    469  });
    470 
    471  pushService.observe(
    472    msg,
    473    mockPushService.pushTopic,
    474    FXA_PUSH_SCOPE_ACCOUNT_UPDATE
    475  );
    476  await promiseConsumeRemoteMessagesCalled;
    477 });
    478 
    479 add_test(function observeSubscriptionChangeTopic() {
    480  let customAccounts = Object.assign(mockFxAccounts, {
    481    updateDeviceRegistration() {
    482      // subscription change means updating the device registration
    483      run_next_test();
    484    },
    485  });
    486 
    487  let pushService = new FxAccountsPushService({
    488    pushService: mockPushService,
    489    fxai: customAccounts,
    490  });
    491 
    492  pushService.observe(
    493    null,
    494    mockPushService.subscriptionChangeTopic,
    495    FXA_PUSH_SCOPE_ACCOUNT_UPDATE
    496  );
    497 });