yamp 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/yamp +119 -0
- data/lib/yamp.rb +81 -0
- metadata +89 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 12d4147065962bc1538c030e019e60e3d0b7f6b0
|
4
|
+
data.tar.gz: e4d7a5c84938d78bc8b5256d35ce31596b8a331c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 17ad410c73d0a142e8524b229871ae5411627908fbdd5ddddd044e7ddb877545f336539ffc7b23ffcbadefade141ed28d5c819c4443c88063630cc02657f0912
|
7
|
+
data.tar.gz: bd62ec4f70c9fdfb76f391f6e0de457aa48014b58f63ee14f76e5ef6f9f85475e1ae7038eb7a0898719d85909276f7b0e81ba049c0e3b25979f35fb6eeef694f
|
data/bin/yamp
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'io/console'
|
4
|
+
require 'clipboard'
|
5
|
+
require 'optparse'
|
6
|
+
require 'yamp'
|
7
|
+
|
8
|
+
trap "SIGINT" do puts "\nByeBye!"; exit(130) end
|
9
|
+
|
10
|
+
class String
|
11
|
+
def red; "\033[31m#{self}\033[0m" end
|
12
|
+
def green; "\033[32m#{self}\033[0m" end
|
13
|
+
def yellow; "\033[33m#{self}\033[0m" end
|
14
|
+
end
|
15
|
+
|
16
|
+
ARGV << '-h' if ARGV.empty?
|
17
|
+
|
18
|
+
vault = nil
|
19
|
+
options = {}
|
20
|
+
password_chars = [*'0'..'9', *'a'..'z',*'A'..'Z','#','!','?','$','/','(',')','[',']']
|
21
|
+
|
22
|
+
OptionParser.new do |opts|
|
23
|
+
opts.banner = %q(
|
24
|
+
Usage: yamp [options]
|
25
|
+
|
26
|
+
Examples:
|
27
|
+
yamp --add facebook --username johndoe@gmail.com --password abc123
|
28
|
+
yamp -a twitter
|
29
|
+
yamp --update twitter -n johndoe
|
30
|
+
yamp --get facebook
|
31
|
+
yamp -g twitter --to-clipboard
|
32
|
+
yamp --delete facebook
|
33
|
+
)
|
34
|
+
opts.on('-a', '--add ENTRY', 'create an entry') {|id| options[:add] = id}
|
35
|
+
opts.on('-g', '--get ENTRY', 'read an entry') {|id| options[:get] = id}
|
36
|
+
opts.on('-u', '--update ENTRY', 'update an entry') {|id| options[:upd] = id}
|
37
|
+
opts.on('-d', '--delete ENTRY', 'delete an entry') {|id| options[:del] = id}
|
38
|
+
opts.on('-p', '--password PWD', 'specify a password') {|pwd| options[:pwd] = pwd}
|
39
|
+
opts.on('-n', '--username USR', 'specify a username') {|usr| options[:usr] = usr}
|
40
|
+
opts.on('-l', '--list', 'list all entries') {options[:lst] = true}
|
41
|
+
opts.on('-c', '--to-clipboard', 'copy password to clipboard') {options[:clip] = true}
|
42
|
+
end.parse!
|
43
|
+
|
44
|
+
unless (options.keys & [:add, :del, :upd, :get, :lst]).size == 1
|
45
|
+
puts "please specifiy either --add, --delete, --update, --get or --list"
|
46
|
+
exit
|
47
|
+
end
|
48
|
+
|
49
|
+
print RUBY_PLATFORM =~ /darwin/ ? "🙈 " : ">"
|
50
|
+
master = STDIN.noecho(&:gets).chomp!; puts "\n"
|
51
|
+
begin
|
52
|
+
vault = YAMP::Vault.new master
|
53
|
+
rescue Exception => e
|
54
|
+
puts e.message
|
55
|
+
exit
|
56
|
+
end
|
57
|
+
|
58
|
+
if id = options[:add]
|
59
|
+
pwd = options[:pwd] ? options[:pwd] : 32.times.map {password_chars.sample}.join
|
60
|
+
unless vault.add id, pwd, options[:usr]
|
61
|
+
puts "entry already exists"
|
62
|
+
else
|
63
|
+
puts "+".green + " #{id}"
|
64
|
+
Clipboard.copy pwd if options[:clip]
|
65
|
+
end
|
66
|
+
exit
|
67
|
+
end
|
68
|
+
|
69
|
+
if id = options[:del]
|
70
|
+
unless vault.remove id
|
71
|
+
puts "no such entry"
|
72
|
+
else
|
73
|
+
puts "-".red + " #{id}"
|
74
|
+
end
|
75
|
+
exit
|
76
|
+
end
|
77
|
+
|
78
|
+
if id = options[:upd]
|
79
|
+
unless options[:pwd] || options[:usr]
|
80
|
+
puts "oops! did you forget something?"
|
81
|
+
exit
|
82
|
+
end
|
83
|
+
pwd_updated = false
|
84
|
+
usr_updated = false
|
85
|
+
if pwd = options[:pwd]
|
86
|
+
pwd_updated = vault.update id, :pwd, pwd
|
87
|
+
end
|
88
|
+
if usr = options[:usr]
|
89
|
+
usr_updated = vault.update id, :usr, usr
|
90
|
+
end
|
91
|
+
unless pwd_updated || usr_updated
|
92
|
+
puts "no such entry"
|
93
|
+
else
|
94
|
+
puts "*".yellow + " #{id}"
|
95
|
+
Clipboard.copy pwd if options[:clip]
|
96
|
+
end
|
97
|
+
exit
|
98
|
+
end
|
99
|
+
|
100
|
+
if id = options[:get]
|
101
|
+
password = vault.get id, :pwd
|
102
|
+
username = vault.get id, :usr
|
103
|
+
unless password || username
|
104
|
+
puts "no such entry"
|
105
|
+
else
|
106
|
+
puts username if username
|
107
|
+
unless options[:clip]
|
108
|
+
puts password
|
109
|
+
else
|
110
|
+
Clipboard.copy password
|
111
|
+
end
|
112
|
+
end
|
113
|
+
exit
|
114
|
+
end
|
115
|
+
|
116
|
+
if options[:lst]
|
117
|
+
puts vault.list.sort
|
118
|
+
exit
|
119
|
+
end
|
data/lib/yamp.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
|
2
|
+
require 'redis'
|
3
|
+
require 'openssl'
|
4
|
+
|
5
|
+
module YAMP
|
6
|
+
|
7
|
+
class Vault
|
8
|
+
|
9
|
+
def initialize master, redis=Redis.new
|
10
|
+
@redis = redis
|
11
|
+
master_hash = redis.get "__mstr_h"
|
12
|
+
master_salt = redis.get "__mstr_s"
|
13
|
+
if master_hash && master_salt
|
14
|
+
@master_key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(master, master_salt, 10000, 32)
|
15
|
+
unless OpenSSL::Digest::SHA512.hexdigest(@master_key) == master_hash
|
16
|
+
raise ArgumentError, "access denied"
|
17
|
+
end
|
18
|
+
else
|
19
|
+
salt = OpenSSL::Random.random_bytes(32)
|
20
|
+
@master_key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(master, salt, 10000, 32)
|
21
|
+
redis.set "__mstr_h", OpenSSL::Digest::SHA512.hexdigest(@master_key)
|
22
|
+
redis.set "__mstr_s", salt
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def add id, password, username=nil
|
27
|
+
return false if %w{__mstr_h __mstr_s}.include? id
|
28
|
+
return false unless @redis.hsetnx id, "pwd", encrypt(id, password)
|
29
|
+
@redis.hsetnx id, "usr", encrypt(id, username) if username
|
30
|
+
return true
|
31
|
+
end
|
32
|
+
|
33
|
+
def update id, key, value
|
34
|
+
return false if %w{__mstr_h __mstr_s}.include? id
|
35
|
+
return false unless [:pwd, :usr].include? key
|
36
|
+
@redis.hset id, key, encrypt(id, value)
|
37
|
+
end
|
38
|
+
|
39
|
+
def remove id
|
40
|
+
return false if %w{__mstr_h __mstr_s}.include? id
|
41
|
+
@redis.del id
|
42
|
+
end
|
43
|
+
|
44
|
+
def get id, key
|
45
|
+
return nil if %w{__mstr_h __mstr_s}.include? id
|
46
|
+
return nil unless [:pwd, :usr].include? key
|
47
|
+
return nil unless @redis.hexists id, key
|
48
|
+
decrypt id, @redis.hget(id, key)
|
49
|
+
end
|
50
|
+
|
51
|
+
def list
|
52
|
+
@redis.keys - %w{__mstr_h __mstr_s}
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def encrypt id, data
|
58
|
+
cipher = OpenSSL::Cipher.new 'chacha20'
|
59
|
+
cipher.encrypt
|
60
|
+
iv = @redis.hget id, "__iv"
|
61
|
+
unless iv
|
62
|
+
iv = cipher.random_iv
|
63
|
+
@redis.hset id, "__iv", iv
|
64
|
+
else
|
65
|
+
cipher.iv = iv
|
66
|
+
end
|
67
|
+
cipher.key = @master_key
|
68
|
+
cipher.update(data) + cipher.final
|
69
|
+
end
|
70
|
+
|
71
|
+
def decrypt id, data
|
72
|
+
cipher = OpenSSL::Cipher.new 'chacha20'
|
73
|
+
cipher.decrypt
|
74
|
+
cipher.iv = @redis.hget id, "__iv"
|
75
|
+
cipher.key = @master_key
|
76
|
+
cipher.update(data) + cipher.final
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: yamp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tobias Heilig
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-09-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: redis
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: openssl
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: clipboard
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.1'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.1'
|
55
|
+
description: A minimal CLI-based password manager built upon redis-cache
|
56
|
+
email: holy708145@gmail.com
|
57
|
+
executables:
|
58
|
+
- yamp
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- bin/yamp
|
63
|
+
- lib/yamp.rb
|
64
|
+
homepage: http://rubygems.org/gems/yamp
|
65
|
+
licenses:
|
66
|
+
- MIT
|
67
|
+
metadata: {}
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options: []
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '2.0'
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
requirements:
|
83
|
+
- redis, see https://redis.io
|
84
|
+
rubyforge_project:
|
85
|
+
rubygems_version: 2.6.13
|
86
|
+
signing_key:
|
87
|
+
specification_version: 4
|
88
|
+
summary: yet another minimalistic passwordmanager
|
89
|
+
test_files: []
|