yamp 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|