Add Password Field to Listbox

[quote=279242:@LangueR]The method you posted above seems to miss characters. The following worked better (for me anyways):

Dim cellText As String = Me.cell(row,1) Dim cnt, len As Integer len = cellText.Len cellText = "" For cnt = 1 To Len cellText = cellText + &u25CF Next cnt Me.ActiveCell.Text = cellText[/quote]

I’m not entirely sure how your method is any different. The only difference is I have another string called “dots” which I use to create the black dots. You use the cellText variable. I don’t see any real difference between what you did and what I did.

OK. So based on Norman’s observations, I have refactored my method to look like this:


If column = 1 Then

    Dim cellText as string = me.cell(row,1)
    
    If CountFields(cellText, &u25CF)-1 <> CellText.Len and cellText <> "" Then  // If the number of dots is equal to the length then we have processed everything...
      
      Dim s() as string = cellText.Split(&u25CF)
      Dim TagArray() as string = me.CellTag(row,column).StringValue.Split("")
      
      For i as integer = 0 to s.Ubound
        If s(i) <> "" Then
          TagArray.Insert(i,s(i))
        End IF
      Next
      
      // now build the dots to fill in the field
      Dim dots as string
      For i as integer = 1 to cellText.Len
        dots = dots+&u25CF
      Next
      
      me.CellTag(row,column) = Join(TagArray,"")
      // Replace the text with the field
      me.ActiveCell.Text = dots
      
    ElseIf CellText = "" Then
      me.CellTag(row,column) = Nil
    End If
    
End If

This works great. You can left arrow into the field and type or paste additional characters and it builds things correctly and masks them all no problem. But there is one BIG issue. Backspacing doesn’t work. It’s easy to make backspace work from the end of the field. However, what if someone left arrows into the masked text and starts backspacing (I know it’s unlikely in a password field - but…). And actually, that could be handled as you could count the number of left arrow clicks in the CellKeyDown event. But what if the user clicks into the middle of the field and starts backspacing. There’s no way to know at what position the cursor is inserted. And since the field is all dot characters, you can’t tell what character has been erased or what is around them.

Is there a way to get back the position of the cursor in the masked text? If that was known, then it could be done, but I’m stumped on this one…

EDIT: Wait - I could get the SelStart property of ActiveCell. THAT would give me the insertion point! Then I would know where to remove characters in the tag…

OK. I believe I now have this and have figured out how to replace characters deleted from the center of the field. This seems to work pretty well:


If column = 1 Then
    Dim cellText as string = me.cell(row,1)
    
    //First see if we have done a backspace...
    // If the length of the text in the cell is less than what is in the cellTag
    // Then we have a deletion of one or more characters
    If cellText.Len < me.CellTag(row,column).StringValue.len Then
      
      Dim InsertionPoint as integer = me.ActiveCell.SelStart  // Grab the position of the cursor in the cell
      
      //we've had a deletion and the number of characters = to the difference between the length of the cellTag and cellText get removed...
      
      // Put the characters from the cellTag in an Array so we can easily remove them
      Dim tagArray() as string = me.CellTag(row,column).StringValue.Split("")
      
      //Figure out how many characters we removed.
      Dim NumCharsRemoved as integer = me.CellTag(row,column).StringValue.len - CellText.Len
      
      // Remove the characters
      For i as integer = 1 to NumCharsRemoved
        tagArray.Remove(InsertionPoint)
      Next
      
      // Re-create the tag and off we go!
      me.CellTag(row,column) = Join(tagArray,"")
      
      
    ElseIf CountFields(cellText, &u25CF)-1 <> CellText.Len and cellText <> "" Then  // If the number of dots is equal to the length then we have processed everything...
      
      // Split the text of the field and tag
      Dim s() as string = cellText.Split(&u25CF)
      Dim TagArray() as string = me.CellTag(row,column).StringValue.Split("")
      
      // Now go through the values of the field array. 
      // If the value is not a null string then it's a new character - so insert that character into the 
      // array created from the tag.
      For i as integer = 0 to s.Ubound
        If s(i) <> "" Then
          TagArray.Insert(i,s(i))
        End IF
      Next
      
      // now build the dots to fill in the field
      Dim dots as string
      For i as integer = 1 to cellText.Len
        dots = dots+&u25CF
      Next
      
      // Now rebuild the tag.
      me.CellTag(row,column) = Join(TagArray,"")
      // Replace the text with the field
      me.ActiveCell.Text = dots
      
      
    ElseIf CellText = "" Then
      // May not ever need this but there for safety sake.
      me.CellTag(row,column) = Nil
    End If
End If

Maybe someone else can find this snippet useful. Save themselves some grief… :slight_smile:

That’s quite an ugly hack that will probably still have cases that won’t be handled correctly.

What should happen is this: The text in the field is leaving the correct chars in it but the DISPLAY of the text should show dots. So, ideally, you should not change the text but only how the text appears.

