Prompt.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. 'use strict';
  2. require('../common');
  3. const fc = require('fast-check');
  4. describe('Prompt', function () {
  5. describe('requestPassword & getPassword', function () {
  6. this.timeout(30000);
  7. it('returns the password fed into the dialog', () => {
  8. fc.assert(fc.property(
  9. fc.string(),
  10. function (password) {
  11. password = password.replace(/\r+|\n+/g, '');
  12. const clean = globalThis.cleanup('', {url: 'ftp://example.com/?0000000000000000'});
  13. document.body.innerHTML = `
  14. <div id="passwordmodal" class="modal fade" role="dialog">
  15. <div class="modal-dialog">
  16. <div class="modal-content">
  17. <div class="modal-body">
  18. <form id="passwordform" role="form">
  19. <div class="form-group">
  20. <input id="passworddecrypt" type="password"
  21. class="form-control" placeholder="Enter password">
  22. </div>
  23. <button type="submit">Decrypt</button>
  24. </form>
  25. </div>
  26. </div>
  27. </div>
  28. </div>
  29. <nav class="navbar navbar-inverse navbar-static-top">
  30. <div id="navbar" class="navbar-collapse collapse">
  31. <ul class="nav navbar-nav"><li><button id="newbutton" type="button" class="hidden btn btn-warning navbar-btn">
  32. <svg width="16" height="16" fill="currentColor" aria-hidden="true"><use href="img/bootstrap-icons.svg#file-earmark"></use></svg> New</button><button id="clonebutton" type="button" class="hidden btn btn-warning navbar-btn">
  33. <svg width="16" height="16" fill="currentColor" aria-hidden="true"><use href="img/bootstrap-icons.svg#copy"></use></svg> Clone</button>
  34. <button id="rawtextbutton" type="button" class="hidden btn btn-warning navbar-btn">
  35. <svg width="16" height="16" fill="currentColor" aria-hidden="true"><use href="img/bootstrap-icons.svg#filetype-txt"></use></svg> Raw text</button>
  36. <button id="downloadtextbutton" type="button" class="hidden btn btn-default navbar-btn"></button>
  37. <button id="qrcodelink" type="button" data-toggle="modal" data-target="#qrcodemodal" class="hidden btn btn-warning navbar-btn"/>
  38. <svg width="16" height="16" fill="currentColor" aria-hidden="true"><use href="img/bootstrap-icons.svg#qr-code"></use></svg> QR code</button></li></ul></div>
  39. </nav>
  40. <div id="errormessage"></div>
  41. <div id="loadingindicator"></div>
  42. <div id="status"></div>
  43. `;
  44. // Initialize the Prompt module to set up event listeners
  45. PrivateBin.Alert.init();
  46. PrivateBin.TopNav.init();
  47. PrivateBin.Prompt.init();
  48. PrivateBin.Prompt.requestPassword();
  49. // mock request response
  50. const originalFetch = globalThis.fetch;
  51. globalThis.fetch = function (url) {
  52. assert.strictEqual(url, 'ftp://example.com/?pasteid=0000000000000000');
  53. return Promise.resolve({
  54. ok: true,
  55. status: 200,
  56. statusText: 'OK',
  57. json: function () {
  58. return Promise.resolve({});
  59. }
  60. });
  61. };
  62. // Simulate user input
  63. const passwordInput = document.getElementById('passworddecrypt');
  64. passwordInput.value = password;
  65. // Simulate form submission to trigger password capture
  66. const passwordForm = document.getElementById('passwordform');
  67. /** {@type SubmitEvent} */
  68. const submitEvent = new Event('submit', { bubbles: true, cancelable: true });
  69. passwordForm.dispatchEvent(submitEvent);
  70. // Verify that getPassword returns the submitted password
  71. const result = PrivateBin.Prompt.getPassword();
  72. globalThis.fetch = originalFetch;
  73. clean();
  74. return result === password;
  75. }
  76. ));
  77. });
  78. });
  79. describe('modal dialogs', function () {
  80. afterEach(function () {
  81. cleanup();
  82. });
  83. it('shows the password dialog until a password was submitted', function () {
  84. const clean = globalThis.cleanup('', {url: 'ftp://example.com/?0000000000000000'});
  85. document.body.innerHTML =
  86. '<div id="passwordmodal" tabindex="-1" class="modal" role="dialog" aria-hidden="true">' +
  87. '<div class="modal-dialog" role="document"><div class="modal-content"><div class="modal-body">' +
  88. '<form id="passwordform" role="form"><input id="passworddecrypt" type="password" />' +
  89. '<button type="submit">Decrypt</button></form></div></div></div></div>';
  90. PrivateBin.Alert.init();
  91. PrivateBin.TopNav.init();
  92. PrivateBin.Prompt.init();
  93. const modal = document.getElementById('passwordmodal');
  94. PrivateBin.Prompt.requestPassword();
  95. assert.ok(modal.classList.contains('show'), 'password dialog is shown');
  96. modal.dispatchEvent(new window.KeyboardEvent('keydown', {key: 'Escape', bubbles: true}));
  97. assert.ok(modal.classList.contains('show'), 'password dialog can not be closed with Escape');
  98. const originalFetch = globalThis.fetch;
  99. globalThis.fetch = function () {
  100. return Promise.resolve({
  101. ok: true,
  102. status: 200,
  103. statusText: 'OK',
  104. json: function () {
  105. return Promise.resolve({});
  106. }
  107. });
  108. };
  109. try {
  110. document.getElementById('passworddecrypt').value = 'secret';
  111. document.getElementById('passwordform').dispatchEvent(
  112. new window.Event('submit', {bubbles: true, cancelable: true})
  113. );
  114. assert.ok(!modal.classList.contains('show'), 'password dialog is hidden after submitting');
  115. assert.strictEqual(PrivateBin.Prompt.getPassword(), 'secret');
  116. } finally {
  117. globalThis.fetch = originalFetch;
  118. clean();
  119. }
  120. });
  121. it('asks for confirmation before loading a document', function () {
  122. document.body.innerHTML =
  123. '<div id="loadconfirmmodal" tabindex="-1" class="modal" role="dialog" aria-hidden="true">' +
  124. '<div class="modal-dialog" role="document"><div class="modal-content">' +
  125. '<div class="modal-header"><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div>' +
  126. '<div class="modal-body"><button id="loadconfirm-open-now" type="button" data-bs-dismiss="modal">' +
  127. 'Yes, see it</button></div></div></div></div>';
  128. const modal = document.getElementById('loadconfirmmodal');
  129. PrivateBin.Prompt.requestLoadConfirmation();
  130. assert.ok(modal.classList.contains('show'), 'confirmation dialog is shown');
  131. assert.strictEqual(document.activeElement, document.getElementById('loadconfirm-open-now'));
  132. });
  133. });
  134. });