kasefet 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/DESIGN.md +30 -3
- data/PHILOSOPHY.md +1 -1
- data/README.md +5 -5
- data/kasefet.gemspec +12 -3
- data/lib/kasefet/cli.rb +31 -12
- data/lib/kasefet/config.rb +25 -11
- data/lib/kasefet/encrypted_flat_kv.rb +14 -8
- data/lib/kasefet/flat_kv.rb +39 -4
- data/lib/kasefet/indexed_flat_kv.rb +76 -0
- data/lib/kasefet/multi_wallet.rb +24 -0
- data/lib/kasefet/version.rb +1 -1
- data/lib/kasefet/wallet.rb +7 -8
- metadata +28 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a594687e14c4388b280060fb9684510f8f3151d0
|
4
|
+
data.tar.gz: 33368567de1b1ebda745b80552e58291eeb91bd9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd9155c78f966ae7a061fbee9f4594d131f614a20360114d26771317b79c0883bd7b065815e19ff3323b036da649c8b0add3c743769e22c4eb397556b031c1de
|
7
|
+
data.tar.gz: 0662f1cadf77d4f873620b2f959e42227b0d2060fe58c036e4c3e19ca44f4b982204a9b360c631564ade8c6a259e13eda6de48b56cbe603cd770637ab0dd78e3
|
data/DESIGN.md
CHANGED
@@ -4,6 +4,8 @@ We reuse this concept in several places, so here's the generic concept. I need t
|
|
4
4
|
|
5
5
|
```
|
6
6
|
root
|
7
|
+
|--index
|
8
|
+
| |--index
|
7
9
|
|--db
|
8
10
|
|--c39d7d6b239c2e20a31672ed979fed2b45c88748d06ba3be6bff85767b5d3d
|
9
11
|
|--20160224.184012.laptop
|
@@ -22,15 +24,40 @@ I leave it as an exercise to the sync program to correctly identify deleted valu
|
|
22
24
|
|
23
25
|
When encrypting files in such a format, I like to keep them prefixed to the encrypted content and then the auth tag. Note that the first version only supports AES-256-GCM.
|
24
26
|
|
25
|
-
|
27
|
+
## File format
|
28
|
+
|
29
|
+
The actual format of the value files is a binary file with the magic number "KSFT". The layout is simple:
|
30
|
+
|
31
|
+
```
|
32
|
+
+-------------------------------------------------------------------------------------------+
|
33
|
+
| Magic Number | Key Length (32 bit big endian unsigned integer) | Key | Value until EOF |
|
34
|
+
| KSFT | 0x0006 | foobar | bazquux.... |
|
35
|
+
+-------------------------------------------------------------------------------------------+
|
36
|
+
```
|
37
|
+
|
38
|
+
## Index directory
|
39
|
+
|
40
|
+
The index is a quick way to convert/iterate over all the keys in a KV store.
|
41
|
+
|
42
|
+
There are two versions of the index file, which involve tradeoffs between change velocity and the likelihood of conflicts. The tradeoff is between storage size and expected velocity.
|
43
|
+
|
44
|
+
## Low-velocity index
|
45
|
+
|
46
|
+
This form is ideal for stores that don't change very often, as the index can be shared between all nodes, and generally doesn't need to be regenerated unless there's a conflict.
|
47
|
+
|
48
|
+
The idea is that there is a single "index" file, which gets updated each time there's a new key added, and it's left to the sync program to leave a "conflicted copy" of the file, which indicates that the index should be rebuilt automatically.
|
49
|
+
|
50
|
+
## High-velocity index
|
51
|
+
|
52
|
+
This is the preferred form if you expect to have many concurrent changes. In this approach, each node maintains its own view of the index, and regenerates it pretty much every single chance it gets. The drawback is that changes are not automatically detected, and the extra storage, which can be non-trivial if there are a large number of keys.
|
53
|
+
|
54
|
+
# Kasefet Password Wallets
|
26
55
|
|
27
56
|
A kasefet wallet has the following layout:
|
28
57
|
|
29
58
|
```
|
30
59
|
wallet
|
31
60
|
|--key
|
32
|
-
|--index
|
33
|
-
| |--index
|
34
61
|
|--metadata (flat file kv directory)
|
35
62
|
|--ksft (flat file kv directory)
|
36
63
|
```
|
data/PHILOSOPHY.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# The name
|
2
2
|
|
3
|
-
Kasefet is the
|
3
|
+
Kasefet is the Hebrew word for "safe", (the locked box meaning of safe). Seemed as good as any, and wasn't taken on RubyGems
|
4
4
|
|
5
5
|
# A bit of history
|
6
6
|
|
data/README.md
CHANGED
@@ -10,12 +10,12 @@ Kasefet is currently a work in progress. This is the todo list for version 1.0,
|
|
10
10
|
|
11
11
|
- [x] Flat file wallet
|
12
12
|
- [x] SSL encrypted wallet
|
13
|
-
- [
|
13
|
+
- [x] support for multiple wallets
|
14
14
|
- [x] editor integration
|
15
|
-
- [
|
16
|
-
- [ ] autotype (Mac)
|
17
|
-
- [
|
18
|
-
- [ ] autotype (Ubuntu)
|
15
|
+
- [x] clipboard integration (Mac Yosemite 10.10)
|
16
|
+
- [ ] autotype (Mac Yosemite 10.10)
|
17
|
+
- [x] clipboard integration (Ubuntu 14.04)
|
18
|
+
- [ ] autotype (Ubuntu 14.04)
|
19
19
|
|
20
20
|
## Installation
|
21
21
|
|
data/kasefet.gemspec
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
lib = File.expand_path(
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
4
|
+
require "kasefet/version"
|
5
|
+
|
6
|
+
require "rbconfig" # for platform data
|
5
7
|
|
6
8
|
Gem::Specification.new do |spec|
|
7
9
|
spec.name = "kasefet"
|
@@ -19,8 +21,15 @@ Gem::Specification.new do |spec|
|
|
19
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
22
|
spec.require_paths = ["lib"]
|
21
23
|
|
24
|
+
spec.add_runtime_dependency "thunder", "~> 0.7"
|
25
|
+
spec.add_runtime_dependency "clipboard", "~> 1.0"
|
26
|
+
|
27
|
+
case RbConfig::CONFIG['host_os']
|
28
|
+
when /windows/
|
29
|
+
spec.add_runtime_dependency "ffi"
|
30
|
+
end
|
31
|
+
|
22
32
|
spec.add_development_dependency "bundler", "~> 1.10"
|
23
33
|
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
-
spec.add_development_dependency "thunder", "~> 0.7"
|
25
34
|
spec.add_development_dependency "minitest"
|
26
35
|
end
|
data/lib/kasefet/cli.rb
CHANGED
@@ -2,6 +2,7 @@ require "thunder"
|
|
2
2
|
|
3
3
|
require "kasefet/config"
|
4
4
|
require "kasefet/wallet"
|
5
|
+
require "kasefet/multi_wallet"
|
5
6
|
|
6
7
|
class Kasefet
|
7
8
|
class CLI
|
@@ -14,17 +15,35 @@ class Kasefet
|
|
14
15
|
|
15
16
|
include Thunder
|
16
17
|
|
17
|
-
|
18
|
+
desc "copy KEYNAME", "copy the contents of KEYNAME to the primary system clipboard"
|
19
|
+
def copy(keyname, **options)
|
20
|
+
load_config(options)
|
21
|
+
load_wallet(options)
|
22
|
+
|
23
|
+
require 'clipboard'
|
24
|
+
|
25
|
+
Clipboard.copy(@wallets.load(keyname))
|
26
|
+
end
|
27
|
+
|
28
|
+
def load_config(options = {})
|
18
29
|
config_file = options[:config]
|
19
30
|
config_file ||= GlobalConfigLocations.find { |file| File.exist?(File.expand_path(file)) }
|
20
31
|
config_file ||= File.expand_path(GlobalConfigLocations.first)
|
21
32
|
@config = Kasefet::Config.new(config_file)
|
33
|
+
@config.load
|
34
|
+
return @config
|
22
35
|
end
|
23
36
|
|
24
|
-
def load_wallet
|
25
|
-
|
26
|
-
|
27
|
-
|
37
|
+
def load_wallet(options = {})
|
38
|
+
wallet_dirs = @config["wallet"]
|
39
|
+
wallet_dirs = @config["wallet"] = File.expand_path(DefaultWalletLocation) unless wallet_dirs
|
40
|
+
wallet_dirs = Array(wallet_dirs)
|
41
|
+
wallets = wallet_dirs.map do |wallet_dir|
|
42
|
+
[wallet_dir, Kasefet::Wallet.new(directory: wallet_dir)]
|
43
|
+
end.to_h
|
44
|
+
|
45
|
+
@wallets = Kasefet::MultiWallet.new(wallets)
|
46
|
+
return @wallets
|
28
47
|
end
|
29
48
|
|
30
49
|
def determine_editor
|
@@ -44,13 +63,13 @@ class Kasefet
|
|
44
63
|
desc "edit KEYNAME", "open the contents of KEYNAME in an editor, and save the changes"
|
45
64
|
def edit(keyname, *content, **options)
|
46
65
|
load_config(options)
|
47
|
-
load_wallet
|
66
|
+
load_wallet(options)
|
48
67
|
|
49
68
|
require 'tmpdir'
|
50
69
|
require 'pathname'
|
51
70
|
Dir.mktmpdir do |tmpdir|
|
52
71
|
tmpdir = Pathname.new(tmpdir)
|
53
|
-
content = @
|
72
|
+
content = @wallets.load(keyname)
|
54
73
|
File.binwrite(tmpdir + keyname, content)
|
55
74
|
|
56
75
|
# invoke the editor
|
@@ -63,7 +82,7 @@ class Kasefet
|
|
63
82
|
puts "`#{editor}` exited with error status: #{$?}. Not saving contents"
|
64
83
|
else
|
65
84
|
new_content = File.binread(tmpdir + keyname)
|
66
|
-
@
|
85
|
+
@wallets.store(keyname, new_content)
|
67
86
|
end
|
68
87
|
end
|
69
88
|
end
|
@@ -71,11 +90,11 @@ class Kasefet
|
|
71
90
|
desc "add KEYNAME CONTENTS...", "store the given CONTENTS in KEYNAME"
|
72
91
|
def add(keyname, *content, **options)
|
73
92
|
load_config(options)
|
74
|
-
load_wallet
|
93
|
+
load_wallet(options)
|
75
94
|
|
76
95
|
content = content.join(" ")
|
77
96
|
|
78
|
-
@
|
97
|
+
@wallets.store(keyname, content)
|
79
98
|
|
80
99
|
return content
|
81
100
|
end
|
@@ -83,9 +102,9 @@ class Kasefet
|
|
83
102
|
desc "show KEYNAME", "print the contents of KEYNAME to stdout"
|
84
103
|
def show(keyname, **options)
|
85
104
|
load_config(options)
|
86
|
-
load_wallet
|
105
|
+
load_wallet(options)
|
87
106
|
|
88
|
-
content = @
|
107
|
+
content = @wallets.load(keyname)
|
89
108
|
|
90
109
|
puts content
|
91
110
|
return content
|
data/lib/kasefet/config.rb
CHANGED
@@ -3,8 +3,6 @@ class Kasefet
|
|
3
3
|
def initialize(file)
|
4
4
|
@file = file
|
5
5
|
@settings = {}
|
6
|
-
return unless File.exists?(file)
|
7
|
-
load
|
8
6
|
end
|
9
7
|
|
10
8
|
attr_accessor :file
|
@@ -18,17 +16,30 @@ class Kasefet
|
|
18
16
|
last_segment[key.split(".")[-1]] = value
|
19
17
|
end
|
20
18
|
|
19
|
+
def each_keys()
|
20
|
+
return @settings.keys.each unless block_given?
|
21
|
+
|
22
|
+
@settings.keys.each do |key|
|
23
|
+
yield key
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
21
27
|
def load
|
22
|
-
|
28
|
+
return unless File.exists?(@file)
|
29
|
+
parse(File.read(@file))
|
30
|
+
end
|
31
|
+
|
32
|
+
def parse(contents, file_path = @file)
|
33
|
+
case File.extname(file_path)
|
23
34
|
when ".yaml", ".yml"
|
24
35
|
require 'yaml'
|
25
|
-
@settings = YAML.load(
|
36
|
+
@settings = YAML.load(contents)
|
26
37
|
when ".json"
|
27
38
|
require 'json'
|
28
|
-
@settings = JSON.parse(
|
39
|
+
@settings = JSON.parse(contents)
|
29
40
|
else
|
30
41
|
# try the key=value format
|
31
|
-
content =
|
42
|
+
content = contents
|
32
43
|
content.split("\n").each do |line|
|
33
44
|
key, value = line.split("=")
|
34
45
|
value = value.to_i if value =~ /\d+/
|
@@ -43,15 +54,19 @@ class Kasefet
|
|
43
54
|
end
|
44
55
|
|
45
56
|
def save
|
46
|
-
|
57
|
+
File.write(@file, format())
|
58
|
+
end
|
59
|
+
|
60
|
+
def format(file_path = @file)
|
61
|
+
case File.extname(file_path)
|
47
62
|
when ".json"
|
48
63
|
require 'json'
|
49
|
-
|
64
|
+
return @settings.to_json
|
50
65
|
when ".yaml", ".yml"
|
51
66
|
require 'yaml'
|
52
|
-
|
67
|
+
return @settings.to_yaml
|
53
68
|
else
|
54
|
-
|
69
|
+
return flatten_hash(@settings).map do |key, value|
|
55
70
|
if value.is_a? Array
|
56
71
|
value.map do |array_value|
|
57
72
|
"#{key}=#{array_value}"
|
@@ -60,7 +75,6 @@ class Kasefet
|
|
60
75
|
"#{key}=#{value}"
|
61
76
|
end
|
62
77
|
end.join("\n")
|
63
|
-
File.write(@file, to_write)
|
64
78
|
end
|
65
79
|
end
|
66
80
|
|
@@ -8,13 +8,19 @@ class Kasefet
|
|
8
8
|
CipherIVLength = 12
|
9
9
|
CipherAuthTagLength = 16
|
10
10
|
|
11
|
-
def initialize(cipher_key:, **options)
|
11
|
+
def initialize(cipher_key:, key_salt: nil, **options)
|
12
12
|
super(**options)
|
13
13
|
@cipher = OpenSSL::Cipher.new("aes-256-gcm")
|
14
14
|
@cipher_key = cipher_key
|
15
|
+
@key_salt = key_salt
|
15
16
|
end
|
16
17
|
|
17
|
-
attr_accessor :cipher_key
|
18
|
+
attr_accessor :cipher_key, :key_salt
|
19
|
+
|
20
|
+
def key_to_digest(key)
|
21
|
+
key = "#{@key_salt}/#{key}/#{@key_salt}" if @key_salt
|
22
|
+
return super(key)
|
23
|
+
end
|
18
24
|
|
19
25
|
def reencrypt_all_values!(new_key)
|
20
26
|
old_key = @cipher_key
|
@@ -51,14 +57,14 @@ class Kasefet
|
|
51
57
|
return value
|
52
58
|
end
|
53
59
|
|
54
|
-
def
|
55
|
-
|
56
|
-
return nil if
|
57
|
-
return decrypt_value(
|
60
|
+
def read_file(file_path)
|
61
|
+
encrypted_contents = super(file_path)
|
62
|
+
return nil if encrypted_contents.nil?
|
63
|
+
return decrypt_value(encrypted_contents, @cipher_key)
|
58
64
|
end
|
59
65
|
|
60
|
-
def
|
61
|
-
super(
|
66
|
+
def write_file(path, contents)
|
67
|
+
return super(path, encrypt_value(contents, @cipher_key))
|
62
68
|
end
|
63
69
|
end
|
64
70
|
end
|
data/lib/kasefet/flat_kv.rb
CHANGED
@@ -8,6 +8,8 @@ class Kasefet
|
|
8
8
|
#
|
9
9
|
# Flat-file based key-value storage engine that is designed to be compatible with naive sync programs
|
10
10
|
class FlatKV
|
11
|
+
MagicNumber = "KSFT"
|
12
|
+
|
11
13
|
# @option [String] :root The root directory of the FlatKV store
|
12
14
|
# @option [String] :device_name The device name to use to identify the writer
|
13
15
|
# @option [String] :extension The default extension to use for the value files
|
@@ -26,15 +28,44 @@ class Kasefet
|
|
26
28
|
|
27
29
|
def [](key)
|
28
30
|
value_file = file_for_key(key)
|
29
|
-
|
30
|
-
|
31
|
+
contents = read_file(value_file)
|
32
|
+
_, value = read_value(contents)
|
33
|
+
return value
|
34
|
+
end
|
35
|
+
|
36
|
+
def read_file(file_path)
|
37
|
+
return nil unless file_path
|
38
|
+
return File.binread(file_path)
|
39
|
+
end
|
40
|
+
|
41
|
+
def read_value(file_contents)
|
42
|
+
return nil, nil unless file_contents
|
43
|
+
|
44
|
+
raise "FlatKV value file must be at least 8 bytes long" unless file_contents.bytesize >= 8
|
45
|
+
magic_number, key_size, file_contents = file_contents.unpack("A4NA*")
|
46
|
+
raise "FlatKV value file must be a KSFT file" unless magic_number == MagicNumber
|
47
|
+
raise "FlatKV value file has been corrupted. Key length in header is longer than file" unless file_contents.bytesize >= key_size
|
48
|
+
key_name, file_contents = file_contents.unpack("A#{key_size}A*")
|
49
|
+
|
50
|
+
return key_name, file_contents
|
31
51
|
end
|
32
52
|
|
33
53
|
def []=(key, value)
|
34
54
|
key_dir = dir_for_key(key)
|
35
55
|
FileUtils.mkdir_p(key_dir)
|
36
56
|
value_file_name = Time.now.strftime("%Y%m%d.%H%M%S%6N.") + @device_name + @extension
|
37
|
-
|
57
|
+
|
58
|
+
value = format_value(key, value)
|
59
|
+
|
60
|
+
write_file(key_dir + value_file_name, value)
|
61
|
+
end
|
62
|
+
|
63
|
+
def format_value(key, value)
|
64
|
+
[MagicNumber, key.bytesize, key, value].pack("A4NA*A*")
|
65
|
+
end
|
66
|
+
|
67
|
+
def write_file(path, contents)
|
68
|
+
File.binwrite(path, contents)
|
38
69
|
end
|
39
70
|
|
40
71
|
def file_for_key(key)
|
@@ -44,8 +75,12 @@ class Kasefet
|
|
44
75
|
return files.last
|
45
76
|
end
|
46
77
|
|
78
|
+
def key_to_digest(key)
|
79
|
+
OpenSSL::Digest::SHA256.hexdigest(key)
|
80
|
+
end
|
81
|
+
|
47
82
|
def dir_for_key(key)
|
48
|
-
digest =
|
83
|
+
digest = key_to_digest(key)
|
49
84
|
return @root + digest[0..1] + digest[2..-1]
|
50
85
|
end
|
51
86
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
require 'kasefet/flat_kv'
|
4
|
+
require 'kasefet/config'
|
5
|
+
|
6
|
+
class Kasefet
|
7
|
+
class IndexedFlatKV
|
8
|
+
def initialize(flat_kv:, index_dir: "index", index_ext: "")
|
9
|
+
@flat_kv = flat_kv
|
10
|
+
@root = flat_kv.root
|
11
|
+
@index_dir = @root + "#{index_dir}"
|
12
|
+
@index_file = @index_dir + "index#{index_ext}"
|
13
|
+
@index = Kasefet::Config.new(@index_file)
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_accessor :index, :index_file
|
17
|
+
|
18
|
+
def [](key)
|
19
|
+
return @flat_kv[key]
|
20
|
+
end
|
21
|
+
|
22
|
+
def []=(key, value)
|
23
|
+
mark_key(key, @flat_kv.key_to_digest(key))
|
24
|
+
return @flat_kv[key] = value
|
25
|
+
end
|
26
|
+
|
27
|
+
def load_index
|
28
|
+
index_contents = @flat_kv.read_file(@index_file)
|
29
|
+
@index.parse(index_contents)
|
30
|
+
end
|
31
|
+
|
32
|
+
def conflicted?
|
33
|
+
Dir[@index_dir + "*"].size != 1
|
34
|
+
end
|
35
|
+
|
36
|
+
def rebuild_index
|
37
|
+
Dir.foreach(@root) do |prefix|
|
38
|
+
next unless prefix =~ /\h\h/
|
39
|
+
Dir.foreach(@root + prefix) do |key_dir|
|
40
|
+
next unless key_dir =~ /\h{62}/ # SHA256 digest is 64 bytes, first two are the prefix
|
41
|
+
Dir.foreach(@root + prefix + key_dir) do |value_file|
|
42
|
+
next if [".", ".."].include?(value_file)
|
43
|
+
value_path = @root + prefix + key_dir + value_file
|
44
|
+
contents = @flat_kv.read_file(value_path)
|
45
|
+
key_name, value = @flat_kv.read_value(contents)
|
46
|
+
mark_key(key_name, prefix + key_dir)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def mark_key(key, digest)
|
53
|
+
@index["dig:" + digest] = key
|
54
|
+
@index["key:" + key] = digest
|
55
|
+
end
|
56
|
+
|
57
|
+
def save_index
|
58
|
+
index_contents = @index.format
|
59
|
+
FileUtils.mkdir_p(@index_dir)
|
60
|
+
@flat_kv.write_file(@index.file, index_contents)
|
61
|
+
end
|
62
|
+
|
63
|
+
def has_key?(key)
|
64
|
+
return !! @index["key:" + key]
|
65
|
+
end
|
66
|
+
|
67
|
+
def each_keys
|
68
|
+
return enum_for(__method__) unless block_given?
|
69
|
+
|
70
|
+
@index.each_keys do |key|
|
71
|
+
next unless key.start_with?("key:")
|
72
|
+
yield key[4..-1]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "kasefet/wallet"
|
2
|
+
|
3
|
+
class Kasefet
|
4
|
+
class MultiWallet
|
5
|
+
def initialize(wallets)
|
6
|
+
@wallets = wallets
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_accessor :wallets
|
10
|
+
|
11
|
+
def load(keyname)
|
12
|
+
@wallets.each do |name, wallet|
|
13
|
+
contents = wallet.load(keyname)
|
14
|
+
return contents unless contents.nil?
|
15
|
+
end
|
16
|
+
return nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def store(keyname, content, name = nil)
|
20
|
+
name ||= @wallets.keys.first
|
21
|
+
@wallets[name].store(keyname, content)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/kasefet/version.rb
CHANGED
data/lib/kasefet/wallet.rb
CHANGED
@@ -27,22 +27,21 @@ class Kasefet
|
|
27
27
|
@wallet_version = @wallet_version.to_i
|
28
28
|
raise "Unknown Kasefet Wallet version: #{@wallet_version}" unless @wallet_version <= VERSION
|
29
29
|
|
30
|
-
@
|
31
|
-
|
30
|
+
@credentials = Kasefet::EncryptedFlatKV.new(
|
31
|
+
root: @root + CREDENTIALS_DIR,
|
32
|
+
cipher_key: @master_key.key,
|
33
|
+
key_salt: @metadata["kasefet.name_salt"],
|
34
|
+
)
|
32
35
|
end
|
33
36
|
|
34
37
|
attr_accessor :root
|
35
38
|
|
36
|
-
def salted_keyname(name)
|
37
|
-
return "#{@name_salt}/#{name}/#{@name_salt}"
|
38
|
-
end
|
39
|
-
|
40
39
|
def load(name)
|
41
|
-
return @credentials[
|
40
|
+
return @credentials[name]
|
42
41
|
end
|
43
42
|
|
44
43
|
def store(name, creds)
|
45
|
-
@credentials[
|
44
|
+
@credentials[name] = creds
|
46
45
|
end
|
47
46
|
end
|
48
47
|
end
|
metadata
CHANGED
@@ -1,57 +1,71 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kasefet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steven Karas
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-03-
|
11
|
+
date: 2016-03-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: thunder
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
20
|
-
type: :
|
19
|
+
version: '0.7'
|
20
|
+
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '0.7'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: clipboard
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '1.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.10'
|
34
48
|
type: :development
|
35
49
|
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
52
|
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
|
-
version: '10
|
54
|
+
version: '1.10'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
56
|
+
name: rake
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
59
|
- - "~>"
|
46
60
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0
|
61
|
+
version: '10.0'
|
48
62
|
type: :development
|
49
63
|
prerelease: false
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
51
65
|
requirements:
|
52
66
|
- - "~>"
|
53
67
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0
|
68
|
+
version: '10.0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: minitest
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -91,7 +105,9 @@ files:
|
|
91
105
|
- lib/kasefet/config.rb
|
92
106
|
- lib/kasefet/encrypted_flat_kv.rb
|
93
107
|
- lib/kasefet/flat_kv.rb
|
108
|
+
- lib/kasefet/indexed_flat_kv.rb
|
94
109
|
- lib/kasefet/master_key.rb
|
110
|
+
- lib/kasefet/multi_wallet.rb
|
95
111
|
- lib/kasefet/version.rb
|
96
112
|
- lib/kasefet/wallet.rb
|
97
113
|
homepage: https://github.com/stevenkaras/kasefet
|