4

On OS X 10.8.x I had an Automator service set up to paste a password from clipboard into the password window that pops up for mounting an encrypted disk.

I don't wish to store the password in my keychain, and it is long and tedious to type out.

I never got the applescript within the Automator service quite right. It would generate an error, but it still got the job done (i.e. the password was pasted). Since upgrading to Yosemite it seems the script in the Automator service doesn't work at all. The error generated indicates "window 1" doesn't exist.

Here is what I had:

tell application "System Events" to tell process "SecurityAgent"
set value of text field 1 of window 1 to (the clipboard)
if exists (text field 2 of window 1) then
    set value of text field 2 of window 1 to (the clipboard)
end if
click button 1 of group 1 of window 1
end tell

I don't recall where I got this from, but some of it may have come from here

I know very little about AppleScript, and would appreciate some help fine tuning (or completely rewriting) this script so that it does the following:

  1. Checks there is data in the clipboard
  2. Checks the SecurityAgent window is active (or in some way ensures it can be interacted with, to avoid generating an error)
  3. Pastes the content of clipboard
  4. Clicks the 'Unlock' button

I don't know if it is possible, but it would be handy if it also brought 1Password to the foreground and activated "Copy password" (which is a menu option in the "Items" menu). I can, however, have Automator actions perform that task. But it would be nice to see (for learning) how to achieve that with AppleScript.

4 Answers 4

2

This script worked for me:

https://gist.github.com/SuperHofstad/f826985ec536ff2d650699cb37a7fadc

set appPass to "PASSWORD" as text

tell application "System Events"
    delay 0.5
    repeat until exists process "SecurityAgent"
        delay 0.5
    end repeat
    tell process "SecurityAgent"
        keystroke appPass
        key code 36
    end tell
end tell
2
  • Hi there, if you could add why this is a good solution and how it works for others in the community, that would be wonderful.
    – bret7600
    Commented Jan 16, 2019 at 2:33
  • Well, it did work, until I noticed that it did not if a program opened after the authentication window came up within the delay, I think. Maybe add check to see if the valid window got the right keystrokes ( if doable ) Another problem is with the last couple versions of macOS, there are more restrictions on what apps can do, so one would need to set appropriate permissions in security and privacy before running the script, and even then, it wasn't perfect, sometimes got permission error. So not a final solution, but one to maybe build upon. I might get time to look at it on a later date. Commented Jan 17, 2019 at 3:25
1

With thanks to input from markhunte and tetsujin, I came up with the following solution. With all things considered, the exact requirements evolved to the following:

  1. Ensure a SecurityAgent dialog is actually present so that script doesn't run otherwise.
  2. Reposition the SecurityAgent dialog because it can readily get in the way in its default position.
  3. Display a message which will stay on top of 1Password, but is not generated through 1password, instructing the user to select the correct item in 1Password
  4. Automatically copy the password for current 1Password item
  5. Delay the script long enough for the password to actually end up in the clipboard, before the script attempts pasting it.
  6. Paste the clipboard into the SecurityAgent, and submit it.

I came up with the following solution:

set appName to "SecurityAgent"
set passApp to "1Password 5" (* set this to the name of your password manager *)

tell application "System Events"
     if not (exists window 1 of process appName) then -- test if SecurityAgent window exists
         return -- abort if SecurityAgent window does not exist
     end if
 end tell
 tell application "System Events"
    set position of window 1 of process appName to {10, 10} -- move SecurityAgent window out of the way 
 end tell
 tell application passApp
      activate -- bring 1Password to the forefront, run it if not running
 end tell
 tell application "System Events"
    tell application "SystemUIServer"
      set answer to display dialog "Make sure correct 1Password item is actively selected (i.e. click it again if it was previously selected), then click “Continue” to proceed." buttons {"Continue"}
    end tell
    tell process passApp
    (* If you are not using 1Password, you may need to change the menu item clicks, below, to whatever is correct in your particular password manager *)
        click menu item "copy password" of menu "item" of menu bar 1
        delay 1
        set appData to the clipboard
    end tell
    tell application "System Events"
        tell process appName
            set value of text field 1 of window 1 to appData
            if exists (text field 2 of window 1) then
                set value of text field 2 of window 1 to appData
                click button 1 of window 1
            else
                click button 2 of window 1
            end if
         end tell
     end tell
end tell

I made the whole script conditional on the presence of SecurityAgent, because this script will be assigned to a keyboard shortcut, and if that key combination is inadvertently selected by the user, I'd rather they not be bothered with an unexpected script process.

If there are ways in which I could refine or improve this solution, please advise. I am very happy to be learning more about AppleScript.

FINAL UPDATES: Had to make one final change. It turned out the button numbers for CANCEL and OK change around from the SecurityAgent instance for creating an encrypted disk/disk-image, and for when opening an encrypted disk/disk-image. So I had to modify the IF THEN statement right near the end to handle each scenario.

