hide a string with "•••••" in a prompt menu ?

Folks -
I am looking for a way to hide the string of characters that a user can enter via a “prompt” dialog menu.

Basicaly, I would like that the display shows “¢¢¢¢¢” when the user of the script type “hello”.

I guess that the script should look like this…

set password1 to text returned of (display dialog “Enter the password” default answer “”) as string

– find a way to hide the string that the user will type.

if password1 = “pfm@48$” then
– do something
end tell
end if

Thanks to all of you for your help, :slight_smile:
Arnaud

Folks -

I found an answer to my question there :

http://blog.thefrontiergroup.com.au/2008/12/prompting-for-a-password-with-applescript/

thanks anyway,
Arnaud

[OT rant]
I personally find bullets in password fields one of the most irritating and stupid ideas in computing. (The other’s icon palettes.) I’m invariably alone and in the privacy of my own home when I have to enter a password, but I’m still expected to type in an uncrackable sequence of characters without being able to check my typing visually. I have to do it so carefully that if I were stupid enough to enter a password in a public place with people looking over my shoulder, any determined password thief would simply be able to note which keys I pressed.

The ideal would be a button in the password dialog enabling the user to choose to have legible text if it’s safe to do so. In the absence of such a button, a script could offer the choice as follows:

set passwordTextPreference to button returned of (display dialog "You are about to be asked for your password. Do you need it to be displayed as bullets while you enter it or as readable text?" buttons {"Cancel", "Bullets", "Text"} default button 2 with icon caution)
set pword to text returned of (display dialog "Please enter your password:" default answer "" hidden answer (passwordTextPreference is "Bullets"))

Bullet fans, however, could find the additional step equally irritating. :wink:

Hi Nigel,

I agree. It’s hard to count how many characters you entered. The button to toggle the hiding is a great idea!

gl,
kel

Here’s another, more complicated take on a potential solution. And it has the bonus of giving the person looking over your shoulder an extra chance to see what you’re typing!

You could always remove the verification step and silence all the bullet fans…

on PromptUserForPassword()
	set UseBullets to true
	set Pass1 to ""
	repeat
		set BulletButton to "Show Password"
		if not UseBullets then
			set BulletButton to "Hide Password"
		end if
		set ButtonList to {"Cancel", BulletButton, "OK"}
		try
			set {Pass1, TheButton} to {text returned, button returned} of (display dialog "Please enter password:" default answer Pass1 buttons ButtonList default button 3 hidden answer UseBullets with icon caution)
		on error
			return false
		end try
		if TheButton is BulletButton then
			set UseBullets to not UseBullets
		else
			if not UseBullets then
				return Pass1
			else
				set ButtonList to {item 1, item 3} of ButtonList
				try
					set {Pass2, TheButton} to {text returned, button returned} of (display dialog "Please re-enter password:" default answer "" buttons ButtonList default button 2 with icon caution with hidden answer)
				on error
					return false
				end try
				if Pass2 is Pass1 then
					return Pass1
				else
					display alert "Passwords do not match!" as warning
				end if
			end if
		end if
	end repeat
end PromptUserForPassword

Well that’s certainly more in line with my “button in dialog” suggestion! :cool:

I’ve compressed the logic a bit and added the rejection of empty strings and non-matching cases:

