Skip to content

Instantly share code, notes, and snippets.

@anshdivu
Created November 1, 2023 22:19
Show Gist options
  • Save anshdivu/264aab8521b47cde15de05a38fd3346a to your computer and use it in GitHub Desktop.
Save anshdivu/264aab8521b47cde15de05a38fd3346a to your computer and use it in GitHub Desktop.
local MAC_USER_ID = "db880u"
local AUTH_METHOD = "2" -- code 2 is for push notification
local SHORTCUT_HOTKEY = "F1"
-- command => osascript -e 'id of app "Cisco AnyConnect Secure Mobility Client"'
-- local CISCO_BUNDLE_ID = 'com.cisco.Cisco-AnyConnect-Secure-Mobility-Client' -- vpn version <=4.6
local CISCO_BUNDLE_ID = 'com.cisco.anyconnect.gui' -- vpn version >=4.9
local function fetchPassword(userId)
-- when you run this command the first time it will require your admin password to read keychain
return hs.execute("security find-generic-password -w -g -a " .. userId)
end
local function restartApp(bundleId, runAfterStartFn)
local appTerminated = hs.application.watcher.terminated
local app = hs.application.get(bundleId)
if not app then
local newApp = hs.application.open(bundleId, 0, true)
return runAfterStartFn(newApp)
end
local appPid = app:pid()
print("**** Killing running app: ", appPid, app)
app:kill()
hs.application.watcher.new(function(appName, eventType, app)
if (eventType == appTerminated and app:pid() == appPid) then
local newApp = hs.application.open(bundleId, 0, true)
runAfterStartFn(newApp)
end
end):start()
end
local function trackCiscoDialogs(ciscoDialogs)
local dialogNum = 0
return function(dialog)
if ciscoDialogs[dialog] then
return
end
dialogNum = dialogNum + 1
if dialogNum == 1 then
print("**** Found password dialog: ", dialogNum, dialog)
ciscoDialogs[dialog] = "password"
elseif dialogNum == 2 then
print("**** Found mfa dialog: ", dialogNum, dialog)
ciscoDialogs[dialog] = "mfa"
elseif dialogNum == 3 then
print("**** Found Accept dialog: ", dialogNum, dialog)
ciscoDialogs[dialog] = "accept"
else
print("**** Found UNKNOWN dialog: ", dialogNum, dialog)
ciscoDialogs[dialog] = "UNKNOWN_" .. dialogNum
end
end
end
local function vpnSignInFlow(userId, ciscoDialogs)
return function(dialog)
local type = ciscoDialogs[dialog]
if type == "password" then
print("**** Focused on password dialog")
local password = fetchPassword(userId)
hs.eventtap.keyStrokes(password)
elseif type == "mfa" then
print("**** Focused on mfa dialog")
hs.eventtap.keyStrokes(AUTH_METHOD)
hs.eventtap.keyStroke({}, "return")
elseif type == "accept" then
print("**** Focused on accept dialog")
hs.eventtap.keyStroke({}, "return")
else
print("**** Correct Dialog Not Found: ", type, dialog)
end
end
end
hs.hotkey.bind({}, SHORTCUT_HOTKEY, function()
restartApp(CISCO_BUNDLE_ID, function(ciscoApp)
print("**** Started Cisco App: ", ciscoApp:pid(), ciscoApp)
local filter = hs.window.filter.new {
[ciscoApp:name()] = {
allowRoles = 'AXDialog'
}
}
local ciscoDialogs = {}
filter:subscribe(hs.window.filter.windowCreated, trackCiscoDialogs(ciscoDialogs))
filter:subscribe(hs.window.filter.windowFocused, vpnSignInFlow(MAC_USER_ID, ciscoDialogs))
end)
end)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment