improve otp menu

This commit is contained in:
Joakim Repomaa
2025-10-09 19:33:48 +03:00
parent 6fdde36bd8
commit 157efae198
4 changed files with 126 additions and 20 deletions

View File

@@ -18,7 +18,7 @@ lib.composeManyExtensions (
dir:
import ./${dir} {
util = util dir;
inherit inputs pkgs-unstable;
inherit inputs lib pkgs-unstable;
}
) dirs
)

View File

@@ -1 +1,7 @@
{ util, pkgs-unstable, ... }: util.package { inherit pkgs-unstable; }
{
util,
pkgs-unstable,
lib,
...
}:
util.package { inherit pkgs-unstable lib; }

96
custom-pkgs/otp/otp.cr Normal file
View File

@@ -0,0 +1,96 @@
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

View File

@@ -1,18 +1,22 @@
{ pkgs, pkgs-unstable }:
let
yubikey-manager = pkgs-unstable.yubikey-manager;
ykman = "${yubikey-manager}/bin/ykman";
sk = "${pkgs.skim}/bin/sk";
wl-copy = "${pkgs.wl-clipboard}/bin/wl-copy";
in
pkgs.writeShellScriptBin "otp" ''
skim_command=("${sk}")
if [ -n "$*" ]; then
skim_command+=(-q "$*")
fi
account=$(${ykman} oath accounts list | "''${skim_command[@]}")
[ -z "$account" ] && exit 1
${ykman} oath accounts code -s "$account" | ${wl-copy} -n
''
{
pkgs,
lib,
pkgs-unstable,
}:
pkgs.runCommand "otp"
{
code = ./otp.cr;
env = {
YKMAN = lib.getExe pkgs-unstable.yubikey-manager;
SKIM = lib.getExe pkgs.skim;
WALKER = lib.getExe pkgs-unstable.walker;
WL_COPY = lib.getExe' pkgs.wl-clipboard "wl-copy";
NOTIFY_SEND = lib.getExe pkgs.libnotify;
NOTIFY_ICON = "${pkgs-unstable.yubioath-flutter}/share/pixmaps/com.yubico.yubioath.png";
};
nativeBuildInputs = [ pkgs.crystal ];
}
''
mkdir -p $out/bin
crystal build $code --release -o $out/bin/otp
''