keepassxc 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6c60203ef5b9cdcd3cbabce41a9712e62d35793cbc5f5a3cb40070a45acee25d
4
+ data.tar.gz: e23b41982c3bec59afff4a50230fa31e00172c51949749e9ac27d3477a94a434
5
+ SHA512:
6
+ metadata.gz: 8737d87a03efbcb532f225cee2eb22ead55449944fc0c5b53b366b8bf922a4fb8197834e4d520061e0bfca1bda19b634de87bedda13df56fb789ad4a8edc213c
7
+ data.tar.gz: a2be3cf5b98ed7e63c65097882b391dd3faef90d0ee3345b6389575412ce70770bb561d79e37f91bce162fb323682047ab247cea4bb72601776a3a7fd55dfaf7
data/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # KeypassXC Ruby binding
2
+
3
+ You want to fetch login data as the browsers do. Then this is for you.
4
+ Similar to my https://github.com/Kjarrigan/keepasshttp-ruby repo.
5
+
6
+ ## Work in progress
7
+
8
+ A coworker just asked me wether I have use the keepassxc-cli but it requires
9
+ to enter a password every time which is annoying and then I remembered my
10
+ keepasshttp-ruby binding and it turns out this is no longer the desired way
11
+ for KeepassXC. So why not make the new version work. Yay!
12
+
13
+ ## Links
14
+
15
+ Some things have changed but the rough idea is the same. So I can probably copy
16
+ over quite a bit of context.
17
+
18
+ * [My HTTP Code](https://github.com/Kjarrigan/keepasshttp-ruby/blob/master/lib/keepasshttp.rb)
19
+ * [The official protocal docs](https://github.com/keepassxreboot/keepassxc-browser/blob/develop/keepassxc-protocol.md)
20
+
21
+ ## Basic communication snippet
22
+
23
+ It is already working now! Altough some comfort is still missing, you can already register your client and
24
+ fetch logins. Yay!
25
+
26
+ ```ruby
27
+ load 'test.rb'
28
+
29
+ kpx = KeepassXC.new client_identifier: KEY_FROM_ASSOCIATE_OR_DB, client_name: ID_FROM_ASSOCIATE_OR_DB
30
+ kpx.change_public_keys
31
+ # kpx.associate
32
+ kpx.test_associate
33
+ p kpx.get_logins 'https://github.com'
34
+ ```
35
+
36
+ You can check what clients are already registered in your DB via the GUI like this:
37
+ * Database
38
+ * Database-Settings
39
+ * Browser-Integration
40
+
41
+ Technically you could even re-use the Key/ID from your browser by just copying them from there.
data/exe/keepassxc-rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'keepassxc'
2
+
3
+ name = ARGV[1] || `hostname`.chomp
4
+
5
+ cfg = KeepassXC::KeyStore.find_or_create
6
+ kpx = KeepassXC::Client.new client_name: name
7
+ kpx.change_public_keys
8
+ if cfg.profiles[name]
9
+ kpx.client_identifier = cfg.profiles[name]
10
+ else
11
+ kpx.associate
12
+ cfg.profiles[name] = kpx.client_identifier
13
+ cfg.save
14
+ end
15
+ kpx.test_associate
16
+
17
+ puts kpx.get_logins(ARGV[0]).first['password']
data/keepassxc.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ require_relative 'lib/keepassxc/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'keepassxc'
5
+ spec.version = KeepassXC::VERSION
6
+ spec.authors = ['Holger Arndt']
7
+ spec.email = ['keepassxc-ruby@kjarrigan.de']
8
+
9
+ spec.summary = %q{Ruby bindings for the KeepassXC Browser API}
10
+ spec.description = %q{Ruby bindings for the KeepassXC Browser API}
11
+ spec.homepage = 'https://github.com/Kjarrigan/keepassxc-ruby'
12
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')
13
+
14
+ spec.metadata['homepage_uri'] = spec.homepage
15
+ spec.metadata['source_code_uri'] = spec.homepage
16
+ spec.metadata['changelog_uri'] = spec.homepage
17
+
18
+ spec.files = Dir.chdir(__dir__) do
19
+ `git ls-files`.split("\n").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
+ end
21
+ spec.bindir = 'exe'
22
+ spec.executables = %w{keepassxc-rb}
23
+ spec.require_paths = ['lib']
24
+ end
data/lib/keepassxc.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'socket'
2
+ require 'json'
3
+
4
+ # TODO, replace this with openssl
5
+ require 'rbnacl'
6
+
7
+ module KeepassXC
8
+ class Error < StandardError; end
9
+
10
+ autoload :Client, 'keepassxc/client'
11
+ autoload :Helper, 'keepassxc/helper'
12
+ autoload :KeyStore, 'keepassxc/key_store'
13
+ autoload :VERSION, 'keepassxc/version'
14
+ end
@@ -0,0 +1,100 @@
1
+ require_relative 'helper'
2
+
3
+ module KeepassXC
4
+ class Client
5
+ include Helper
6
+
7
+ attr_accessor :client_id, :client_identifier, :client_name
8
+
9
+ def initialize(client_identifier: nil, client_name: nil)
10
+ @client_id = generate_nonce
11
+ user_id = `id -u`.chomp.to_i
12
+ @sock = UNIXSocket.new("/run/user/#{user_id}/org.keepassxc.KeePassXC.BrowserServer")
13
+ @private_key = RbNaCl::PrivateKey.generate
14
+ @client_identifier = client_identifier || to_b64(@private_key.public_key)
15
+ @client_name = client_name
16
+ end
17
+
18
+ def generate_nonce
19
+ to_b64 RbNaCl::Random.random_bytes
20
+ end
21
+
22
+ def change_public_keys
23
+ resp = send_msg(
24
+ action: 'change-public-keys',
25
+ publicKey: to_b64(@private_key.public_key),
26
+ nonce: generate_nonce,
27
+ clientID: @client_id
28
+ )
29
+ @session = RbNaCl::SimpleBox.from_keypair(resp['publicKey'].unpack1('m*'), @private_key)
30
+
31
+ resp
32
+ end
33
+
34
+ def associate
35
+ resp = send_encrypted_msg(
36
+ 'action' => 'associate',
37
+ 'key' => to_b64(@private_key.public_key),
38
+ 'idKey' => @client_identifier
39
+ )
40
+ @client_name = resp['id']
41
+
42
+ resp
43
+ end
44
+
45
+ def test_associate
46
+ send_encrypted_msg(
47
+ 'action' => 'test-associate',
48
+ 'key' => @client_identifier,
49
+ 'id' => @client_name
50
+ )
51
+ end
52
+
53
+ def get_logins(url)
54
+ send_encrypted_msg(
55
+ 'action' => 'get-logins',
56
+ 'url' => url,
57
+ 'keys' => [
58
+ {
59
+ 'id' => @client_name,
60
+ 'key' => @client_identifier
61
+ }
62
+ ]
63
+ )['entries']
64
+ end
65
+
66
+ def send_encrypted_msg(msg)
67
+ nonce, enc = encrypt(msg)
68
+
69
+ send_msg(
70
+ action: msg['action'],
71
+ message: to_b64(enc),
72
+ nonce: to_b64(nonce),
73
+ clientID: client_id
74
+ )
75
+ end
76
+
77
+ def encrypt(msg)
78
+ crypt = @session.box(JSON.dump(msg.transform_keys(&:to_s)))
79
+ nonce = crypt.slice!(0, RbNaCl::SecretBox.nonce_bytes)
80
+
81
+ [nonce, crypt]
82
+ end
83
+
84
+ def decrypt(msg, nonce:)
85
+ @session.decrypt(from_b64(nonce) + from_b64(msg))
86
+ end
87
+
88
+ def send_msg(msg)
89
+ @sock.send(JSON.dump(msg.transform_keys(&:to_s)), 0)
90
+ json = @sock.recvfrom(4096).first
91
+ resp = JSON.parse(json)
92
+
93
+ raise Error, resp['error'] if resp.key?('error')
94
+ resp = JSON.parse(decrypt(resp['message'], nonce: resp['nonce'])) if resp.key?('message')
95
+ binding.irb if resp['success'] != 'true'
96
+
97
+ resp
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,11 @@
1
+ module KeepassXC
2
+ module Helper
3
+ def to_b64(string)
4
+ [string].pack('m*').chomp
5
+ end
6
+
7
+ def from_b64(string)
8
+ string.unpack1('m*')
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,50 @@
1
+ require 'fileutils'
2
+ require 'json'
3
+
4
+ module KeepassXC
5
+ class KeyStore
6
+ attr_reader :path
7
+
8
+ DEFAULT_PATH = File.join(Dir.home, '.config', 'keepassxc-rb')
9
+ def initialize(path: DEFAULT_PATH)
10
+ @path = path
11
+ end
12
+
13
+ def create
14
+ unless exist?
15
+ FileUtils.mkdir_p File.dirname(path)
16
+ File.write(path, JSON.dump(profiles: {}))
17
+ end
18
+ File.chmod(0600, path) unless secure?
19
+ end
20
+
21
+ def self.find_or_create(path: DEFAULT_PATH)
22
+ storage = new(path: path)
23
+ storage.create
24
+ storage
25
+ end
26
+
27
+ def raw
28
+ @raw ||= JSON.load_file(path)
29
+ rescue Errno::ENOENT
30
+ @raw = {}
31
+ end
32
+
33
+ def profiles
34
+ raw['profiles']
35
+ end
36
+
37
+ def save
38
+ create
39
+ File.write(path, JSON.dump(raw))
40
+ end
41
+
42
+ def secure?
43
+ File.stat(path).mode == 0600
44
+ end
45
+
46
+ def exist?
47
+ File.exist?(path)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,3 @@
1
+ module KeepassXC
2
+ VERSION = '0.1.0'
3
+ end
metadata ADDED
@@ -0,0 +1,54 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: keepassxc
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Holger Arndt
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-04-16 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Ruby bindings for the KeepassXC Browser API
14
+ email:
15
+ - keepassxc-ruby@kjarrigan.de
16
+ executables:
17
+ - keepassxc-rb
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - README.md
22
+ - exe/keepassxc-rb
23
+ - keepassxc.gemspec
24
+ - lib/keepassxc.rb
25
+ - lib/keepassxc/client.rb
26
+ - lib/keepassxc/helper.rb
27
+ - lib/keepassxc/key_store.rb
28
+ - lib/keepassxc/version.rb
29
+ homepage: https://github.com/Kjarrigan/keepassxc-ruby
30
+ licenses: []
31
+ metadata:
32
+ homepage_uri: https://github.com/Kjarrigan/keepassxc-ruby
33
+ source_code_uri: https://github.com/Kjarrigan/keepassxc-ruby
34
+ changelog_uri: https://github.com/Kjarrigan/keepassxc-ruby
35
+ post_install_message:
36
+ rdoc_options: []
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 2.7.0
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubygems_version: 3.1.2
51
+ signing_key:
52
+ specification_version: 4
53
+ summary: Ruby bindings for the KeepassXC Browser API
54
+ test_files: []