on PromptUserForPassword()
	script o
		on prmpt(msg, ButtonList, UseBullets)
			return (display dialog msg default answer "" buttons ButtonList cancel button 1 default button "OK" hidden answer UseBullets with icon caution)
		end prmpt
	end script
	
	set UseBullets to true
	set ButtonList to {"Cancel", "Show Password", "OK"}
	repeat
		try
			set {Pass1, TheButton} to {text returned, button returned} of o's prmpt("Please enter password:", ButtonList, UseBullets)
			if (TheButton is "OK") then
				considering case
					if ((count Pass1) is 0) then
						display alert "Empty string entered!" as warning
					else if ((not UseBullets) or (text returned of o's prmpt("Please re-enter password:", {"Cancel", "OK"}, UseBullets) is Pass1)) then
						return Pass1
					else
						display alert "Passwords do not match!" as warning
					end if
				end considering
			else
				set UseBullets to (not UseBullets)
				set item 2 of ButtonList to item ((UseBullets as integer) + 1) of {"Hide Password", "Show Password"}
			end if
		on error
			return false
		end try
	end repeat
end PromptUserForPassword

PromptUserForPassword()

I totally forgot that you need to explicitly tell AS to consider case! Time to revisit some scripts that use that…

For more bells and whistles, how about some length and content (upper/lower/numeric) requirements on the password? I know how I’d do it, but your logic is cooler (like the +1 to a boolean to pick the button).

This also seems like a good place to mention that: If you want to use this inside an Automator routine, you need to replace

return (display dialog msg default answer "" buttons ButtonList cancel button 1 default button "OK" hidden answer UseBullets with icon caution)

with

tell application "System Events" to return (display dialog msg default answer "" buttons ButtonList cancel button 1 default button "OK" hidden answer UseBullets with icon caution)

because the Automator “Run Applescript” action doesn’t understand the

hidden answer <boolean>

argument.

So here’s my clunky version of a password getter that lets you set a minimum password length and lets you require or forbid upper/lower/special characters! It also retains the initial password typed so that, if the user switches to/from bullets the password is preserved so they don’t have to type again.

PromptUserForPassword("test")

on PromptUserForPassword(theTitle)
	script o
		property MinLength : 1
		property CharSet : {{name:"lower case", forbidden:false, required:false, Chars:"aäáà âãåăąæbcçćčdďđeéèêëěęfghiíìîïjklĺľłmnñńňoöóòôõőøpqrÅ•Å™sÅŸÅ¡Å›tťţuüúùûůűvwxyýzžźżþ"}, ¬
			{name:"upper case", forbidden:false, required:false, Chars:"AÄÁÀÂÃÅĂĄÆBCÇĆČDĎĐEÉÈÊËĚĘFGHIÍÌÎÏJKLĹĽŁMNÑŃŇOÖÓÒÔÕŐØPQRŔŘSŞŠŚTŤŢUÜÚÙÛŮŰVWXYÝZŽŹŻÞ"}, ¬
			{name:"special", forbidden:false, required:false, Chars:"!@#$%^&*()-=_+[]{}/\\,.≠?'`;:"}}
		on prmpt(msg, promptTitle, defaultAns, ButtonList, UseBullets)
			if (count ButtonList) > 2 then
				set {NumRequired, NumForbidden} to {0, 0}
				repeat with c in CharSet
					set {NumRequired, NumForbidden} to {NumRequired + (c's required as integer), NumForbidden + (c's forbidden as integer)}
				end repeat
				if NumRequired > 0 then
					set msg to msg & return & "(Needs at least 1 "
					set i to 1
					repeat with c in CharSet
						if c's required then
							set msg to msg & c's name
							if i < NumRequired then
								set msg to msg & ", "
							else
								set msg to msg & " character)"
							end if
							set i to i + 1
						end if
					end repeat
				end if
				if NumForbidden > 0 then
					set msg to msg & return & "(Don't use "
					set i to 1
					repeat with c in CharSet
						if c's forbidden then
							set msg to msg & c's name
							if i < NumForbidden - 1 then
								set msg to msg & ", "
							else if i < NumForbidden then
								set msg to msg & " or "
							end if
							set i to i + 1
						end if
					end repeat
					set msg to msg & " characters)"
				end if
			end if
			return (display dialog msg with title promptTitle default answer defaultAns buttons ButtonList cancel button 1 default button "OK" hidden answer UseBullets with icon caution)
		end prmpt
		on passOK(ThePass)
			local RequiredOK
			if (count ThePass) is 0 then
				return {false, "Empty string entered!"}
			else if (count ThePass) < MinLength then
				return {false, "Please enter at least " & MinLength & " characters."}
			else
				set RequiredOK to {}
				repeat with c in CharSet
					set end of RequiredOK to not c's required
					if c's required or c's forbidden then
						repeat with pc in (ThePass as string)
							if c's required and not (end of RequiredOK) and pc is in c's Chars then set RequiredOK's item (count RequiredOK) to true
							if c's forbidden and pc is in c's Chars then return {false, "Password cannot contain " & c's name & " characters!"}
						end repeat
					end if
				end repeat
				repeat with i from 1 to count RequiredOK
					if not (item i of RequiredOK) then return {false, "Password requires at least 1 " & name of (CharSet's item i) & " character!"}
				end repeat
			end if
			return {true}
		end passOK
	end script
	
	set UseBullets to true
	set ButtonList to {"Cancel", "Show Password", "OK"}
	set Pass1 to ""
	repeat
		try
			set {Pass1, TheButton} to {text returned, button returned} of o's prmpt("Please enter password:", theTitle, Pass1, ButtonList, UseBullets)
			if (TheButton is "OK") then
				considering case
					set PassCheck to o's passOK(Pass1)
					if not beginning of PassCheck then
						display alert ((end of PassCheck) as string) as warning
					else if ((not UseBullets) or (text returned of o's prmpt("Please re-enter password:", theTitle, "", {"Cancel", "OK"}, UseBullets) is Pass1)) then
						return Pass1
					else
						display alert "Passwords do not match!" as warning
						set Pass1 to ""
					end if
				end considering
			else
				set UseBullets to (not UseBullets)
				set item 2 of ButtonList to item ((UseBullets as integer) + 1) of {"Hide Password", "Show Password"}
			end if
		on error
			return false
		end try
	end repeat
end PromptUserForPassword