В IE, как отображение списка сохраненных имен пользователей / паролей в браузере и диалог сохранения имени пользователя / пароля можно контролировать с помощью javascript? - PullRequest
0 голосов
/ 12 ноября 2019

В моем веб-приложении есть две страницы, связанные с учетной записью пользователя, страница создания / редактирования учетной записи и страница входа. Эти страницы работают почти так же, как и ожидалось, за исключением того, что я хочу:

  • Предотвратить отображение имен пользователей / паролей браузера (иначе, список) на странице создания / редактирования учетной записи пользователя

  • Условно отобразить список на странице входа в систему,

  • Условно отобразить диалоговое окно сохранения имени пользователя / пароля браузера (также известное как save-dialog) после отправкистраницу создания / редактирования учетной записи пользователя и

  • Запретить отображение диалогового окна сохранения после отправки страницы входа в систему.

Создание учетной записи пользователя /Страница редактирования имеет флажок «Мое устройство», который можно установить или снять, чтобы управлять некоторыми функциями моего веб-приложения и позволить браузеру отображать / скрывать свой диалог сохранения и список на этой странице и на странице входа в систему.

Находясь на странице создания / редактирования учетной записи, этот список никогда не должен отображаться, поэтому хакер не может легко увидеть имена пользователей, которые уже были сохранены в диспетчере имен и паролей браузера. Однако после того, как пользователь вошел в систему, он может изменить свое имя пользователя и / или пароль на этой странице, затем отправить изменения, и если флажок «Мое устройство» установлен, разрешить браузеру отображать диалоговое окно сохранения.

На странице входа в систему также используется параметр флажка «Мое устройство», чтобы список можно было видеть или нет, если он установлен или не установлен, соответственно. Независимо от настройки «Мое устройство», список сохранения никогда не должен отображаться на этой странице, поскольку это может привести к несинхронизации пароля пользователя на сервере и в браузере и помешать владельцу «автоматически»-logging 'в мое веб-приложение успешно.

На приведенной ниже странице не отображается ни список, ни должен, но также не всегда отображается диалоговое окно сохранения, когда новое / несохраненное имя пользователя / парольбыла введена комбинация или измененный набор.

Вот пример упрощенной страницы создания / редактирования учетной записи пользователя, который в Google Chrome, Microsoft Edge и Firefox правильно скрывает список и много раз показывает диалоговое окно сохранения, когдаФлажок «Мое устройство» установлен. Однако в Microsoft Internet Explorer диалоговое окно сохранения никогда не отображается:

<!DOCTYPE html>
<html lang="en">
  <!--

      How to turn off form autocompletion
      https://developer.mozilla.org/en-US/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion#Preventing_autofilling_with_autocompletenew-password

      The HTML autocomplete attribute
      https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete

  -->
  <head>
    <meta charset="UTF-8">
    <title>Username-Password Test Edit html</title>

    <!-- Dot-Font used to simulate the password type input element -->

    <link type="text/css" rel="stylesheet"
          href="https://cdn.rawgit.com/noppa/text-security/master/dist/text-security-disc.css">
    <script src="https://cdn.jsdelivr.net/npm/ua-parser-js@0/dist/ua-parser.min.js"></script>
    <style>
      * { font-size: x-large; font-family: Arial; }

      /* Show placeholder in normal text */

      .password_empty { font-family: inherit; }

      /* Show value as dots */

      .password_not_empty { font-family: 'text-security-disc'; }

      .column1 { position: absolute; left:  30px; }
      .column2 { position: absolute; left: 190px; top: 0; }

      textarea,
      input[type="email"],
      input[type="password"],
      input[type="text"] { height: 22px; width: 250px; padding-left: 2px; }
    </style>
  </head>
  <body onload="pageLoad();">
    <p id="message" style="opacity: 0;">
      Please use the Submit button to save your information.
    </p>
    <form action="Username_Password_Test.php" method="post" autocomplete="off"
          onsubmit="return submitIt();">

      <!--
        Hidden Username and Password input 'honey-pot' elements for the browser to notice,
        so that it doesn't show the usernames/passwords list.
      -->

      <div id="username_password_div" style="display: none;">
        <input type="text" id="user_name" name="user_name"
               placeholder="username" tabIndex=-1
               autocomplete="on" />
        <input type="password" id="pass_word" name="pas_word"
               placeholder="password" tabIndex=-1
               autocomplete="new-password" />
      </div>

      <br />
      <label class="column1">
        Full Name:
        <input type="text" id="fullname" name="fullname" tabIndex=1
               autocomplete="off"
               class="column2"
               placeholder="Enter your full name"
               value="Test Me" />
      </label><br />
      <br />
      <label class="column1">
        Email:
        <input type="email" id="email" name="email" class="column2" tabIndex=2
               autocomplete="off"
               placeholder="Enter your email"
               value="test.me@email.web" />
      </label><br />
      <br />
      <label class="column1" title="Check if this is your personal device.">
        Your device:
        <span class="column2"
              style="white-space: nowrap;">
          <input type="checkbox" id="your_device" name="your_device" tabIndex=-1
                 autocomplete="off"
                 style="margin: 3px 0;"
                 value="yes" />
          (Leave unchecked for strict account protections.)
        </span>
      </label><br />
      <br />
      <label class="column1">
        Username:
        <input type="text" id="username" name="username" tabIndex=3
               autocomplete="off"
               class="column2"
               placeholder="Enter a username"
               value="" />
      </label><br />
      <br />
      <label class="column1">
        Password:
        <input type="text" id="password" name="password" tabIndex=4
               autocomplete="off"
               class="column2 password_empty"
               placeholder="Enter a password"
               oninput="set_password_ClassName();"
               value="" />
      </label><br />
      <label class="column1" style="margin-top: 4px;">
        Show password?
        <input type="checkbox" id="view_hide_password" tabIndex=-1
               class="column2" style="margin: 7px 0 0 0;"
               onclick="set_password_ClassName(); password.focus();" />
      </label><br />
      <br />
      <button id="submitForm" class="column1" >Submit</button><br /><br />
    </form>
    <script>
      function pageLoad() {
        var labels                 = document.querySelectorAll( 'label' );

        var inputs, input;

        // Create global variables ...

        window.activeElement      =
        window.last_activeElement =  null;

        window.username            = document.getElementById( 'username' );
        window.password            = document.getElementById( 'password' );
        window.view_hide_password  = document.getElementById( 'view_hide_password' );
        window.submit              = document.getElementById( 'submit' );

        //
        // Track which elements get the focus in the window.activeElement - used for
        // IE/Edge to tell what element has the focus when the form is submitted,
        // which sets the document.activeElement to the form when the form is submitted,
        // thus preventing the form submit submitIt function to check which element
        // actually has the focus.
        //

        document.addEventListener( 'focus', setFocus, true );
        document.addEventListener( 'focusout', unsetFocus, true );

        set_password_ClassName();

        setFocus( username );

      } // End of pageLoad() function.

      function setFocus( target ) {
        var target_wtx_context, activeElement_wtx_context;

        //
        // Is the target parameter missing or it can't be focused on, then use the
        // event's target as the element to be focused on ...
        //

        target = ( ( ( target !== undefined ) && ( target.autofocus !== undefined ) )
                   ? target
                   : ( ( event !== undefined ) &&
                       ( event.target !== undefined ) &&
                       ( event.target.autofocus !== undefined )
                       ? event.target
                       : null ) );

        //
        // Get the target's wtx-context, unless the target is the submit button because
        // they don't have them.
        //

        if( ( target.nodeName !== 'BUTTON' ) || ( target.id !== 'submitForm' ) ) {

          target_wtx_context        = getWTXContext( target );

          //
          // If the target has a wtx-context, then set the activeElement's
          // wtx-context.
          //

          if( target_wtx_context ) {

            activeElement_wtx_context = ( ( activeElement )
                                          ? activeElement.getAttribute( 'wtx-context' )
                                          : null );

          } // End of if( target_wtx_context ) ...

        } // End of if( ( target.nodeName !== 'BUTTON' ) ||
          //            ( target.id !== 'submitForm' ) ) ...

        //
        // If the submit button or the current target and the activeElement aren't the
        // same, then set the activeElememt to the current target ...
        //

        if( ( ( target.nodeName === 'BUTTON' ) &&
              ( target.id === 'submitForm' ) ) ||
            ( ( target_wtx_context !== activeElement_wtx_context ) &&
              ( isFocusable( target ) ) ) ) {

          activeElement = target;

          // Focus on the current target, if it isn't the submit button ...

          if( ( target.nodeName !== 'BUTTON' ) ||
              ( target.id !== 'submitForm' ) ) {

            target.focus();

          }
          else {

            submitIt();

          } // End of if( ( target.nodeName !== 'BUTTON' ) ||
            //            ( target.id !== 'submitForm' ) ) ...
            //        else ...

        }
        else if( last_activeElement ) {

          // The current element and the activeElement are the same.

          activeElement = last_activeElement;

        }
        else {

          activeElement = document.active_Element;

        } // End of if( ( ( target.nodeName === 'BUTTON' ) &&
          //              ( target.id === 'submitForm' ) ) ||
          //            ( ( target_wtx_context !== activeElement_wtx_context ) &&
          //              ( isFocusable( target ) ) ) ) ...
          //        else if( last_activeElement ) ... else ...

      } // End of setFocus( target ) function.

      function getWTXContext( target ) {
        //
        // The wtx-context attribute that the Google Chrome browser adds to many
        // elements is useful for comparing elements rather than the
        // 'fields/values' in element objects, but not all browsers add the wtx-content
        // attribute, so this function is used to create a unique value when the
        // getAttribute( 'wtx-content' ) function-call returns a null value.
        //

        var wtx_context =  ( ( target !== null )
                             ? target.getAttribute( 'wtx-context' )
                             : null );

        return ( wtx_context
                 ? wtx_context
                 : ( ++getWTXContext.counter ).toString() + '-wtx' );
      } // End of getWTXContext( target )  function.
      getWTXContext.counter = 1;

      function unsetFocus() {
        var target = event.target;

        if( isFocusable( target ) ) {

          last_activeElement = target;

        } // End of if( isFocusable( target ) ) ...

      } // End of unsetFocus() function.

      function isFocusable( target ) {
        return !( ( target.nodeName == 'BODY' ) ||
                  ( target.nodeName == 'DIV' ) ||
                  ( target.nodeName == 'SPAN' ) )
      } // End of isFocusable( target ) function.

      function set_password_ClassName() {
        //
        // Toggle between the normal text class and the dot-font in the pseudo-
        // password input "password" type text element.  This allows the user to
        // view/hide the password value that they type into the input field.
        // Additionally, the password-empty allows the placeholder to be readable
        // when the pseudo- password input field doesn't contain a value.
        //

        var message     = document.getElementById( 'message' );
        var normal_text = 'password_empty';

        // Remove the password_{not_}empty class ...

        if( password.classList.contains( 'password_empty' ) ) {

          password.classList.remove( 'password_empty' );

        }
        else if( password.classList.contains( 'password_not_empty' ) ) {

          password.classList.remove( 'password_not_empty' );

        } // End of if( password.classList.contains( 'password_empty' ) ) ...
          //        else if( password.classList.contains( 'password_not_empty' ) ) ...

        if( view_hide_password !== null ) {

          if( !view_hide_password.checked ) {

            password.classList.add( ( password.value.trim().length > 0 )
                                    ? 'password_not_empty'
                                    : 'password_empty' );

          }
          else {

            // Show regular text in the password field ...

            password.classList.add( normal_text );

            password.type = 'text';

          } // End of if( !view_hide_password.checked ) ... else ...

        } // End of if( ( view_hide_password !== null ) ...

      } // End of set_password_ClassName() function.

      function submitIt() {
        var pass_word, user_name;

        if( activeElement &&
            ( activeElement.nodeName === 'BUTTON' ) &&
            ( activeElement.id === 'submitForm' ) ) {


          if( document.getElementById( 'your_device' ).checked ) {

            //
            // Make the pseudo-password input type text element a real password field
            // so that the browser will display the save-dialog when the username and
            // password values haven't been saved before or have been changed.
            //

            password.type = 'password';

          } // End of if( document.getElementById( 'your_device' ).checked ) ...

          // The following errors, saying that submit() isn't a function.

          // activeElement.form.submit();

          // This works and submits the form ...

          ( Object.getPrototypeOf( activeElement.form ).submit ).
          call( activeElement.form );

        }
        else {

          // The form is being submitted, but the activeEement isn't the submit button.

          //
          // Display a message telling the user to use the submit button to submit the
          // form.
          //

          if( message.timer ) clearInterval( message.timer );

          message.style.opacity = 1;  // Full opacity.
          message.duration      = 10; // Start from 10, subtract 1 every 1/8 second.
          message.timer         = setInterval(

                 function() {
                   var currentOp = getComputedStyle( message ).
                                   getPropertyValue( 'opacity' );
                   var duration  = parseFloat( message.duration );

                   if( duration > 0 )

                     message.duration = ( duration - 1 ).toString();

                   else {

                     if( currentOp > 0 )

                       currentOp -= 0.1;

                     else {

                       currentOp = 0;
                       clearInterval( message.timer );

                    } // End of if( currentOp > 0 ) ...
                      //        else ...

                    message.style.opacity = currentOp.toString();

                  } // End of if( duration = > 0 ) ...
                    //        else ...

                 },
                 125 );

        } // End of if( activeElement &&
          //            ( activeElement.nodeName === 'BUTTON' ) &&
          //            ( activeElement.id === 'submitForm' ) ) ...

        return false;
      } // End of submitIt() function.
    </script>
  </body>
</html>

Спасибо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...