Compare commits
No commits in common. "master" and "5d7fca409641214159fba40efd28590e420dfab5" have entirely different histories.
master
...
5d7fca4096
BIN
.docs/logo.png
BIN
.docs/logo.png
Binary file not shown.
Before Width: | Height: | Size: 15 KiB |
Binary file not shown.
Before Width: | Height: | Size: 34 KiB |
@ -13,6 +13,3 @@ indent_size = 2
|
||||
[{*.ecr,*.json}]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
[README.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,6 +1,10 @@
|
||||
/docs/
|
||||
/dist/
|
||||
/lib/
|
||||
/bin/
|
||||
/.shards/
|
||||
*.dwarf
|
||||
|
||||
/src/views/
|
||||
|
||||
data.json
|
||||
pwd.yml
|
||||
|
51
HISTORY.md
51
HISTORY.md
@ -1,51 +0,0 @@
|
||||
## Legend
|
||||
- 🐛 - Bug
|
||||
- ✔️ - Fixed
|
||||
- ❌ - Removed
|
||||
- ➕ - Added
|
||||
- ℹ️ - Information
|
||||
- ♻️ - Edited
|
||||
|
||||
## 0.2.7b - [14/04/2023]
|
||||
- ➕ - Added environment variable for custom input timeout
|
||||
- ✔️ - User input is converted to lowercase
|
||||
|
||||
## 0.2.6 - [03/08/2022]
|
||||
- ➕ - Added environment variable for custom password file path
|
||||
- ➕ - Added version in to ASCII logo
|
||||
|
||||
## 0.2.5 - [31/07/2022]
|
||||
- ➕ - Added timeout user input
|
||||
- ♻️ - Source file separated
|
||||
|
||||
## 0.2.4 - [26/07/2022]
|
||||
- ➕ - Added hint for fix file permissions error.
|
||||
- ℹ️ - Crystal version raise to 1.5.0 for NO_COLOR support
|
||||
- ✔️ - Fixed output finding records for all queryes
|
||||
- ✔️ - Fixed check password file name info
|
||||
|
||||
## 0.2.3 - [02/05/2022]
|
||||
- ♻️ - Password outdated date change to 3 month
|
||||
- ➕ - Added `pmng` logo
|
||||
- ➕ - Added show count finded records
|
||||
- ➕ - Added colors to help output
|
||||
|
||||
## 0.2.2 - [08/04/2022]
|
||||
- ➕ - Added check permissions for password file
|
||||
- ➕ - Added title by start program
|
||||
- ➕ - Added terminal cleaning functionality
|
||||
- ➕ - Added help tips to user prompt
|
||||
- ➕ - Added emoji for output
|
||||
- ➕ - Added colors for help sections
|
||||
- ✔️ - Fixed bug on bye emoji color
|
||||
- ♻️ - Edited color & style for data output
|
||||
- 🐛 - After emoji label not view space symbol (emoji temporary changed)
|
||||
|
||||
## 0.2.1 - [14/03/2022]
|
||||
- ➕ - prompt '>' set color green
|
||||
- ♻️ - change default pwd path to '$HOME/.pwd.yml'
|
||||
- ✔️ - fixed empty search field
|
||||
- ✔️ - fixed password generate colors to russian flag
|
||||
|
||||
## 0.2.0 - [04/01/2022]
|
||||
- reading passwords file from program folder (portable mode)
|
16
README.md
16
README.md
@ -1,15 +1 @@
|
||||
# 🔑 The very simple password manager for humans
|
||||
|
||||
![Crystal](https://img.shields.io/badge/Crystal-000000?style=for-the-badge&color=000000&logo=crystal)
|
||||
![License](https://img.shields.io/badge/license-public_domain-brightgreen?style=for-the-badge&color=ffcc68)
|
||||
![NO_COLOR](https://img.shields.io/badge/no__color-support-brightgreen?style=for-the-badge&color=d44e52)
|
||||
![Emoji](https://img.shields.io/badge/emoji-like-brightgreen?style=for-the-badge&color=ec8a4b)
|
||||
[![Download](https://img.shields.io/badge/Download-brightgreen?style=for-the-badge&color=38607c)](#download)
|
||||
|
||||
## 📷 Screenshots
|
||||
|
||||
See [SCREENSHOTS.md](SCREENSHOTS.md).
|
||||
|
||||
## 💾 Download
|
||||
|
||||
[![Linux x86_64](https://img.shields.io/badge/linux-x86--64-brightgreen?style=for-the-badge&color=55a894)](https://data.iiiypuk.me/pmng/alpha/pmng-0.2.6-linux-x86_64.tar.xz)
|
||||
# passw0rd_manager
|
||||
|
@ -1,5 +0,0 @@
|
||||
## 📷 Screenshots
|
||||
|
||||
![pmng](./.docs/logo.png)
|
||||
|
||||
![Passwords](./.docs/passwords.png)
|
@ -1,25 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Preparing
|
||||
if [ -d "./dist/" ];
|
||||
then
|
||||
rm dist/* 2> /dev/null
|
||||
else
|
||||
mkdir dist/
|
||||
fi
|
||||
|
||||
# Detect Musl C library
|
||||
# thx @Unmanned Player https://stackoverflow.com/a/60471114
|
||||
|
||||
libc=$(ldd /bin/ls | grep 'musl' | head -1 | cut -d ' ' -f1)
|
||||
if [ -z $libc ];
|
||||
then
|
||||
# build libc
|
||||
OUTPUT=pmng-$(shards version)-linux-x86_64
|
||||
crystal build ./src/pmng.cr --release --progress -o ./dist/$OUTPUT
|
||||
tar -cJf ./dist/$OUTPUT.tar.xz ./dist/$OUTPUT
|
||||
else
|
||||
# Build musl
|
||||
crystal build ./src/pmng.cr --release --progress -o ./dist/pmng-$(shards version)-linux-musl-x86_64
|
||||
fi
|
||||
|
@ -1,6 +1,2 @@
|
||||
version: 2.0
|
||||
shards:
|
||||
ameba:
|
||||
git: https://github.com/crystal-ameba/ameba.git
|
||||
version: 1.4.3
|
||||
|
||||
shards: {}
|
||||
|
15
shard.yml
15
shard.yml
@ -1,18 +1,15 @@
|
||||
name: pmng
|
||||
version: 0.2.7
|
||||
name: passw0rd_manager
|
||||
version: 0.1.0
|
||||
|
||||
authors:
|
||||
- Alexander Popov <iiiypuk@iiiypuk.me>
|
||||
|
||||
targets:
|
||||
pmng:
|
||||
main: src/pmng.cr
|
||||
passw0rd_manager:
|
||||
main: src/passw0rd_manager.cr
|
||||
|
||||
development_dependencies:
|
||||
ameba:
|
||||
github: crystal-ameba/ameba
|
||||
version: ~> 1.4.0
|
||||
dependencies:
|
||||
|
||||
crystal: 1.7.0
|
||||
crystal: 1.2.2
|
||||
|
||||
license: MIT
|
||||
|
9
spec/passw0rd_manager_spec.cr
Normal file
9
spec/passw0rd_manager_spec.cr
Normal file
@ -0,0 +1,9 @@
|
||||
require "./spec_helper"
|
||||
|
||||
describe Passw0rdManager do
|
||||
# TODO: Write tests
|
||||
|
||||
it "works" do
|
||||
false.should eq(true)
|
||||
end
|
||||
end
|
@ -1,2 +1,2 @@
|
||||
require "spec"
|
||||
require "../src/pmng"
|
||||
require "../src/passw0rd_manager"
|
||||
|
125
src/passw0rd_manager.cr
Normal file
125
src/passw0rd_manager.cr
Normal file
@ -0,0 +1,125 @@
|
||||
require "option_parser"
|
||||
require "yaml"
|
||||
require "colorize"
|
||||
|
||||
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.1.0"
|
||||
|
||||
begin
|
||||
OptionParser.parse do |parser|
|
||||
parser.banner = "Welcome to The Beatles App!"
|
||||
|
||||
parser.on "-v", "--version", "Show version" do
|
||||
puts "Version #{VERSION}"
|
||||
exit
|
||||
end
|
||||
parser.on "-h", "--help", "Show help" do
|
||||
puts parser
|
||||
exit
|
||||
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(:red)
|
||||
puts Random::Secure.urlsafe_base64(16, padding: false).colorize(:white).back(:blue)
|
||||
exit
|
||||
end
|
||||
parser.on "-t", "--unixtime", "Return local timestamp" do
|
||||
puts Time.local.to_unix.colorize(:yellow)
|
||||
exit
|
||||
end
|
||||
end
|
||||
rescue ex
|
||||
puts ex.message, ""
|
||||
end
|
||||
|
||||
if !File.exists?("pwd.yml")
|
||||
puts "No password.yml file exists."
|
||||
|
||||
exit(1)
|
||||
end
|
||||
|
||||
yaml = File.open("pwd.yml") do |file|
|
||||
YAML.parse(file)
|
||||
end
|
||||
|
||||
new_array = [] of Password
|
||||
count = 0
|
||||
while count < yaml.size
|
||||
new_array << Password.from_yaml(yaml[count].to_yaml)
|
||||
count += 1
|
||||
end
|
||||
|
||||
while true
|
||||
print "Enter URL (or :q for exit)\n> "
|
||||
password_string = gets
|
||||
|
||||
if password_string.to_s == ":q"
|
||||
puts "Bye! 👋🏻"
|
||||
exit
|
||||
elsif password_string.to_s == ":h"
|
||||
puts "Help:\n-----"
|
||||
puts ":s - Return stats"
|
||||
|
||||
elsif password_string.to_s == ":s"
|
||||
puts "Statictics:\n----------"
|
||||
print "Elements: ".colorize(:yellow)
|
||||
puts new_array.size
|
||||
|
||||
print "Outdated: ".colorize(:red)
|
||||
outdated_count = 0
|
||||
current_time = Time.local.to_unix
|
||||
a = [] of String
|
||||
new_array.each do |item|
|
||||
if item.update + (2629743 * 2) < current_time # 2629743 * 2 -- 2 month
|
||||
outdated_count += 1
|
||||
a << item.url
|
||||
end
|
||||
end
|
||||
|
||||
puts outdated_count
|
||||
end
|
||||
|
||||
new_array.each do |item|
|
||||
if item.url.includes?(password_string.to_s)
|
||||
puts item.url.colorize(:magenta).mode(:blink)
|
||||
|
||||
if !item.email.blank?
|
||||
puts item.email.colorize(:red)
|
||||
end
|
||||
if !item.login.blank?
|
||||
puts item.login.colorize(:yellow)
|
||||
end
|
||||
if !item.password.blank?
|
||||
puts item.password.colorize(:red).back(:red)
|
||||
end
|
||||
if !item.desc.blank?
|
||||
puts item.desc.colorize(:cyan)
|
||||
end
|
||||
if !item.profile_url.blank?
|
||||
puts item.profile_url.colorize(:green)
|
||||
end
|
||||
|
||||
puts "---".colorize(:dark_gray)
|
||||
end
|
||||
end
|
||||
|
||||
puts
|
||||
end
|
118
src/pmng.cr
118
src/pmng.cr
@ -1,118 +0,0 @@
|
||||
require "option_parser"
|
||||
require "yaml"
|
||||
require "colorize"
|
||||
|
||||
require "./pmng/*"
|
||||
require "./pmng/functions/*"
|
||||
|
||||
module Pmng
|
||||
# check password file exists
|
||||
if File.exists?(PASSWORD_FILE_PATH)
|
||||
yaml = File.open(PASSWORD_FILE_PATH) do |file|
|
||||
YAML.parse(file)
|
||||
end
|
||||
else
|
||||
print "~/.pwd.yml".colorize(:red).mode(:bold)
|
||||
puts ": No such file"
|
||||
|
||||
exit(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)
|
||||
print "Execute: ".colorize(:yellow)
|
||||
print "(chmod 600 ~/.pwd.yml) ".colorize(:green).mode(:bold)
|
||||
puts "for fix.".colorize(:yellow)
|
||||
|
||||
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
|
||||
|
||||
# pmng title
|
||||
system "clear"
|
||||
puts ASCII_LOGO.colorize(:yellow)
|
||||
puts "The very simple password manager for humans".colorize(:yellow).mode(:bold)
|
||||
puts "-------------------------------------------".colorize(:yellow).mode(:bold)
|
||||
|
||||
statistics = Functions::Statistics.new(passwords_array)
|
||||
|
||||
# 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)
|
||||
|
||||
begin
|
||||
STDIN.read_timeout = USER_INPUT_TIMEOUT
|
||||
password_string = STDIN.gets
|
||||
rescue IO::TimeoutError
|
||||
loop = false
|
||||
end
|
||||
|
||||
if password_string.to_s == ":q"
|
||||
# if ':q' to close program
|
||||
loop = false
|
||||
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 statistics.size
|
||||
|
||||
print "Passwords outdated: ".colorize(:red).mode(:bold)
|
||||
puts statistics.outdated
|
||||
else
|
||||
# list search password
|
||||
system "clear"
|
||||
|
||||
passwords_finded_array = 0
|
||||
|
||||
passwords_array.each do |item|
|
||||
if item.url.includes?(password_string.to_s.downcase)
|
||||
Functions.show_item(item)
|
||||
|
||||
puts "-----".colorize(:dark_gray).mode(:bold)
|
||||
|
||||
passwords_finded_array += 1
|
||||
end
|
||||
end
|
||||
|
||||
puts
|
||||
print "Finded ".colorize(:yellow).mode(:bold)
|
||||
print passwords_finded_array.colorize(:red).mode(:bold)
|
||||
puts " records".colorize(:yellow).mode(:bold)
|
||||
puts "-----".colorize(:dark_gray).mode(:bold)
|
||||
end
|
||||
|
||||
puts
|
||||
end
|
||||
|
||||
system "clear"
|
||||
puts "Bye! 👋"
|
||||
end
|
@ -1,35 +0,0 @@
|
||||
begin
|
||||
OptionParser.parse do |parser|
|
||||
parser.banner = "The very simple password manager for humans\n"
|
||||
|
||||
parser.on "-v", "--version", "Show version" do
|
||||
puts ASCII_LOGO.colorize(:yellow)
|
||||
puts "The very simple password manager for humans.".colorize(:yellow)
|
||||
print "Version ".colorize(:yellow)
|
||||
puts VERSION.colorize(:red).mode(:bold)
|
||||
puts "\nURL to full changes log: ".colorize(:yellow)
|
||||
puts "https://git.a2s.su/iiiypuk/pmng/raw/branch/master/HISTORY.md".colorize(:green).mode(:bold)
|
||||
|
||||
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
|
@ -1,28 +0,0 @@
|
||||
def password_file
|
||||
# Return password file path
|
||||
|
||||
begin
|
||||
file_path = "#{ENV["PMNG_PWD_FILE"]}"
|
||||
file_path.to_s
|
||||
rescue KeyError
|
||||
file_path = "#{ENV["HOME"]}/.pwd.yml"
|
||||
file_path.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def input_timeout
|
||||
# Return user input timeout
|
||||
|
||||
user_input_timeout = 60
|
||||
|
||||
begin
|
||||
user_input_timeout = "#{ENV["PMNG_TIMEOUT"]}"
|
||||
user_input_timeout.to_i
|
||||
rescue KeyError
|
||||
user_input_timeout.to_i # return default 60s
|
||||
end
|
||||
end
|
||||
|
||||
VERSION = {{ `shards version "#{__DIR__}"`.chomp.stringify }}
|
||||
PASSWORD_FILE_PATH = password_file()
|
||||
USER_INPUT_TIMEOUT = input_timeout()
|
@ -1,8 +0,0 @@
|
||||
ASCII_LOGO = "
|
||||
██████╗ ███╗ ███╗███╗ ██╗ ██████╗
|
||||
██╔══██╗████╗ ████║████╗ ██║██╔════╝
|
||||
██████╔╝██╔████╔██║██╔██╗ ██║██║ ███╗
|
||||
██╔═══╝ ██║╚██╔╝██║██║╚██╗██║██║ ██║
|
||||
██║ ██║ ╚═╝ ██║██║ ╚████║╚██████╔╝
|
||||
╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝ #{VERSION}
|
||||
"
|
@ -1,33 +0,0 @@
|
||||
module Pmng::Functions
|
||||
extend self
|
||||
|
||||
def show_item(password)
|
||||
print "🌐 "
|
||||
puts password.url.colorize(:magenta).mode(:bold).mode(:underline)
|
||||
|
||||
if !password.email.blank?
|
||||
print "📧 "
|
||||
puts password.email.colorize(:red)
|
||||
end
|
||||
|
||||
if !password.login.blank?
|
||||
print "🗿 "
|
||||
puts password.login.colorize(:yellow)
|
||||
end
|
||||
|
||||
if !password.password.blank?
|
||||
print "🔐 "
|
||||
puts password.password.colorize(:red).back(:red)
|
||||
end
|
||||
|
||||
if !password.desc.blank?
|
||||
print "📄 "
|
||||
puts password.desc.colorize(:cyan)
|
||||
end
|
||||
|
||||
if !password.profile_url.blank?
|
||||
print "👦 "
|
||||
puts password.profile_url.colorize(:green)
|
||||
end
|
||||
end
|
||||
end
|
@ -1,33 +0,0 @@
|
||||
module Pmng::Functions
|
||||
extend self
|
||||
|
||||
class Statistics
|
||||
getter passwords : Array(Password)
|
||||
getter outdated : Int32
|
||||
getter size : Int32
|
||||
|
||||
def initialize(@passwords)
|
||||
@size = passwords.size
|
||||
|
||||
outdated_count = 0
|
||||
current_time = Time.local.to_unix
|
||||
a = [] of String
|
||||
@passwords.each do |item|
|
||||
if item.update + (2629743 * 3) < current_time # 2629743 * 3 -- 3 month
|
||||
outdated_count += 1
|
||||
a << item.url
|
||||
end
|
||||
end
|
||||
|
||||
@outdated = outdated_count
|
||||
end
|
||||
|
||||
def size
|
||||
@size
|
||||
end
|
||||
|
||||
def outdated
|
||||
@outdated
|
||||
end
|
||||
end
|
||||
end
|
@ -1,18 +0,0 @@
|
||||
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
|
Loading…
Reference in New Issue
Block a user