chupacabra 0.0.0 → 0.0.2
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/chupacabra +34 -0
- data/lib/chupacabra.rb +29 -1
- data/lib/chupacabra/crypto.rb +41 -0
- data/lib/chupacabra/storage.rb +60 -0
- data/lib/chupacabra/system.rb +69 -0
- data/lib/chupacabra/version.rb +3 -0
- metadata +74 -49
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: dfaa094a87841fef12866c5ce7a1fc975cb642f0
|
4
|
+
data.tar.gz: 7da4daa7002ce40c5053fad4d996aca648354927
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9e0e18c05e3541a0d2c9f1ca95b8aca28e87e6535f0dcb32f4d11a26d182a463d4c21c7836705bd9b7b8177ff598185bd18c03221d34743955b29a2b08439712
|
7
|
+
data.tar.gz: 129adb2c4fb29a30e32db9a0430c140eb21bf54d52a7ebfdf4cfa12337a1911c45cd27e5d7a4b446350da068015bb77672d3045f85b254a51e798309972dfc2e
|
data/bin/chupacabra
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'chupacabra'
|
3
|
+
require 'optparse'
|
4
|
+
require 'ostruct'
|
5
|
+
|
6
|
+
|
7
|
+
options = OpenStruct.new
|
8
|
+
|
9
|
+
# Defaults
|
10
|
+
options.verbose = false
|
11
|
+
|
12
|
+
OptionParser.new do |opts|
|
13
|
+
opts.banner = "Usage: chupacabra [options]"
|
14
|
+
|
15
|
+
opts.on("-v", "--verbose", "Prints password") do |port|
|
16
|
+
options.verbose = true
|
17
|
+
end
|
18
|
+
|
19
|
+
opts.on("-V", "--version", "Output version") do |address|
|
20
|
+
puts Chupacabra::VERSION
|
21
|
+
exit
|
22
|
+
end
|
23
|
+
|
24
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
25
|
+
puts opts
|
26
|
+
exit
|
27
|
+
end
|
28
|
+
end.parse!(ARGV)
|
29
|
+
|
30
|
+
if options.verbose
|
31
|
+
puts Chupacabra.get_password
|
32
|
+
else
|
33
|
+
Chupacabra.get_password
|
34
|
+
end
|
data/lib/chupacabra.rb
CHANGED
@@ -1,3 +1,31 @@
|
|
1
|
-
|
1
|
+
require 'chupacabra/system'
|
2
|
+
require 'chupacabra/crypto'
|
3
|
+
require 'chupacabra/storage'
|
4
|
+
require 'chupacabra/version'
|
2
5
|
|
6
|
+
module Chupacabra
|
7
|
+
extend self
|
8
|
+
attr_accessor :env
|
9
|
+
|
10
|
+
def get_password
|
11
|
+
data = Storage.new(System.get_password)
|
12
|
+
key = System.get_clipboard
|
13
|
+
if data[key]
|
14
|
+
output(data[key])
|
15
|
+
else
|
16
|
+
data[key] = Crypto.generate_password
|
17
|
+
output(data[key])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test?
|
22
|
+
env == 'test'
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def output(text)
|
28
|
+
System.set_clipboard(text)
|
29
|
+
text
|
30
|
+
end
|
3
31
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
module Chupacabra
|
5
|
+
module Crypto
|
6
|
+
|
7
|
+
class WrongPassword < StandardError; end
|
8
|
+
|
9
|
+
extend self
|
10
|
+
PASSWORD_LENGTH = 32
|
11
|
+
|
12
|
+
def encrypt(text, password)
|
13
|
+
encrypter = OpenSSL::Cipher::Cipher.new 'AES256'
|
14
|
+
encrypter.encrypt
|
15
|
+
encrypter.pkcs5_keyivgen password
|
16
|
+
Base64.encode64(encrypter.update(text) + encrypter.final).strip
|
17
|
+
end
|
18
|
+
|
19
|
+
def decrypt(text, password)
|
20
|
+
encrypted = Base64.decode64(text).strip
|
21
|
+
decrypter = OpenSSL::Cipher::Cipher.new 'AES256'
|
22
|
+
decrypter.decrypt
|
23
|
+
decrypter.pkcs5_keyivgen password
|
24
|
+
decrypter.update(encrypted) + decrypter.final
|
25
|
+
|
26
|
+
rescue OpenSSL::Cipher::CipherError
|
27
|
+
raise WrongPassword, 'Wrong password'
|
28
|
+
end
|
29
|
+
|
30
|
+
def generate_password
|
31
|
+
letters = 'abcdefghijklmnopqrstuwxyz'
|
32
|
+
upcase = letters.upcase
|
33
|
+
numbers = '1234567890'
|
34
|
+
stuff = '!@$%^&#()-_'
|
35
|
+
all = [letters, upcase, numbers, stuff].collect{ |collection| collection.split('') }
|
36
|
+
output = all.collect { |collection| collection.shuffle.first }
|
37
|
+
(PASSWORD_LENGTH - all.length).times { output << all.flatten.shuffle.first }
|
38
|
+
output.join
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module Chupacabra
|
4
|
+
class Storage
|
5
|
+
|
6
|
+
def self.filepath
|
7
|
+
Pathname.new(ENV['HOME']) + filename
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.clear
|
11
|
+
filepath.unlink if filepath.exist?
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(password)
|
15
|
+
@password = password
|
16
|
+
end
|
17
|
+
|
18
|
+
def [](key)
|
19
|
+
data[extract(key)]
|
20
|
+
end
|
21
|
+
|
22
|
+
def []=(key, value)
|
23
|
+
data[extract(key)] = value
|
24
|
+
save
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_h
|
28
|
+
data
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def self.filename
|
34
|
+
Chupacabra.test? ? '.chupacabra_test' : '.chupacabra'
|
35
|
+
end
|
36
|
+
|
37
|
+
def data
|
38
|
+
@data ||=
|
39
|
+
if File.exists?(self.class.filepath)
|
40
|
+
Marshal.load(Crypto.decrypt(File.read(self.class.filepath), @password))
|
41
|
+
else
|
42
|
+
{ }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def save
|
47
|
+
File.open(self.class.filepath, 'w') do |file|
|
48
|
+
file << Crypto.encrypt(Marshal.dump(@data), @password)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def extract(key)
|
53
|
+
if key =~ /https?\:\/\/(?:www.)?([^\/\?]+)/
|
54
|
+
$1
|
55
|
+
else
|
56
|
+
raise ArgumentError, "#{key} doesn't look like url"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module Chupacabra
|
4
|
+
module System
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def get_password
|
8
|
+
return get_env_password if get_env_password
|
9
|
+
password = get_password_from_dialog
|
10
|
+
raise "Password can't be empty" if !password || password.empty?
|
11
|
+
set_env_password(password)
|
12
|
+
password
|
13
|
+
end
|
14
|
+
|
15
|
+
def clear
|
16
|
+
`launchctl unsetenv #{password_variable}` if osx?
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_clipboard
|
20
|
+
`pbpaste`.strip
|
21
|
+
end
|
22
|
+
|
23
|
+
def set_clipboard(text)
|
24
|
+
raise 'Unsupported string' if text =~ /'/
|
25
|
+
`echo '#{text}' | pbcopy`
|
26
|
+
end
|
27
|
+
|
28
|
+
def osx?
|
29
|
+
`uname`.strip == 'Darwin'
|
30
|
+
end
|
31
|
+
|
32
|
+
def linux?
|
33
|
+
`uname`.strip == 'Linux'
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def password_variable
|
39
|
+
Chupacabra.test? ? 'CHUPACABRA' : 'CHUPACABRA_TEST'
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_password_from_dialog
|
43
|
+
strip_dialog_response(ask_for_password)
|
44
|
+
end
|
45
|
+
|
46
|
+
def strip_dialog_response(response)
|
47
|
+
response.match(/text returned:(.+), button returned:OK/)[1]
|
48
|
+
end
|
49
|
+
|
50
|
+
def ask_for_password
|
51
|
+
dialog = 'display dialog "Enter Chupacabra password"' +
|
52
|
+
'default answer ""' +
|
53
|
+
'with title "Chupacabra"' +
|
54
|
+
'with icon caution with hidden answer'
|
55
|
+
|
56
|
+
`osascript -e 'tell application "Finder"' -e "activate" -e '#{dialog}' -e 'end tell'`
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_env_password
|
60
|
+
password64 = `launchctl getenv #{password_variable}`.strip
|
61
|
+
return if password64.empty?
|
62
|
+
Base64.decode64(password64).strip
|
63
|
+
end
|
64
|
+
|
65
|
+
def set_env_password(password)
|
66
|
+
`launchctl setenv #{password_variable} '#{Base64.encode64(password).strip}'`
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
metadata
CHANGED
@@ -1,67 +1,92 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: chupacabra
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 0
|
9
|
-
- 0
|
10
|
-
version: 0.0.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
11
5
|
platform: ruby
|
12
|
-
authors:
|
6
|
+
authors:
|
13
7
|
- Dawid Sklodowski
|
14
8
|
autorequire:
|
15
9
|
bindir: bin
|
16
10
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
11
|
+
date: 2013-07-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pry
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Encrypted and easy to use personal storage for user passwords
|
23
56
|
email: dawid.sklodowski@gmail.com
|
24
|
-
executables:
|
25
|
-
|
57
|
+
executables:
|
58
|
+
- chupacabra
|
26
59
|
extensions: []
|
27
|
-
|
28
60
|
extra_rdoc_files: []
|
29
|
-
|
30
|
-
|
61
|
+
files:
|
62
|
+
- bin/chupacabra
|
63
|
+
- lib/chupacabra/crypto.rb
|
64
|
+
- lib/chupacabra/storage.rb
|
65
|
+
- lib/chupacabra/system.rb
|
66
|
+
- lib/chupacabra/version.rb
|
31
67
|
- lib/chupacabra.rb
|
32
|
-
has_rdoc: true
|
33
68
|
homepage: http://github.com/dawid-sklodowski/chupacabra
|
34
|
-
licenses:
|
35
|
-
|
69
|
+
licenses:
|
70
|
+
- MIT
|
71
|
+
metadata: {}
|
36
72
|
post_install_message:
|
37
73
|
rdoc_options: []
|
38
|
-
|
39
|
-
require_paths:
|
74
|
+
require_paths:
|
40
75
|
- lib
|
41
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
none: false
|
52
|
-
requirements:
|
53
|
-
- - ">="
|
54
|
-
- !ruby/object:Gem::Version
|
55
|
-
hash: 3
|
56
|
-
segments:
|
57
|
-
- 0
|
58
|
-
version: "0"
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
59
86
|
requirements: []
|
60
|
-
|
61
87
|
rubyforge_project:
|
62
|
-
rubygems_version:
|
88
|
+
rubygems_version: 2.0.2
|
63
89
|
signing_key:
|
64
|
-
specification_version:
|
65
|
-
summary:
|
90
|
+
specification_version: 4
|
91
|
+
summary: Personal crypto pass
|
66
92
|
test_files: []
|
67
|
-
|