97 lines
2.5 KiB
Crystal
97 lines
2.5 KiB
Crystal
require "option_parser"
|
|
|
|
NOTIFY_ICON = {{env("NOTIFY_ICON")}}
|
|
NOTIFY_SEND_COMMAND = {{env("NOTIFY_SEND")}}
|
|
WL_COPY_COMMAND = {{env("WL_COPY")}}
|
|
YKMAN_COMMAND = {{env("YKMAN")}}
|
|
SKIM_COMMAND = {{env("SKIM")}}
|
|
WALKER_COMMAND = {{env("WALKER")}}
|
|
|
|
class OTP
|
|
private property dmenu_command : String = SKIM_COMMAND
|
|
private property dmenu_args = [] of String
|
|
|
|
def run
|
|
parser = OptionParser.new do |opts|
|
|
opts.banner = "Usage: #{PROGRAM_NAME} [options]"
|
|
|
|
opts.on("-h", "--help", "Display this help message") do
|
|
puts opts
|
|
exit
|
|
end
|
|
|
|
opts.on("-w", "--walker", "Use walker as dmenu") do
|
|
self.dmenu_command = WALKER_COMMAND
|
|
self.dmenu_args << "--dmenu" << "-p" << "Select account:"
|
|
end
|
|
end
|
|
|
|
parser.parse
|
|
|
|
self.dmenu_args += ["-q", *ARGV] unless ARGV.empty?
|
|
|
|
account = select_account
|
|
code = code_for(account)
|
|
copy(code)
|
|
end
|
|
|
|
private def notify_send(message, urgency = :normal)
|
|
return if message.chomp.empty?
|
|
|
|
Process.run(NOTIFY_SEND_COMMAND, ["-i", NOTIFY_ICON, "-u", urgency.to_s, "OTP", message.chomp])
|
|
end
|
|
|
|
private def list_accounts
|
|
error = IO::Memory.new
|
|
output = IO::Memory.new
|
|
status = Process.run(YKMAN_COMMAND, %w[oath accounts list], output: output, error: error)
|
|
errors = error.rewind.gets_to_end.try(&.chomp)
|
|
notify_send(errors, urgency: status.success? ? :normal : :critical) unless errors.empty?
|
|
exit status.exit_code unless status.success?
|
|
|
|
output.rewind.gets_to_end
|
|
end
|
|
|
|
private def select_account
|
|
output = IO::Memory.new
|
|
accounts = list_accounts
|
|
puts accounts
|
|
input = IO::Memory.new(accounts)
|
|
Process.run(dmenu_command, dmenu_args, output: output, input: input)
|
|
|
|
account = output.rewind.gets(chomp: true)
|
|
return account if account
|
|
|
|
notify_send("No account selected", urgency: :critical)
|
|
exit 1
|
|
end
|
|
|
|
private def code_for(account)
|
|
output = IO::Memory.new
|
|
|
|
Process.run(YKMAN_COMMAND, ["oath", "accounts", "code", "-s", account], output: output) do |process|
|
|
spawn do
|
|
while line = process.error.gets(chomp: true)
|
|
notify_send(line)
|
|
end
|
|
end
|
|
end
|
|
|
|
exit $?.exit_code unless $?.success?
|
|
|
|
code = output.rewind.gets(chomp: true)
|
|
return code if code
|
|
|
|
notify_send("No code generated", urgency: :critical)
|
|
exit 1
|
|
end
|
|
|
|
private def copy(code)
|
|
input = IO::Memory.new(code)
|
|
Process.run(WL_COPY_COMMAND, %w[-n], input: input)
|
|
notify_send("Copied to clipboard")
|
|
end
|
|
end
|
|
|
|
OTP.new.run
|