auto_login AppleScriptコード

日記の容量の制限で溢れてしまったので、9月26日から分割した。

ログイン情報取得.scpt

  • Safariで表示中のページからログイン情報を取得して、保存する。


set BS to load script POSIX file ((do shell script "dirname " & quoted form of ((path to me)'s POSIX path)) & "/_login_base.scpt")

tell BS
authenticate("●入力された情報を保存します。" & return)

set new_record to record_from(url_key() & ":" & input_tag_json())
if new_record as list = {{}} then error number -128 --強制終了

try
openssl_decode(MASTER_PASS, login_info_path("/"), login_tmp_path("/"))
set current_record to read_file(login_tmp_path(""))

save_file(login_tmp_path(""), new_record & current_record)
openssl_encode(MASTER_PASS, login_tmp_path("/"), login_info_path("/"))

message(paht_to_me_name(), input_tag_json())
end try
remove_file(login_tmp_path("/"))
end tell

自動ログイン.scpt

  • 保存しているログイン情報を基に、自動ログインする。


set BS to load script POSIX file ((do shell script "dirname " & quoted form of ((path to me)'s POSIX path)) & "/_login_base.scpt")

tell BS
authenticate("自動入力します。" & return)

try
openssl_decode(MASTER_PASS, login_info_path("/"), login_tmp_path("/"))
auto_input(login_info_record(url_key()))
end try
remove_file(login_tmp_path("/"))
end tell

_login_base.scpt

  • ログイン情報取得.scpt、自動ログイン.scpt等、auto_loginフォルダ内のスクリプトの基本となるハンドラ(メソッド)の集合体。


(* _login_base.scptのロード方法
基本(スクリプトフォルダ限定)
set BS to load script file ((path to scripts folder as text) & "auto_login:_login_base.scpt") Finder活用バージョン(再配置可能)
tell application "Finder" to set BS to load script file (((path to me)'s folder as text) & "_login_base.scpt") シェルスクリプト活用バージョン(再配置可能)
set BS to load script POSIX file ((do shell script "dirname " & quoted form of ((path to me)'s POSIX path)) & "/_login_base.scpt") property parent : load script file... -- 可能(OK
set parent to load script file... -- 不可能(NG
*)
global MASTER_PASS
global PS



--スターパスワードの設定と認証を必要に応じて処理する
on authenticate(msg) tell application "Finder" to set PS to load script file (((path to me)'s folder as text) & "_login_pass.scpt") if PS's MASTER_PASS_SHA1 = "" then
save_master_password(msg) else
authenticate_password(msg) end if
end authenticate

--スターパスワードの設定
on save_master_password(msg) repeat
activate
msg & "マスターパスワードを登録してください。"
set res1 to display dialog result default answer "" with title paht_to_me_name() with hidden answer
activate
"確認のため、もう一度入力してください。"
set res2 to display dialog result default answer "" with title paht_to_me_name() with hidden answer
if res1's text returned = res2's text returned then
set PS's MASTER_PASS_SHA1 to sha1(res1's text returned) set MASTER_PASS to res1's text returned
store script PS in POSIX file ((do shell script "dirname " & quoted form of ((path to me)'s POSIX path)) & "/_login_pass.scpt") replacing yes --プロパティを保存するため
exit repeat
else
beep
activate
"パスワードが一致しません。\nもう一度最初からやり直してください。"
display dialog result with title paht_to_me_name() with icon 0
end if
end repeat
end save_master_password

--スターパスワードの認証
on authenticate_password(msg) repeat
activate
msg & "パスワードを入力してください。"
set res to display dialog result default answer "" with title paht_to_me_name() with hidden answer
if sha1(res's text returned) = PS's MASTER_PASS_SHA1 then
set MASTER_PASS to res's text returned
exit repeat
else
beep
activate
"パスワードが違っています。"
display dialog result with title paht_to_me_name() with icon 0
end if
end repeat
end authenticate_password

--strに対応するsha1ハッシュを返す
on sha1(str) do shell script "echo " & str & "|openssl dgst -sha1"
end sha1



--urla_key)をキーにしたログイン情報(各フォームの値)を返す
on login_info_record(a_key) try
run script "(read file (((path to temporary items) as text) & \"_login.tmp\") as record)'s " & a_key
on error msg number num
if num = -50 then display dialog "パスワードが違っています。" & tab & num
if num = -1728 then display dialog "このページでは自動ログインできません。" & tab & num
error number -128 --強制終了
end try
end login_info_record

--ログイン情報(a_record)を基にフォームに値を自動入力する
on auto_input(a_record) tell application "Safari"
activate
repeat with r in a_record
if r's type = "text" or r's type = "password" then
do JavaScript "document.getElementsByName(" & quoted form of r's name & ")[0].value = " & quoted form of r's value in document 1
else if r's type = "radio" or r's type = "checkbox" then
do JavaScript "document.getElementsByTagName('input')[" & r's index & "].checked = " & r's checked in document 1
else if r's type = "option" then
if (do JavaScript "document.getElementsByTagName('option')[" & r's index & "].value" in document 1) = r's value then
do JavaScript "document.getElementsByTagName('option')[" & r's index & "].selected = " & r's selected in document 1
end if
end if
end repeat
end tell
end auto_input

--現在表示中のページからログイン情報をjsonAppleScriptのレコード形式のテキスト)で返す
on input_tag_json() tell application "Safari"
--text || password のみ取得する
--do JavaScript "var s=[]; var inputs=document.getElementsByTagName('input'); for(i=0;i<inputs.length;i++){if(inputs[i].type=='text'||inputs[i].type=='password'){s.push('{type: \"'+inputs[i].type+'\", name: \"'+inputs[i].name+'\", value: \"'+inputs[i].value+'\")};} '{'+s.join(',')+'}';" in document 1
--hidden以外 && image以外 を取得する
--do JavaScript "var s=[]; var inputs=document.getElementsByTagName('input'); for(i=0;i<inputs.length;i++){if(inputs[i].type!='hidden'&&inputs[i].type!='image'){s.push('{type: \"'+inputs[i].type+'\", name: \"'+inputs[i].name+'\", value: \"'+inputs[i].value+'\", checked: \"'+inputs[i].checked+'\", index: \"'+i+'\"}');}} '{'+s.join(',')+'}';" in document 1
--optionタグも取得する
do JavaScript "var s=[]; var inputs=document.getElementsByTagName('input'); var options=document.getElementsByTagName('option'); for(i=0;i<inputs.length;i++){if(inputs[i].type!='hidden'&&inputs[i].type!='image'){s.push('{type: \"'+inputs[i].type+'\", name: \"'+inputs[i].name+'\", value: \"'+inputs[i].value+'\", checked: \"'+inputs[i].checked+'\", index: \"'+i+'\"}');}} for(i=0;i<options.length;i++){if(options[i].selected){s.push('{type: \"option\", name: \"'+options[i].name+'\", value: \"'+options[i].value+'\", selected: \"'+options[i].selected+'\", index: \"'+i+'\"}');}} '{'+s.join(',')+'}';" in document 1
end tell
end input_tag_json

--aes-128-cbc形式のデータに暗号化する
on openssl_encode(pw, in_path, out_path) do shell script "openssl enc -e -aes-128-cbc -pass pass:" & pw & " <" & in_path & " >" & out_path
end openssl_encode

--aes-128-cbc形式のデータを復号化する
on openssl_decode(pw, in_path, out_path) try
do shell script "openssl enc -d -aes-128-cbc -pass pass:" & pw & " <" & in_path & " >" & out_path
on error msg number num
if num = 1 then
do shell script "touch " & in_path
do shell script "touch " & out_path
else
error msg number num
end if
end try
end openssl_decode

--ログイン情報_login.infoのパスを返す
-- flag=="/"UNIX形式のパス
-- flag=""AppleScript形式のパス
on login_info_path(flag) tell application "Finder"
if flag = "/" then
(((path to me)'s folder as text) & "_login.info")'s POSIX path
else
((path to me)'s folder as text) & "_login.info"
end if
end tell
end login_info_path

--ログイン情報を復号化した一時ファイルのパスを返す
on login_tmp_path(flag) if flag = "/" then
((path to temporary items as text) & "_login.tmp")'s POSIX path
else
(path to temporary items as text) & "_login.tmp"
end if
end login_tmp_path

--自分自身の名前を返す
on paht_to_me_name() tell application "Finder"
((path to me)'s name) end tell
end paht_to_me_name

--ログイン情報(レコード形式)を保存する
on save_file(file_path, a_data) set flag to false
try
set f to open for access file file_path with write permission
write a_data to f
set flag to true
end try
close access f
flag
end save_file

--ログイン情報(レコード形式)を読み込む
on read_file(file_path) try
read file file_path as record
on error
{} end try
end read_file

--ファイルを削除する
on remove_file(file_path) try
do shell script "rm " & file_path
end try
end remove_file

--現在表示中のページのurlをレコードのキー値に変換する
on url_key() tell application "Safari"
set url_info to do JavaScript "document.location" in document 1
end tell
""
result & (do shell script "echo " & quoted form of url_info's origin & "|tr -C '[:alpha:]' '_'") result & (do shell script "echo " & quoted form of url_info's pathname & "|tr -C '[:alnum:]' '_'") end url_key

--json形式のテキストをレコードに変換する
on record_from(json_list) run script "{" & my join(json_list, ",") & "}"
end record_from

--リストをテキストに変換する(delimiterを区切り記号とする)
on join(sourceList, delimiter) set oldDelimiters to AppleScript's text item delimiters
set AppleScript's text item delimiters to delimiter
set theText to sourceList as text
set AppleScript's text item delimiters to oldDelimiters
return theText
end join

--growlでメッセージを表示する(growlnotifyがインストールされていない時はdisplay dialogを利用して表示する)
on message(title, msg) try
do shell script "/usr/local/bin/growlnotify -a " & quoted form of (my name as text) & " -m " & quoted form of msg & space & quoted form of title & " 2>&1"
if result is not "" then error number -128
on error
activate
display dialog msg buttons {"OK"} default button "OK" with title title with icon note giving up after 4 --with icon note caution stop
end try
end message

--エスケープのエスケープを返す
(* on escape(str) do shell script "echo " & quoted form of str & "|sed -e 's/\\\"/\\\\\\\"/g'" end escape *)

_login_pass.scpt

_login.info

  • 各ページのログイン情報のレコードが、aes-128-cbcで暗号化されている。

パスワードリセット

  • スターパスワードを変更する。変更時に上記 _login.info の暗号化キーも変更して保存し直している。


set BS to load script POSIX file ((do shell script "dirname " & quoted form of ((path to me)'s POSIX path)) & "/_login_base.scpt")
set PS to load script POSIX file ((do shell script "dirname " & quoted form of ((path to me)'s POSIX path)) & "/_login_pass.scpt")

tell BS
if PS's MASTER_PASS_SHA1 = "" then
authenticate("スターパスワードが未設定です。" & return)
else
authenticate("スターパスワードをリセットします。" & return & "現在の")
try
openssl_decode(MASTER_PASS, login_info_path("/"), login_tmp_path("/"))
set current_record to read_file(login_tmp_path(""))

remove_file(login_tmp_path("/"))
save_master_password("新しい")

save_file(login_tmp_path(""), current_record)
openssl_encode(MASTER_PASS, login_tmp_path("/"), login_info_path("/"))

message(paht_to_me_name(), "スターパスワードのリセットが完了しました。")
end try
remove_file(login_tmp_path("/"))
end if
end tell

show_login_info.scpt

  • 上記ログイン情報_login.infoの内容をレコードとして表示する。(開発・メンテナンス用)

edit_login_info.scpt

  • show_login_info.scptで表示したログイン情報を編集して保存する。(開発・メンテナンス用)
  • 注意:使い方によっては _login.info が壊れて、せっかくのログイン情報が読めなくなる可能性あり。