Partial Password Masking on Input Field
Asked Answered
R

3

9

So I need to mask a SSN# input field, lets say the ssn is 123-45-6789, I need to display ***-**-6789 (real time as they enter each digit) but I still need to retain the original value to submit.

I got to the point where I can do that if the user strictly enters the value but it breaks if the user does anything else such as delete, or moving cursor to a random position and adds/deletes a number, copy pasting/deleting, etc. I really don't want to listen to a bunch of events to make this work if thats even possible.

I also tried having a div sit on top of the input field to display the masked ssn while the actual ssn was transparent/hidden behind it but again they lose the functionality of being able to add/delete/select delete/paste in random parts (other then when they start at the end) and also the cursor not totally in sync with the end of the ssn number (asterisk size was the issue). This also broke on some mobile browsers.

I also thought of having two separate input fields, one type password, and one type text sit right next to each other, but again highlighting and deleting/pasting between the two would be an issue.

Ideally if there was something out there to have an input field have two types, part of the value be type password and the rest be type text, that would be fantastic. Btw this is for react js app.

TLDR: Need a fully functional input field that will do password masking on only first 5 digits of ssn and be plaintext for last 4 digits (while having the full plaintext value available for submission).

Thanks!

Rab answered 15/7, 2017 at 0:3 Comment(0)
L
4

This might be a little sloppy, but it works as you want it to, is all in one text field, returns the full accurate SSN (despite replacing first 5 values with bullet points), and allows for editing anywhere in the field.

<input type="password" id="ssn" maxlength=9 />

<script>
    var ssn = document.getElementById('ssn');
    ssn.addEventListener('input', ssnMask, false);
    var ssnFirstFive = "";
    var secondHalf = "";
    var fullSSN = "";

    function ssnMask(){
        if (ssn.value.length <= 5){
            ssn.type = 'password';
        }
        else{
            detectChanges();
            secondHalf = ssn.value.substring(5);
            ssn.type = 'text';
            ssn.value = "•••••";
            ssn.value += secondHalf;
            fullSSN = ssnFirstFive + secondHalf;
        }
    }

    function detectChanges() {
        for (var i = 0; i < 5; i++){
            if (ssn.value[i] != "•"){
                ssnFirstFive = ssnFirstFive.substring(0, i) + ssn.value[i] + ssnFirstFive.substring(i+1);
            }
        }
    }
</script>

Essentially, every time the input is changed, it checks to see if it matches the first 5 from before, and if it doesn't, it will update the necessary characters.

Lefty answered 15/7, 2017 at 1:40 Comment(6)
That's a pretty nice solution. Didn't realize you could copy out of a password field.Humanism
Yeah, it probably isn't exactly the most secure option, but it gets the job doneLefty
Thanks, made some tweaks to this and its as good as it can get at this pointRab
I like this, but had to retrofit it. The fact that the text input appropriation doesn't actually contain the full value means you have to access it some other way, which is problematic for form submits. Additionally this is a singular instance approach, not supportive of a multitude which is just not adequate in my case. Therefore I'm using a derivation of this code, with a hidden password field containing the actual value. The code is simply for display purposes.Invest
This doesn't work. When I delete the last char and add a char in the 2nd digit, only the last 3 digit are unmasked.Tears
@AhmerWaseem I need exactly the same functionality in your react app, can you tell me what changes you did to make it work? Can you give your piece of working code?Mcclendon
H
1

You can use 3 different fields and make then password fields.

Add a focus handler that changes their type into text and a blur handler that changes them back to password.

You can combine them before submission or on the server.

#ssn1{width:25px;}
#ssn2{width:20px;}
#ssn3{width:35px;}
<input type="password" name="ssn" maxlength=3 id="ssn1" />
<input type="password" name="ssn" maxlength=2 id="ssn2"/>
<input type="password" name="ssn" maxlength=4 id="ssn3"/>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
  $('[name="ssn"]').focus(function() {
    $(this).attr("type", "text")
  });
  $('[name="ssn"]').blur(function() {
    $(this).attr("type", "password")
  });
</script>

You can also write a pass handler to all a full SSN to be pasted in the first field and have all three fields get set.

This is the closest you are going unless you work with a single full text box and give the user the ability to mask and unmask the field.

In production apps, this actually the approach I take:

Masked:

enter image description here

Unmasked:

enter image description here

You can implement you own focus/blur functions to automatically unmask/mask the field as needed.

Humanism answered 15/7, 2017 at 0:32 Comment(2)
The only issue is that when the user wants to highlight numbers that happen to be in different fields to delete them or they want to paste a number in.Rab
Selecting on an individual field will unmask it so they can highlight/copy/delete/paste numbers in. You can also put a paste handler on the first field and parse a valid SSN from the paste data an populate all 3 feilds if you would like. You can't have it both ways unless you give the user an option to mask/unmask the entire field as I have shown in my update.Humanism
I
0

Achieve this using html data attributes.

i have used the same html tag and store actual value in html tag attribute (data-value) to use later on and store value to display in html tag attribute value.

Function to partial mask input value

function mask_field_value(obj, mask_letters_count=7){
  mask_value =  $(this).data('mask-value') || '';
  unmask_value = $(this).data('unmask-value') || '';
  if (obj.value.length <= mask_letters_count){
        obj.type = 'password';
        mask_value = obj.value;
        $(this).data('mask-value', obj.value);
    } else {
        obj.type = 'text';
        unmask_value = obj.value.substring(mask_letters_count);
        obj.value = "*".repeat(mask_letters_count) + unmask_value;
        $(this).data('unmask-value', unmask_value);
    }
    $(this).data('value', mask_value + unmask_value);
    console.log($(this).data('value'));
}

Add an event on input fields to mask

$(document).ready(function () {
    $(document).on('keyup', '.mask_input_display', function () {
         mask_field_value(this);
    });
});
Intrauterine answered 13/3, 2020 at 13:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.