require "option_parser" require "yaml" require "colorize" # password serializer class Password include YAML::Serializable @[YAML::Field(key: "url")] property url : String @[YAML::Field(key: "email")] property email : String @[YAML::Field(key: "login")] property login : String @[YAML::Field(key: "password")] property password : String @[YAML::Field(key: "desc")] property desc : String @[YAML::Field(key: "profile_url")] property profile_url : String @[YAML::Field(key: "update")] property update : Int32 end VERSION = "0.2.2" # program options begin OptionParser.parse do |parser| parser.banner = "The very simple password manager for humans\n" parser.on "-v", "--version", "Show version" do puts "The very simple password manager for humans." puts "Version #{VERSION}" exit(0) end parser.on "-h", "--help", "Show help" do puts parser exit(0) end parser.on "-g", "--generate-password", "Generate password" do puts Random::Secure.urlsafe_base64(16, padding: false).colorize(:black).back(:white) puts Random::Secure.urlsafe_base64(16, padding: false).colorize(:white).back(:blue) puts Random::Secure.urlsafe_base64(16, padding: false).colorize(:white).back(:red) exit(0) end parser.on "-t", "--unixtime", "Return local timestamp" do puts Time.local.to_unix.colorize(:yellow).mode(:bold) exit(0) end end rescue ex puts ex.message, "" end # password_file_path = PROGRAM_NAME.split("/") # password_file_path.pop # password_file_path.insert(-1, "pwd.yml") # password_file_path = password_file_path.join("/") # TODO: Fix later password_file_path = "#{ENV["HOME"]}/.pwd.yml" # check password file exists if File.exists?(password_file_path) yaml = File.open(password_file_path) do |file| YAML.parse(file) end else puts "No password.yml file exists." exit(1) end # fill passwords array passwords_array = [] of Password count = 0 while count < yaml.size passwords_array << Password.from_yaml(yaml[count].to_yaml) count += 1 end # check file ppermissions password_file_permissions = File.info(password_file_path).permissions.to_s if /\d{3}/.match(password_file_permissions).try &.[0] != "600" puts "Password file permissions is not RW for you.".colorize(:red) exit(1) end # pmng title system "clear" puts "The very simple password manager for humans".colorize(:yellow).mode(:bold) puts "-------------------------------------------".colorize(:yellow).mode(:bold) # main loop loop = true while loop # shell prompt print "Enter URL (".colorize(:white).mode(:bold) print ":h".colorize(:red).mode(:bold) print " for help or ".colorize(:white).mode(:bold) print ":q".colorize(:red).mode(:bold) print " for exit)\n".colorize(:white).mode(:bold) print "> ".colorize(:green).mode(:bold) password_string = gets if password_string.to_s == ":q" # if ':q' to close program system "clear" puts "Bye! 👋" exit(0) elsif password_string.to_s.size == 0 # if puts empty, retry prompt puts elsif password_string.to_s == ":h" # if ':h' to view help system "clear" puts "Help\n----".colorize(:yellow).mode(:bold) print ":s".colorize(:red).mode(:bold) puts " - Return stats" elsif password_string.to_s == ":s" # if ':s' to view Statistics system "clear" puts "Statistics\n----------".colorize(:yellow).mode(:bold) print "All elements: ".colorize(:yellow).mode(:bold) puts passwords_array.size print "Passwords outdated: ".colorize(:red).mode(:bold) outdated_count = 0 current_time = Time.local.to_unix a = [] of String passwords_array.each do |item| if item.update + (2629743 * 3) < current_time # 2629743 * 3 -- 3 month outdated_count += 1 a << item.url end end puts outdated_count else # list search password system "clear" passwords_array.each do |item| if item.url.includes?(password_string.to_s) print "🌐 " puts item.url.colorize(:magenta).mode(:bold).mode(:underline) if !item.email.blank? print "📧 " puts item.email.colorize(:red) end if !item.login.blank? # print "\u{1F3F7}\u{FE0F} " print "🗿 " puts item.login.colorize(:yellow) end if !item.password.blank? print "🔐 " puts item.password.colorize(:red).back(:red) end if !item.desc.blank? print "📄 " puts item.desc.colorize(:cyan) end if !item.profile_url.blank? print "👦 " puts item.profile_url.colorize(:green) end puts "-----".colorize(:dark_gray).mode(:bold) end end end puts end