8
  • the reason you are getting issue with 1Password not activating is because you are telling it inside of a system events tell block. Take it out of that and put it above the start of the system events tell block.
    – markhunte
    Commented Mar 8, 2015 at 10:30
  • I think I ended up doing it that way because I was having trouble making the whole script conditional with the IF THEN statement I've used. From what I recall, testing IF the SecurityAgent process window exists only worked if it occurred within a tell application "system events" section. Is there another way I would go about making the entire script conditional on that, without having to wrap everything within the tell application "system events" section? For instance, is there such as a thing as IF THEN ABORT ?
    – inspirednz
    Commented Mar 8, 2015 at 21:32
  • Then at the beginning of the script I could simply test if the SecurityAgent window exists, and if not, then terminate the script.
    – inspirednz
    Commented Mar 8, 2015 at 22:03
  • see my update to my answer. I just remembered that you can use 'activate application app name' in the system events block and it will behave as expected. Also shown if not then return.
    – markhunte
    Commented Mar 8, 2015 at 22:20
  • Figured it out. I can use a RETURN statement to abort the script. I have adjusted my answer above accordingly.
    – inspirednz
    Commented Mar 8, 2015 at 22:25
1

To stop the error you are getting you need to take out the 'of group' part of the click command.

(Tested by creating a encrypted dmg)

You do not need it and that is why you get the error.

The Buttons are 1 and 2.

1 will be cancel. 2 will be ok

So you will need to change the button you are calling also.

    set theData to (the clipboard)

set appName to "SecurityAgent"

tell application "System Events"
    if exists window 1 of process appName then (* only continue if process is running. If it is not it will not have a window *)
        tell process appName

            set value of text field 1 of window 1 to theData
            if exists (text field 2 of window 1) then
                set value of text field 2 of window 1 to theData
            end if
            click button 2 of window 1
     end tell
    end if
end tell

Update:

In answer to the OP's questions in comments and use their code snippet this edit shows how to activate

1passowrd and use if not then with a return to cancel the script on conditions that a window does not exist.

    set appName to "SecurityAgent"
set passApp to "1Password 5" (* set this to the name of your password manager *)
tell application "System Events"
    if not (exists window 1 of process appName) then (* only continue if process is running. If it is not it will not have a window *)

        return (* The return ends the script run here*)

    end if

end tell
activate application passApp
tell application "System Events"
    set position of window 1 of process appName to {10, 10}

    tell application "SystemUIServer"
        set answer to display dialog "Make sure correct 1Password item is actively selected (i.e. click it again if it was previously selected), then click “Continue” to proceed." buttons {"Continue"}
    end tell

    tell application "System Events"
        tell process passApp
            (* If you are not using 1Password, you may need to change the menu item clicks, below, to whatever is correct in your particular password manager *)
            click menu item "copy password" of menu "item" of menu bar 1
            delay 1
            set appData to the clipboard
        end tell
        tell process appName
            set value of text field 1 of window 1 to appData
            if exists (text field 2 of window 1) then
                set value of text field 2 of window 1 to appData
            end if
            click button 2 of window 1
        end tell
    end tell

end tell
4
  • Thanks. Works great. I tried adding in script to first obtain the password, using tell application "System Events" tell process "1Password 5" click menu item "copy password" of menu "item" of menu bar 1 end tell end tell but somehow the resulting clipboard data does not get assigned to theData. Rather any previous clipboard data is assigned to theData. Which means that if I run the script a second time, then the correct data will end up in theData, but only because it was copied into clipboard the first time around. Any suggestions why that might be?
    – inspirednz
    Commented Mar 8, 2015 at 1:36
  • Looks like the above mentioned issue with the password being picked up is because the script was moving to fast. I added a 1 second delay, and the problem is solved. Will post the resulting script as a new Answer.
    – inspirednz
    Commented Mar 8, 2015 at 2:13
  • Same issue is occurring. I want to use the variable passApp for all instances of "1Password 5". But activate application passApp does not work when within the tell application "system events" block. No idea why not. The solution I updated in my Answer below seems to do the trick.
    – inspirednz
    Commented Mar 8, 2015 at 22:40
  • Which is what I normally would do and suggested before. But silly me forgot that 1password was already running and that why 'activate application app name' worked. doh. will edit again.
    – markhunte
    Commented Mar 8, 2015 at 22:50
0

I don't have anything to test it on, so this is a pure guess.

Maybe the app isn't frontmost at that point, so this might help

tell process "SecurityAgent" to activate (*this will bring it to the front if it's already running*)
    --tell application "System Events" (*try with & without this - you'll need to balance up the end tells at the end*)
    set value of text field 1 of window 1 to (the clipboard)
    if exists (text field 2 of window 1) then
        set value of text field 2 of window 1 to (the clipboard)
    end if
    click button 1 of group 1 of window 1
    -- end tell (* uncomment to balance tell blocks if using the above System Events*)

I'm not certain whether you need System Events to do that task, or whether you could simply direct the output at SecurityAgent itself.

BTW, there is pretty much always data in the clipboard, so testing for that would not really help - without noting the actual password in the script [insecure, of course] there is no way I can see to test if it matches the correct data.

3
  • You do not need to activate the window as you are telling the process to do stuff other then keystrokes. You will also need "System Events" to tell the process..
    – markhunte
    Commented Mar 7, 2015 at 12:49
  • Thanks for this. I have a slight hurdle. I get the error, - Expected end of line but found “"”. - A number of times I got the same error when I was playing around with the script I was already working on. But I had no idea why this error comes up, as the syntax looked identical to other scripts I have on hand. Any ideas? In this instance, the error is referring to the first instance of " just before SecurityAgent.
    – inspirednz
    Commented Mar 7, 2015 at 23:25
  • ahh… tell application, not process
    – Tetsujin
    Commented Mar 8, 2015 at 8:08

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .