diff --git a/custom-pkgs/default.nix b/custom-pkgs/default.nix index 576d568..ba7207b 100644 --- a/custom-pkgs/default.nix +++ b/custom-pkgs/default.nix @@ -18,7 +18,7 @@ lib.composeManyExtensions ( dir: import ./${dir} { util = util dir; - inherit inputs pkgs-unstable; + inherit inputs lib pkgs-unstable; } ) dirs ) diff --git a/custom-pkgs/otp/default.nix b/custom-pkgs/otp/default.nix index 84e5e76..c82c25b 100644 --- a/custom-pkgs/otp/default.nix +++ b/custom-pkgs/otp/default.nix @@ -1 +1,7 @@ -{ util, pkgs-unstable, ... }: util.package { inherit pkgs-unstable; } +{ + util, + pkgs-unstable, + lib, + ... +}: +util.package { inherit pkgs-unstable lib; } diff --git a/custom-pkgs/otp/otp.cr b/custom-pkgs/otp/otp.cr new file mode 100644 index 0000000..863bf11 --- /dev/null +++ b/custom-pkgs/otp/otp.cr @@ -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 diff --git a/custom-pkgs/otp/package.nix b/custom-pkgs/otp/package.nix index 489fc19..0cfc6e3 100644 --- a/custom-pkgs/otp/package.nix +++ b/custom-pkgs/otp/package.nix @@ -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 + ''