omemo.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. (function (root, factory) {
  2. define(["jasmine", "mock", "converse-core", "test-utils"], factory);
  3. } (this, function (jasmine, mock, converse, test_utils) {
  4. var Strophe = converse.env.Strophe;
  5. var b64_sha1 = converse.env.b64_sha1;
  6. var $iq = converse.env.$iq;
  7. var _ = converse.env._;
  8. var u = converse.env.utils;
  9. describe("The OMEMO module", function() {
  10. it("will add processing hints to sent out encrypted <message> stanzas",
  11. mock.initConverseWithPromises(
  12. null, ['rosterGroupsFetched'], {},
  13. function (done, _converse) {
  14. // TODO
  15. done();
  16. }));
  17. it("adds a toolbar button for starting an encrypted chat session",
  18. mock.initConverseWithPromises(
  19. null, ['rosterGroupsFetched'], {},
  20. function (done, _converse) {
  21. let iq_stanza;
  22. test_utils.createContacts(_converse, 'current');
  23. const contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
  24. test_utils.waitUntil(function () {
  25. return _.filter(
  26. _converse.connection.IQ_stanzas,
  27. (iq) => {
  28. const node = iq.nodeTree.querySelector('iq[to="'+_converse.bare_jid+'"] query[node="eu.siacs.conversations.axolotl.devicelist"]');
  29. if (node) { iq_stanza = iq.nodeTree;}
  30. return node;
  31. }).length;
  32. }).then(function () {
  33. expect(iq_stanza.outerHTML).toBe(
  34. '<iq type="get" from="dummy@localhost" to="dummy@localhost" xmlns="jabber:client" id="'+iq_stanza.getAttribute("id")+'">'+
  35. '<query xmlns="http://jabber.org/protocol/disco#items" '+
  36. 'node="eu.siacs.conversations.axolotl.devicelist"/>'+
  37. '</iq>');
  38. const stanza = $iq({
  39. 'from': contact_jid,
  40. 'id': iq_stanza.getAttribute('id'),
  41. 'to': _converse.bare_jid,
  42. 'type': 'result',
  43. }).c('query', {
  44. 'xmlns': 'http://jabber.org/protocol/disco#items',
  45. 'node': 'eu.siacs.conversations.axolotl.devicelist'
  46. }).c('device', {'id': '482886413b977930064a5888b92134fe'}).up()
  47. _converse.connection._dataRecv(test_utils.createRequest(stanza));
  48. expect(_converse.devicelists.length).toBe(1);
  49. const devicelist = _converse.devicelists.get(_converse.bare_jid);
  50. expect(devicelist.devices.length).toBe(1);
  51. expect(devicelist.devices.at(0).get('id')).toBe('482886413b977930064a5888b92134fe');
  52. test_utils.openChatBoxFor(_converse, contact_jid);
  53. return test_utils.waitUntil(() => {
  54. return _.filter(_converse.connection.IQ_stanzas, function (iq) {
  55. const node = iq.nodeTree.querySelector('publish[xmlns="eu.siacs.conversations.axolotl.devicelist"]');
  56. if (node) { iq_stanza = iq.nodeTree; }
  57. return node;
  58. }).length;
  59. });
  60. }).then(function () {
  61. expect(iq_stanza.outerHTML).toBe(
  62. '<iq from="dummy@localhost" type="set" xmlns="jabber:client" id="'+iq_stanza.getAttribute('id')+'">'+
  63. '<pubsub xmlns="http://jabber.org/protocol/pubsub">'+
  64. '<publish xmlns="eu.siacs.conversations.axolotl.devicelist">'+
  65. '<item>'+
  66. '<list xmlns="eu.siacs.conversations.axolotl"/>'+
  67. '<device id="482886413b977930064a5888b92134fe"/>'+
  68. '<device id="123456789"/>'+
  69. '</item>'+
  70. '</publish>'+
  71. '</pubsub>'+
  72. '</iq>');
  73. const stanza = $iq({
  74. 'from': _converse.bare_jid,
  75. 'id': iq_stanza.getAttribute('id'),
  76. 'to': _converse.bare_jid,
  77. 'type': 'result'});
  78. _converse.connection._dataRecv(test_utils.createRequest(stanza));
  79. return test_utils.waitUntil(() => {
  80. return _.filter(_converse.connection.IQ_stanzas, function (iq) {
  81. const node = iq.nodeTree.querySelector('publish[node="eu.siacs.conversations.axolotl.bundles:123456789"]');
  82. if (node) { iq_stanza = iq.nodeTree; }
  83. return node;
  84. }).length;
  85. });
  86. }).then(function () {
  87. expect(iq_stanza.getAttributeNames().sort().join()).toBe(["from", "type", "xmlns", "id"].sort().join());
  88. expect(iq_stanza.querySelector('prekeys').childNodes.length).toBe(100);
  89. const signed_prekeys = iq_stanza.querySelectorAll('signedPreKeyPublic');
  90. expect(signed_prekeys.length).toBe(1);
  91. const signed_prekey = signed_prekeys[0];
  92. expect(signed_prekey.getAttribute('signedPreKeyId')).toBe('0')
  93. expect(iq_stanza.querySelectorAll('signedPreKeySignature').length).toBe(1);
  94. expect(iq_stanza.querySelectorAll('identityKey').length).toBe(1);
  95. const stanza = $iq({
  96. 'from': _converse.bare_jid,
  97. 'id': iq_stanza.getAttribute('id'),
  98. 'to': _converse.bare_jid,
  99. 'type': 'result'});
  100. _converse.connection._dataRecv(test_utils.createRequest(stanza));
  101. return test_utils.waitUntil(() => {
  102. return _.filter(
  103. _converse.connection.IQ_stanzas,
  104. (iq) => {
  105. const node = iq.nodeTree.querySelector('iq[to="'+contact_jid+'"] query[node="eu.siacs.conversations.axolotl.devicelist"]');
  106. if (node) { iq_stanza = iq.nodeTree; }
  107. return node;
  108. }).length;});
  109. }).then(function () {
  110. expect(iq_stanza.outerHTML).toBe(
  111. '<iq type="get" from="dummy@localhost" to="'+contact_jid+'" xmlns="jabber:client" id="'+iq_stanza.getAttribute("id")+'">'+
  112. '<query xmlns="http://jabber.org/protocol/disco#items" '+
  113. 'node="eu.siacs.conversations.axolotl.devicelist"/>'+
  114. '</iq>');
  115. const stanza = $iq({
  116. 'from': contact_jid,
  117. 'id': iq_stanza.getAttribute('id'),
  118. 'to': _converse.bare_jid,
  119. 'type': 'result',
  120. }).c('query', {
  121. 'xmlns': 'http://jabber.org/protocol/disco#items',
  122. 'node': 'eu.siacs.conversations.axolotl.devicelist'
  123. }).c('device', {'id': '368866411b877c30064a5f62b917cffe'}).up()
  124. .c('device', {'id': '3300659945416e274474e469a1f0154c'}).up()
  125. .c('device', {'id': '4e30f35051b7b8b42abe083742187228'}).up()
  126. .c('device', {'id': 'ae890ac52d0df67ed7cfdf51b644e901'});
  127. _converse.connection._dataRecv(test_utils.createRequest(stanza));
  128. expect(_converse.devicelists.length).toBe(2);
  129. const devicelist = _converse.devicelists.get(contact_jid);
  130. expect(devicelist.devices.length).toBe(4);
  131. expect(devicelist.devices.at(0).get('id')).toBe('368866411b877c30064a5f62b917cffe');
  132. expect(devicelist.devices.at(1).get('id')).toBe('3300659945416e274474e469a1f0154c');
  133. expect(devicelist.devices.at(2).get('id')).toBe('4e30f35051b7b8b42abe083742187228');
  134. expect(devicelist.devices.at(3).get('id')).toBe('ae890ac52d0df67ed7cfdf51b644e901');
  135. return test_utils.waitUntil(() => _converse.chatboxviews.get(contact_jid).el.querySelector('.chat-toolbar'));
  136. }).then(function () {
  137. const view = _converse.chatboxviews.get(contact_jid);
  138. const toolbar = view.el.querySelector('.chat-toolbar');
  139. expect(view.model.get('omemo_active')).toBe(undefined);
  140. const toggle = toolbar.querySelector('.toggle-omemo');
  141. expect(_.isNull(toggle)).toBe(false);
  142. expect(u.hasClass('fa-unlock', toggle)).toBe(true);
  143. expect(u.hasClass('fa-lock', toggle)).toBe(false);
  144. spyOn(view, 'toggleOMEMO').and.callThrough();
  145. view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
  146. toolbar.querySelector('.toggle-omemo').click();
  147. expect(view.toggleOMEMO).toHaveBeenCalled();
  148. expect(view.model.get('omemo_active')).toBe(true);
  149. return test_utils.waitUntil(() => u.hasClass('fa-lock', toolbar.querySelector('.toggle-omemo')));
  150. }).then(function () {
  151. const view = _converse.chatboxviews.get(contact_jid);
  152. const toolbar = view.el.querySelector('.chat-toolbar');
  153. const toggle = toolbar.querySelector('.toggle-omemo');
  154. expect(u.hasClass('fa-unlock', toggle)).toBe(false);
  155. expect(u.hasClass('fa-lock', toggle)).toBe(true);
  156. done();
  157. }).catch(_.partial(console.error, _));
  158. }));
  159. });
  160. describe("A chatbox with an active OMEMO session", function() {
  161. it("will not show the spoiler toolbar button",
  162. mock.initConverseWithPromises(
  163. null, ['rosterGroupsFetched'], {},
  164. function (done, _converse) {
  165. // TODO
  166. done()
  167. }));
  168. });
  169. }));