keepasshttp 0.1.1 → 0.2.0
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 +4 -4
- data/.rubocop.yml +7 -1
- data/Gemfile +3 -0
- data/Gemfile.lock +3 -1
- data/README.md +23 -5
- data/exe/keepasshttp +30 -1
- data/lib/keepasshttp.rb +29 -5
- data/lib/keepasshttp/key_store.rb +107 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2f07357cd21290bc9cdc42bbf6b12060a890d499e33a27dbf7e9278391862c6d
|
4
|
+
data.tar.gz: 3f4659d7322951be51501b5c95880a734b75152f4a9780847572e707d3d69609
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c96c8c638dcab3ba57830b466f3c3dbab439100f4d54399f3497fe98538def7e35e5ecca2d8c44b8da7f3e6020f59ee565be482ce1968102b3f89039fe8df410
|
7
|
+
data.tar.gz: bcc493cf7281c03d75cf168466b009edb07338d63186ca4f3a6c467ca33f76f96930e08411176cd11b4f992ee1a810556a910f90015a6a977602d2cb89eedf50
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
keepasshttp (0.
|
4
|
+
keepasshttp (0.2.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
9
|
diff-lcs (1.3)
|
10
|
+
net-ssh (5.0.2)
|
10
11
|
rake (10.5.0)
|
11
12
|
rspec (3.8.0)
|
12
13
|
rspec-core (~> 3.8.0)
|
@@ -28,6 +29,7 @@ PLATFORMS
|
|
28
29
|
DEPENDENCIES
|
29
30
|
bundler (~> 1.16)
|
30
31
|
keepasshttp!
|
32
|
+
net-ssh
|
31
33
|
rake (~> 10.0)
|
32
34
|
rspec (~> 3.0)
|
33
35
|
|
data/README.md
CHANGED
@@ -20,14 +20,32 @@ Or install it yourself as:
|
|
20
20
|
|
21
21
|
## Usage
|
22
22
|
|
23
|
-
```
|
24
|
-
require '
|
23
|
+
```ruby
|
24
|
+
require 'keepasshttp'
|
25
25
|
|
26
|
-
keep =
|
26
|
+
keep = Keepasshttp.connect
|
27
27
|
|
28
|
-
keep.
|
28
|
+
keep.credentials_for('http://example.com')
|
29
29
|
```
|
30
30
|
|
31
|
+
### KeyStores
|
32
|
+
|
33
|
+
With the above code you'll be prompted by your Keepass to enter a label for the new key (because the tool generates a new key every time)
|
34
|
+
which is shorter that typing your password but still annoying. So I added a (session) key_store. At the moment you can choose between:
|
35
|
+
|
36
|
+
* :Plain - save your key in plaintext - maximum convienience, minimal security
|
37
|
+
```ruby
|
38
|
+
Keepasshttp.connect(key_store: :Plain)
|
39
|
+
```
|
40
|
+
* :SshAgent - (re)use your running ssh-agent session to encrypt your session key (and then save it to a file)
|
41
|
+
```ruby
|
42
|
+
Keepasshttp.connect(key_store: :SshAgent)
|
43
|
+
```
|
44
|
+
* { key:, id: } - Do the keymanagement yourself and just input the necessary keys as Hash.
|
45
|
+
```ruby
|
46
|
+
Keepasshttp.connect(key_store: { key: 'SECRET', id: 'Foo' })
|
47
|
+
```
|
48
|
+
|
31
49
|
## Development
|
32
50
|
|
33
51
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -37,7 +55,7 @@ To install this gem onto your local machine, run `bundle exec rake install`.
|
|
37
55
|
To see if it works run
|
38
56
|
|
39
57
|
```bash
|
40
|
-
$ keepasshttp URL_THAT_IS_IN_YOUR_KEEPASSDB
|
58
|
+
$ keepasshttp URL_THAT_IS_IN_YOUR_KEEPASSDB [OPTS]
|
41
59
|
```
|
42
60
|
|
43
61
|
If it works Keypass will prompt you for a label (which name you pick is irrelevant) and it should print you an json to the shell containing your data.
|
data/exe/keepasshttp
CHANGED
@@ -4,5 +4,34 @@
|
|
4
4
|
require 'bundler/setup'
|
5
5
|
require 'keepasshttp'
|
6
6
|
require 'json'
|
7
|
+
require 'optparse'
|
7
8
|
|
8
|
-
|
9
|
+
params = {}
|
10
|
+
|
11
|
+
ARGV.options do |opts|
|
12
|
+
opts.on('-p INTEGER', '--port', 'Use Keystore::Plain') do |val|
|
13
|
+
params[:port] = val.to_i
|
14
|
+
end
|
15
|
+
|
16
|
+
opts.on('--plain', 'Use Keystore::Plain') do
|
17
|
+
params[:key_store] = :Plain
|
18
|
+
end
|
19
|
+
|
20
|
+
opts.on('--ssh-agent', 'Use Keystore::SshAgent') do
|
21
|
+
params[:key_store] = :SshAgent
|
22
|
+
end
|
23
|
+
|
24
|
+
opts.on('--key STRING', 'Input your key directly') do |val|
|
25
|
+
params[:key_store] ||= {}
|
26
|
+
params[:key_store][:key] = val
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on('--id STRING', 'Input your id directly') do |val|
|
30
|
+
params[:key_store] ||= {}
|
31
|
+
params[:key_store][:id] = val
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.parse!
|
35
|
+
end
|
36
|
+
|
37
|
+
puts Keepasshttp.connect(params).credentials_for(ARGV[0]).to_json
|
data/lib/keepasshttp.rb
CHANGED
@@ -17,23 +17,34 @@ class Keepasshttp
|
|
17
17
|
end
|
18
18
|
using Base64Helper
|
19
19
|
|
20
|
-
VERSION = '0.
|
20
|
+
VERSION = '0.2.0'
|
21
21
|
|
22
|
-
def self.connect(
|
23
|
-
kee = new(
|
22
|
+
def self.connect(**params)
|
23
|
+
kee = new(**params)
|
24
24
|
kee.login
|
25
25
|
kee
|
26
26
|
end
|
27
27
|
|
28
28
|
attr_accessor :port
|
29
29
|
attr_reader :session
|
30
|
+
attr_reader :id
|
31
|
+
autoload :KeyStore, 'keepasshttp/key_store'
|
30
32
|
|
31
|
-
def initialize(port: 19_455)
|
33
|
+
def initialize(port: 19_455, key_store: false)
|
32
34
|
@port = port
|
33
35
|
@session = false
|
36
|
+
init_keystore(key_store) if key_store
|
34
37
|
end
|
35
38
|
|
36
|
-
def
|
39
|
+
def init_keystore(key_store)
|
40
|
+
@key_store = if key_store.is_a?(Hash)
|
41
|
+
KeyStore::External.new(key_store)
|
42
|
+
else
|
43
|
+
KeyStore.const_get(key_store)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def credentials_for(url)
|
37
48
|
ping
|
38
49
|
|
39
50
|
enc_url = encrypt(url, iv: new_iv)
|
@@ -51,6 +62,9 @@ class Keepasshttp
|
|
51
62
|
|
52
63
|
@session = OpenSSL::Cipher.new('AES-256-CBC')
|
53
64
|
session.encrypt
|
65
|
+
|
66
|
+
return cached_login if @key_store&.available?
|
67
|
+
|
54
68
|
@key = session.random_key
|
55
69
|
new_iv
|
56
70
|
|
@@ -58,6 +72,16 @@ class Keepasshttp
|
|
58
72
|
return false unless json
|
59
73
|
|
60
74
|
@id = json['Id']
|
75
|
+
|
76
|
+
@key_store&.save(id: @id, key: @key)
|
77
|
+
end
|
78
|
+
|
79
|
+
def cached_login
|
80
|
+
cache = @key_store.load
|
81
|
+
@key = cache[:key]
|
82
|
+
@id = cache[:id]
|
83
|
+
new_iv
|
84
|
+
ping
|
61
85
|
end
|
62
86
|
|
63
87
|
def ping
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
class Keepasshttp
|
6
|
+
module KeyStore
|
7
|
+
# Input the key and the id directly into the client so you can take care
|
8
|
+
# of the storage yourself.
|
9
|
+
class External
|
10
|
+
def initialize(key:, id:)
|
11
|
+
@params = { key: key, id: id }
|
12
|
+
end
|
13
|
+
|
14
|
+
def save(*_args)
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
18
|
+
def load
|
19
|
+
@params
|
20
|
+
end
|
21
|
+
|
22
|
+
def available?
|
23
|
+
true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# The most simple but unsecure way wo store your session key (so you don't
|
28
|
+
# have to reenter the label over and over again). Use this only for testing!
|
29
|
+
class Plain
|
30
|
+
# TODO, make the PATH adjustable
|
31
|
+
PATH = File.join(Dir.home, '.keepasshttp-ruby')
|
32
|
+
def self.save(params = {})
|
33
|
+
File.write(PATH, params.to_yaml)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.load
|
37
|
+
YAML.load_file(PATH)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.available?
|
41
|
+
File.exist?(PATH) && File.size(PATH).positive?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Use your running ssh-agent session to encrypt your session key
|
46
|
+
class SshAgent < Plain
|
47
|
+
class << self
|
48
|
+
def available?
|
49
|
+
require 'net/ssh'
|
50
|
+
|
51
|
+
super
|
52
|
+
rescue LoadError
|
53
|
+
raise LoadError, 'To use key_store: :SshAgent you have to install ' \
|
54
|
+
"the 'net-ssh' gem"
|
55
|
+
end
|
56
|
+
|
57
|
+
def save(params = {})
|
58
|
+
enc, iv = encrypt(params.delete(:key))
|
59
|
+
params[:key] = enc
|
60
|
+
params[:iv] = iv
|
61
|
+
super(params)
|
62
|
+
end
|
63
|
+
|
64
|
+
def load
|
65
|
+
params = super
|
66
|
+
params[:key] = decrypt(params[:key], iv: params.delete(:iv))
|
67
|
+
params
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def encrypt(string)
|
73
|
+
agent = Net::SSH::Authentication::Agent.connect
|
74
|
+
|
75
|
+
cip = OpenSSL::Cipher.new('AES-256-CBC')
|
76
|
+
cip.encrypt
|
77
|
+
iv = cip.random_iv
|
78
|
+
|
79
|
+
cip.key = agent.sign(identity(agent), iv)[-32..-1]
|
80
|
+
|
81
|
+
[cip.update(string) + cip.final, iv]
|
82
|
+
end
|
83
|
+
|
84
|
+
def decrypt(string, iv:)
|
85
|
+
agent = Net::SSH::Authentication::Agent.connect
|
86
|
+
|
87
|
+
cip = OpenSSL::Cipher.new('AES-256-CBC')
|
88
|
+
cip.decrypt
|
89
|
+
cip.iv = iv
|
90
|
+
|
91
|
+
cip.key = agent.sign(identity(agent), iv)[-32..-1]
|
92
|
+
|
93
|
+
cip.update(string) + cip.final
|
94
|
+
end
|
95
|
+
|
96
|
+
# TODO, make the key selectable
|
97
|
+
def identity(agent)
|
98
|
+
if agent.identities.empty?
|
99
|
+
raise 'No identity available. Run `ssh-add` and try again'
|
100
|
+
end
|
101
|
+
|
102
|
+
agent.identities.first
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: keepasshttp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Holger Arndt
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-10-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -74,6 +74,7 @@ files:
|
|
74
74
|
- exe/keepasshttp
|
75
75
|
- keepasshttp.gemspec
|
76
76
|
- lib/keepasshttp.rb
|
77
|
+
- lib/keepasshttp/key_store.rb
|
77
78
|
homepage: https://github.com/Kjarrigan/keepasshttp-ruby
|
78
79
|
licenses:
|
79
80
|
- MIT
|