How that’s accomplished? Not sure. Here are a few ideas:

  • use a font that contains only the dot and is applied for all possible chars. I don’t know of such a font but I imagine they exists for just this purpose.
  • try drawing your own string of dots in the CellTextPaint event.

Also, if this is for OSX only, you may be able to find the editable cell Cocoa object and set its password property. How? Again, I haven’t tried that yet, but it should be possible, by getting the focused object on that window. Maybe MBS has a way, even an example.

BTW, you have accepted an answer that’s probably not the best one any more. Are you aware you can revoke accepted answers again?

Well, yes, it’s ugly but thanks for the fact that there’s a bug where you can’t set the password property of ActiveCell. That’s all that’s needed.

As for your suggestions, Thomas, they are good ones. But for the first with using a font comprised of dots for all characters, I don’t think that’s very secure. Someone could copy the text out of the listbox field and then paste it into an editor where they could change the font and see the password string. Yes, that’s an obscure corner case, but it’s still a possibility.

Drawing dots in the paint event is certainly an option. That’s one to consider and I might look at that.

And no, the app is not for OS X only…

Not so much a bug as a design limitation thats existed pretty much since the original incarnation of the listbox was created so many years ago

Using a font that is all dots would, IMHO, not be viable since, as you note, you cant intercept & reject the use of cut copy paste etc in the active cell
Drawing all dots in the cell textpaint from something NOT stored in the cell itself (like the tag) means that not only can you not copy it it never shows anything but dots

I don’t think you’ve given the attack against “dots” in password fields much thought. The dots are ONLY there to prevent someone peeking at your screen from reading them. Any SOFTWARE on your computer that wants to read the password will have no trouble with that anyway. If you can read the entered text in Xojo, why do you think other code can’t do the same? Unless you really want to get a behavior that common Password protection editfields currently do not provide? But even then - softeware could just monitor the keystrokes, then (“keylogger”). I think you’re trying to solve a problem you cannot solve.

I mean, what’s your application here? Do you just want to let a user enter a password like any other app does, and then store that somewhere? In that case, why do you even want to hide it while the user types it? That’s only necessary if your app is likely to be used in an environment where there’s a risk of unauthorized users peeking over the shoulder of the one entering the data. In that regard, I find it quite excessive that many apps hide my typing when I’m at home where there’s no such risk - it only annoy me by making it harder for me to see what I typed. And while I’m on a ranting spree - even more laughable is entering passwords on an iPhone: When you enter a password, it will show them as dots, but only after briefly showing the typed chars. An iPhone is much more likely to be used outside of a “safe” environment, such as on the street or in a cafe, where other people are much more likely able to peek over your shoulder and thus read or even record your passwor entering as a video with their own mobile device.

So, maybe you’re overdoing it :slight_smile:
Or maybe you’re writing a highly classifyable app where security is the highest priority. But then you’re probably still making a lot of mistakes here :wink:

Also, Jon, in the case where you imagine “someone” copying the text from the password field.

I guess I did not realize that you’re using this for two cases:

  1. While entering.
  2. Displaying the entered password later.

All of what I wrote in my posts before was for case 1. There, I think, in most cases it’s still not necessary to even hide the typing.

However, for case 2 you seem to be making a big security mistake, and that’s a common one:

If you consider showing the previously entered actual password later again in a listbox, then that means that you’re storing the password somewhere. That’s a big security flaw. An entered pw should never be stored anywhere. Instead, you should use the once-entered pw to encrypt something, and then only store the encrypted information. Later, if the user wants to access that secured data, you let the user re-enter his pw, and instead of you comparing that to your stored copy, you decrypt that data and thereby tell whether his pw is correct.

Of course, there are cases where you need to know the real password because you’ll pass that on, e.g. to open a database connection. In that case, still, the safer way would be to use what I just explained: You’d let the user enter that DB password, but encrypt that right away with another password the user has to enter at some time when using your app.
When you go this path, then yes, you’d end up with a password you can know and even show to the user. But if you do that, you’d leave the decrypted password inside your app, having it stored in plain view. A hacker could find that. If you store that password in an EditField, even if the “password” property is checked, it’s easy to read it out, e.g. by using “F-Script”, which is able to browse all Cocoa elements using a nice UI browser.

So if you are really concerned about securing passwords, never put the decrypted password anywhere, espcially not in user interface elements, even if they APPEAR to be inaccessible. They are, because you stored the text there, and it’s in there somewhere.

Okay, enough of this. It’s your software, I just thought you should now all the options.

There is another solution, maybe simpler : display a password textfield on top of the cell. Since LisBox does not have smooth scrolling, it is possible to do that very precisely.

Start with the TextField off view, say at top = -50

Sub Action() TextField1.Width = ListBox1.Width TextField1.Height = ListBox1.RowHeight TextField1.Top =ListBox1.Top + ( ListBox1.RowHeight * 3) TextField1.Left = ListBox1.Left TextField1.Setfocus End Sub

Then when entry is finished, put back the TextField off view.