kstor 0.4.3 → 0.5.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/README.md +6 -2
- data/bin/kstor +48 -40
- data/bin/kstor-srv +2 -2
- data/lib/kstor/config.rb +2 -1
- data/lib/kstor/controller/authentication.rb +25 -4
- data/lib/kstor/controller/base.rb +61 -0
- data/lib/kstor/controller/request_handler.rb +84 -16
- data/lib/kstor/controller/secret.rb +63 -64
- data/lib/kstor/controller/users.rb +11 -22
- data/lib/kstor/controller.rb +3 -3
- data/lib/kstor/crypto/armored_value.rb +82 -0
- data/lib/kstor/crypto/keys.rb +9 -41
- data/lib/kstor/crypto.rb +0 -1
- data/lib/kstor/error.rb +36 -3
- data/lib/kstor/log/simple_logger.rb +83 -0
- data/lib/kstor/log/systemd_logger.rb +22 -0
- data/lib/kstor/log.rb +53 -4
- data/lib/kstor/message/base.rb +223 -0
- data/lib/kstor/message/error.rb +15 -0
- data/lib/kstor/message/group_create.rb +14 -0
- data/lib/kstor/message/group_created.rb +16 -0
- data/lib/kstor/message/ping.rb +14 -0
- data/lib/kstor/message/pong.rb +14 -0
- data/lib/kstor/message/secret_create.rb +16 -0
- data/lib/kstor/message/secret_created.rb +14 -0
- data/lib/kstor/message/secret_delete.rb +14 -0
- data/lib/kstor/message/secret_deleted.rb +14 -0
- data/lib/kstor/message/secret_list.rb +14 -0
- data/lib/kstor/message/secret_search.rb +14 -0
- data/lib/kstor/message/secret_unlock.rb +14 -0
- data/lib/kstor/message/secret_update_meta.rb +15 -0
- data/lib/kstor/message/secret_update_value.rb +15 -0
- data/lib/kstor/message/secret_updated.rb +14 -0
- data/lib/kstor/message/secret_value.rb +35 -0
- data/lib/kstor/message.rb +26 -113
- data/lib/kstor/model.rb +42 -25
- data/lib/kstor/server.rb +15 -3
- data/lib/kstor/session.rb +34 -2
- data/lib/kstor/socket_server.rb +20 -1
- data/lib/kstor/sql_connection.rb +16 -1
- data/lib/kstor/store.rb +182 -72
- data/lib/kstor/systemd.rb +5 -0
- data/lib/kstor/version.rb +2 -1
- data/lib/kstor.rb +1 -1
- metadata +25 -3
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'kstor/store'
|
4
4
|
require 'kstor/model'
|
5
5
|
require 'kstor/crypto'
|
6
|
+
require 'kstor/controller/base'
|
6
7
|
|
7
8
|
module KStor
|
8
9
|
class SecretNotFound < Error
|
@@ -12,79 +13,70 @@ module KStor
|
|
12
13
|
|
13
14
|
module Controller
|
14
15
|
# Handle secret-related requests.
|
15
|
-
class Secret
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
else
|
29
|
-
raise Error.for_code('REQ/UNKNOWN', req.type)
|
30
|
-
end
|
31
|
-
end
|
16
|
+
class Secret < Base
|
17
|
+
request_type Message::SecretCreate
|
18
|
+
request_type Message::SecretSearch
|
19
|
+
request_type Message::SecretUnlock
|
20
|
+
request_type Message::SecretUpdateMeta
|
21
|
+
request_type Message::SecretUpdateValue
|
22
|
+
request_type Message::SecretDelete
|
23
|
+
|
24
|
+
response_type Message::SecretCreated
|
25
|
+
response_type Message::SecretList
|
26
|
+
response_type Message::SecretValue
|
27
|
+
response_type Message::SecretUpdated
|
28
|
+
response_type Message::SecretDeleted
|
32
29
|
|
33
30
|
private
|
34
31
|
|
35
|
-
def
|
36
|
-
meta = Model::SecretMeta.new(**req.
|
37
|
-
secret_groups = req.
|
38
|
-
|
39
|
-
user, req.args['plaintext'], secret_groups, meta
|
40
|
-
)
|
41
|
-
Response.new('secret.created', 'secret_id' => secret_id)
|
42
|
-
end
|
43
|
-
|
44
|
-
def handle_search(user, req)
|
45
|
-
secrets = search(user, Model::SecretMeta.new(**req.args))
|
46
|
-
args = secrets.map do |s|
|
47
|
-
h = s.to_h
|
48
|
-
h.delete('group_id')
|
49
|
-
h
|
32
|
+
def handle_secret_create(user, req)
|
33
|
+
meta = Model::SecretMeta.new(**req.meta)
|
34
|
+
secret_groups = req.group_ids.map do |gid|
|
35
|
+
@store.groups[gid.to_i]
|
50
36
|
end
|
51
|
-
|
52
|
-
'
|
53
|
-
|
54
|
-
|
37
|
+
args = {
|
38
|
+
'secret_id' => create(user, req.plaintext, secret_groups, meta)
|
39
|
+
}
|
40
|
+
[Message::SecretCreated, args]
|
55
41
|
end
|
56
42
|
|
57
|
-
def
|
58
|
-
|
59
|
-
|
43
|
+
def handle_secret_search(user, req)
|
44
|
+
Log.debug("secretcontroller#handle_secret_search: #{req.args.inspect}")
|
45
|
+
secrets = search(user, Model::SecretMeta.new(**req.meta))
|
46
|
+
args = { 'secrets' => secrets.map { |s| s.to_h.except('group_id') } }
|
47
|
+
[Message::SecretList, args]
|
48
|
+
end
|
49
|
+
|
50
|
+
def handle_secret_unlock(user, req)
|
51
|
+
secret = unlock(user, req.secret_id)
|
60
52
|
args = unlock_format(secret)
|
61
53
|
|
62
|
-
|
54
|
+
[Message::SecretValue, args]
|
63
55
|
end
|
64
56
|
|
65
|
-
def
|
66
|
-
meta = Model::SecretMeta.new(req.
|
57
|
+
def handle_secret_update_meta(user, req)
|
58
|
+
meta = Model::SecretMeta.new(req.meta)
|
67
59
|
Log.debug("secret#handle_update_meta: meta=#{meta.to_h.inspect}")
|
68
|
-
update_meta(user, req.
|
69
|
-
|
60
|
+
update_meta(user, req.secret_id, meta)
|
61
|
+
[Message::SecretUpdated, { 'secret_id' => req.secret_id }]
|
70
62
|
end
|
71
63
|
|
72
|
-
def
|
73
|
-
update_value(user, req.
|
74
|
-
|
64
|
+
def handle_secret_update_value(user, req)
|
65
|
+
update_value(user, req.secret_id, req.plaintext)
|
66
|
+
[Message::SecretUpdated, { 'secret_id' => req.secret_id }]
|
75
67
|
end
|
76
68
|
|
77
|
-
def
|
78
|
-
delete(user, req.
|
79
|
-
|
69
|
+
def handle_secret_delete(user, req)
|
70
|
+
delete(user, req.secret_id)
|
71
|
+
[Message::SecretDeleted, { 'secret_id' => req.secret_id }]
|
80
72
|
end
|
81
73
|
|
82
74
|
def users
|
83
|
-
@
|
75
|
+
@store.users
|
84
76
|
end
|
85
77
|
|
86
78
|
def groups
|
87
|
-
@
|
79
|
+
@store.groups
|
88
80
|
end
|
89
81
|
|
90
82
|
# in: metadata wildcards
|
@@ -106,13 +98,13 @@ module KStor
|
|
106
98
|
# needs: private key of one common group between user and secret
|
107
99
|
# out: plaintext
|
108
100
|
def unlock(user, secret_id)
|
109
|
-
secret =
|
101
|
+
secret = secret_fetch(secret_id, user.id)
|
110
102
|
group_privk = user.keychain[secret.group_id].privk
|
111
103
|
|
112
|
-
value_author = users[secret.value_author_id]
|
104
|
+
value_author = @store.users[secret.value_author_id]
|
113
105
|
secret.unlock(value_author.pubk, group_privk)
|
114
106
|
|
115
|
-
meta_author = users[secret.meta_author_id]
|
107
|
+
meta_author = @store.users[secret.meta_author_id]
|
116
108
|
secret.unlock_metadata(meta_author.pubk, group_privk)
|
117
109
|
|
118
110
|
secret
|
@@ -137,12 +129,12 @@ module KStor
|
|
137
129
|
# needs: every group public key for this secret, user private key
|
138
130
|
# out: nil
|
139
131
|
def update_meta(user, secret_id, partial_meta)
|
140
|
-
secret =
|
132
|
+
secret = secret_fetch(secret_id, user.id)
|
141
133
|
unlock_metadata(user, secret)
|
142
134
|
meta = secret.metadata.merge(partial_meta)
|
143
135
|
group_ids = @store.groups_for_secret(secret.id)
|
144
136
|
group_encrypted_metadata = group_ids.to_h do |group_id|
|
145
|
-
group_pubk = groups[group_id].pubk
|
137
|
+
group_pubk = @store.groups[group_id].pubk
|
146
138
|
author_privk = user.privk
|
147
139
|
encrypted_meta = Crypto.encrypt_secret_metadata(
|
148
140
|
group_pubk, author_privk, meta.to_h
|
@@ -156,10 +148,10 @@ module KStor
|
|
156
148
|
# needs: every group public key for this secret, user private key
|
157
149
|
# out: nil
|
158
150
|
def update_value(user, secret_id, plaintext)
|
159
|
-
secret =
|
151
|
+
secret = secret_fetch(secret_id, user.id)
|
160
152
|
group_ids = @store.groups_for_secret(secret.id)
|
161
153
|
group_ciphertexts = group_ids.to_h do |group_id|
|
162
|
-
group_pubk = groups[group_id].pubk
|
154
|
+
group_pubk = @store.groups[group_id].pubk
|
163
155
|
author_privk = user.privk
|
164
156
|
encrypted_value = Crypto.encrypt_secret_value(
|
165
157
|
group_pubk, author_privk, plaintext
|
@@ -174,7 +166,7 @@ module KStor
|
|
174
166
|
# out: nil
|
175
167
|
def delete(user, secret_id)
|
176
168
|
# Check if user can see this secret:
|
177
|
-
secret =
|
169
|
+
secret = secret_fetch(secret_id, user.id)
|
178
170
|
raise Error.for_code('SECRET/NOTFOUND', secret_id) if secret.nil?
|
179
171
|
|
180
172
|
@store.secret_delete(secret_id)
|
@@ -182,20 +174,27 @@ module KStor
|
|
182
174
|
|
183
175
|
def unlock_format(secret)
|
184
176
|
args = secret.to_h
|
185
|
-
args['value_author'] = users[secret.value_author_id].to_h
|
186
|
-
args['metadata_author'] = users[secret.meta_author_id].to_h
|
177
|
+
args['value_author'] = @store.users[secret.value_author_id].to_h
|
178
|
+
args['metadata_author'] = @store.users[secret.meta_author_id].to_h
|
187
179
|
|
188
180
|
group_ids = @store.groups_for_secret(secret.id)
|
189
|
-
args['groups'] = groups.values_at(*group_ids).map(&:to_h)
|
181
|
+
args['groups'] = @store.groups.values_at(*group_ids).map(&:to_h)
|
190
182
|
|
191
183
|
args
|
192
184
|
end
|
193
185
|
|
194
186
|
def unlock_metadata(user, secret)
|
195
187
|
group_privk = user.keychain[secret.group_id].privk
|
196
|
-
author = users[secret.meta_author_id]
|
188
|
+
author = @store.users[secret.meta_author_id]
|
197
189
|
secret.unlock_metadata(author.pubk, group_privk)
|
198
190
|
end
|
191
|
+
|
192
|
+
def secret_fetch(secret_id, user_id)
|
193
|
+
secret = @store.secret_fetch(secret_id, user_id)
|
194
|
+
raise Error.for_code('SECRET/NOTFOUND', secret_id) if secret.nil?
|
195
|
+
|
196
|
+
secret
|
197
|
+
end
|
199
198
|
end
|
200
199
|
end
|
201
200
|
end
|
@@ -4,36 +4,25 @@ require 'kstor/store'
|
|
4
4
|
require 'kstor/model'
|
5
5
|
require 'kstor/crypto'
|
6
6
|
require 'kstor/log'
|
7
|
+
require 'kstor/controller/base'
|
7
8
|
|
8
9
|
module KStor
|
9
10
|
module Controller
|
10
11
|
# Handle user and group related requests.
|
11
|
-
class User
|
12
|
-
|
13
|
-
|
14
|
-
end
|
15
|
-
|
16
|
-
def handle_request(user, req)
|
17
|
-
case req.type
|
18
|
-
when /^group-create$/ then handle_group_create(user, req)
|
19
|
-
end
|
20
|
-
end
|
12
|
+
class User < Base
|
13
|
+
request_type Message::GroupCreate
|
14
|
+
response_type Message::GroupCreated
|
21
15
|
|
22
16
|
private
|
23
17
|
|
24
18
|
def handle_group_create(user, req)
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
'group.created',
|
33
|
-
'group_id' => group.id,
|
34
|
-
'group_name' => group.name,
|
35
|
-
'group_pubk' => group.pubk
|
36
|
-
)
|
19
|
+
group = group_create(user, req.name)
|
20
|
+
args = {
|
21
|
+
group_id: group.id,
|
22
|
+
group_name: group.name,
|
23
|
+
group_pubk: group.pubk
|
24
|
+
}
|
25
|
+
[Message::GroupCreated, args]
|
37
26
|
end
|
38
27
|
|
39
28
|
def group_create(user, name)
|
data/lib/kstor/controller.rb
CHANGED
@@ -34,8 +34,8 @@ module KStor
|
|
34
34
|
end
|
35
35
|
|
36
36
|
# Error: missing request argument.
|
37
|
-
class
|
38
|
-
error_code 'REQ/
|
39
|
-
error_message 'Missing argument %s for
|
37
|
+
class MissingMessageArgument < Error
|
38
|
+
error_code 'REQ/MISSINGARGS'
|
39
|
+
error_message 'Missing argument(s) %s for message type %s'
|
40
40
|
end
|
41
41
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kstor/crypto/ascii_armor'
|
4
|
+
|
5
|
+
module KStor
|
6
|
+
module Crypto
|
7
|
+
# Wrapper class for an ASCII-armored value.
|
8
|
+
class ArmoredValue
|
9
|
+
# Create a new ASCII-armored value.
|
10
|
+
#
|
11
|
+
# @param value [String] ASCII-armored string
|
12
|
+
# @return [KStor::Crypto::ArmoredValue] new armored value
|
13
|
+
#
|
14
|
+
# @see KStor::Crypto::ASCIIArmor#decode
|
15
|
+
# @see KStor::Crypto::ASCIIArmor#encode
|
16
|
+
def initialize(value)
|
17
|
+
@value = value
|
18
|
+
end
|
19
|
+
|
20
|
+
# Serialize value.
|
21
|
+
#
|
22
|
+
# @return [String] serialized value
|
23
|
+
def to_ascii
|
24
|
+
@value
|
25
|
+
end
|
26
|
+
alias to_s to_ascii
|
27
|
+
|
28
|
+
# Get back original value.
|
29
|
+
#
|
30
|
+
# @return [String] binary data
|
31
|
+
def to_binary
|
32
|
+
ASCIIArmor.decode(@value)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Create from binary data
|
36
|
+
#
|
37
|
+
# @param bin_str [String] binary data
|
38
|
+
# @return [KStor::Crypto::ArmoredValue] new value
|
39
|
+
def self.from_binary(bin_str)
|
40
|
+
new(ASCIIArmor.encode(bin_str))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# A Hash that can be easily serialized to ASCII chars.
|
45
|
+
#
|
46
|
+
# Uses JSON as intermediary data format.
|
47
|
+
class ArmoredHash < ArmoredValue
|
48
|
+
# Create from Ruby Hash.
|
49
|
+
#
|
50
|
+
# @param hash [Hash] a Ruby Hash.
|
51
|
+
# @return [KStor::Crypto::ArmoredHash] new hash
|
52
|
+
def self.from_hash(hash)
|
53
|
+
from_binary(hash.to_json)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Convert to Ruby Hash.
|
57
|
+
#
|
58
|
+
# @return [Hash] new Ruby Hash
|
59
|
+
def to_hash
|
60
|
+
JSON.parse(to_binary)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Access value for this key.
|
64
|
+
#
|
65
|
+
# @param key [String] what to lookup
|
66
|
+
# @return [Any, nil] value
|
67
|
+
def [](key)
|
68
|
+
to_hash[key]
|
69
|
+
end
|
70
|
+
|
71
|
+
# Set value for a key.
|
72
|
+
#
|
73
|
+
# @param key [String] hash key
|
74
|
+
# @param val [Any] hash value
|
75
|
+
def []=(key, val)
|
76
|
+
h = to_hash
|
77
|
+
h[key] = val
|
78
|
+
@value = ASCIIArmor.encode(h.to_json)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/kstor/crypto/keys.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'kstor/crypto/ascii_armor'
|
4
|
+
require 'kstor/crypto/armored_value'
|
4
5
|
|
5
6
|
module KStor
|
6
7
|
module Crypto
|
@@ -39,49 +40,13 @@ module KStor
|
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
42
|
-
# Wrapper class for an ASCII-armored value.
|
43
|
-
class ArmoredValue
|
44
|
-
def initialize(value)
|
45
|
-
@value = value
|
46
|
-
end
|
47
|
-
|
48
|
-
def to_ascii
|
49
|
-
@value
|
50
|
-
end
|
51
|
-
alias to_s to_ascii
|
52
|
-
|
53
|
-
def to_binary
|
54
|
-
ASCIIArmor.decode(@value)
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.from_binary(bin_str)
|
58
|
-
new(ASCIIArmor.encode(bin_str))
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
# A Hash.
|
63
|
-
class ArmoredHash < ArmoredValue
|
64
|
-
def self.from_hash(hash)
|
65
|
-
from_binary(hash.to_json)
|
66
|
-
end
|
67
|
-
|
68
|
-
def to_hash
|
69
|
-
JSON.parse(to_binary)
|
70
|
-
end
|
71
|
-
|
72
|
-
def [](key)
|
73
|
-
to_hash[key]
|
74
|
-
end
|
75
|
-
|
76
|
-
def []=(key, val)
|
77
|
-
h = to_hash
|
78
|
-
h[key] = val
|
79
|
-
@value = ASCIIArmor.encode(h.to_json)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
43
|
# KDF parameters.
|
84
44
|
class KDFParams < ArmoredHash
|
45
|
+
# Create new Key Derivation Function parameters from a Ruby Hash.
|
46
|
+
#
|
47
|
+
# Hash parameter must have keys for "salt"," opslimit" and "memlimit".
|
48
|
+
#
|
49
|
+
# @param hash [Hash] KDF parameters data.
|
85
50
|
def self.from_hash(hash)
|
86
51
|
hash['salt'] = ASCIIArmor.encode(hash['salt'])
|
87
52
|
hash['opslimit'] = hash['opslimit'].to_s
|
@@ -89,6 +54,7 @@ module KStor
|
|
89
54
|
super(hash)
|
90
55
|
end
|
91
56
|
|
57
|
+
# Convert back to a Ruby Hash.
|
92
58
|
def to_hash
|
93
59
|
hash = super
|
94
60
|
hash['salt'] = ASCIIArmor.decode(hash['salt'])
|
@@ -101,6 +67,7 @@ module KStor
|
|
101
67
|
|
102
68
|
# A private key.
|
103
69
|
class PrivateKey < ArmoredValue
|
70
|
+
# Convert ASCII-armored value to a RbNaCl private key.
|
104
71
|
def to_rbnacl
|
105
72
|
RbNaCl::PrivateKey.new(to_binary)
|
106
73
|
end
|
@@ -108,6 +75,7 @@ module KStor
|
|
108
75
|
|
109
76
|
# A public key.
|
110
77
|
class PublicKey < ArmoredValue
|
78
|
+
# Convert ASCII-armored value to a RbNaCl public key.
|
111
79
|
def to_rbnacl
|
112
80
|
RbNaCl::PublicKey.new(to_binary)
|
113
81
|
end
|
data/lib/kstor/crypto.rb
CHANGED
@@ -39,7 +39,6 @@ module KStor
|
|
39
39
|
# @return [SecretKey] secret key and KDF parameters
|
40
40
|
def key_derive(passphrase, params = nil)
|
41
41
|
params ||= key_derive_params_generate
|
42
|
-
Log.debug("crypto: kdf params = #{params.to_hash}")
|
43
42
|
data = RbNaCl::PasswordHash.argon2(
|
44
43
|
passphrase, params['salt'],
|
45
44
|
params['opslimit'], params['memlimit'], params['digest_size']
|
data/lib/kstor/error.rb
CHANGED
@@ -12,26 +12,41 @@ module KStor
|
|
12
12
|
attr_reader :message
|
13
13
|
attr_reader :registry
|
14
14
|
|
15
|
+
# Declare error code for a subclass.
|
16
|
+
#
|
17
|
+
# @param str [String] unique error code.
|
15
18
|
def error_code(str)
|
16
19
|
@code = str
|
17
20
|
end
|
18
21
|
|
22
|
+
# Declare error message for a subclass.
|
23
|
+
#
|
24
|
+
# This will be passed to String#format as a format string.
|
25
|
+
#
|
26
|
+
# @param str [String] error message or format.
|
19
27
|
def error_message(str)
|
20
28
|
@message = str
|
21
29
|
end
|
22
30
|
|
31
|
+
# Create a new error for this code.
|
32
|
+
#
|
33
|
+
# @param code [String] error code
|
34
|
+
# @param args [Array] arguments to subclass initialize method.
|
23
35
|
def for_code(code, *args)
|
24
36
|
@registry[code].new(*args)
|
25
37
|
end
|
26
38
|
|
39
|
+
# List of all subclasses.
|
27
40
|
def list
|
28
41
|
@registry.classes
|
29
42
|
end
|
30
43
|
end
|
31
44
|
|
45
|
+
# When subclassed, add child to registry.
|
46
|
+
#
|
47
|
+
# @param subclass [Class] subclass to add to error registry.
|
32
48
|
def self.inherited(subclass)
|
33
49
|
super
|
34
|
-
Log.debug("#{subclass} inherits from Error")
|
35
50
|
@registry ||= ErrorRegistry.new
|
36
51
|
if @registry.key?(subclass.code)
|
37
52
|
code = subclass.code
|
@@ -43,35 +58,53 @@ module KStor
|
|
43
58
|
@registry << subclass
|
44
59
|
end
|
45
60
|
|
61
|
+
# Create new error.
|
62
|
+
#
|
63
|
+
# @param args [Array] arguments to String#format with the message as a
|
64
|
+
# format string.
|
65
|
+
# @return [KStor::Error] instance of subclass of Error.
|
46
66
|
def initialize(*args)
|
47
67
|
super(format("ERR/%s #{self.class.message}", self.class.code, *args))
|
48
68
|
end
|
49
69
|
|
50
|
-
|
51
|
-
|
70
|
+
# Create a new server response from an error.
|
71
|
+
#
|
72
|
+
# @return [KStor::Message::Error] error response
|
73
|
+
def response(sid)
|
74
|
+
Message::Error.new(
|
75
|
+
{ 'code' => self.class.code, 'message' => message },
|
76
|
+
{ session_id: sid }
|
77
|
+
)
|
52
78
|
end
|
53
79
|
end
|
54
80
|
|
81
|
+
# Basically an Array of error subclasses, with an index on error codes.
|
82
|
+
#
|
55
83
|
# @api private
|
56
84
|
class ErrorRegistry
|
85
|
+
# Create new registry.
|
57
86
|
def initialize
|
58
87
|
@error_classes = []
|
59
88
|
@index = nil
|
60
89
|
end
|
61
90
|
|
91
|
+
# List of subclasses.
|
62
92
|
def classes
|
63
93
|
@error_classes.values
|
64
94
|
end
|
65
95
|
|
96
|
+
# Append an error class.
|
66
97
|
def <<(klass)
|
67
98
|
@error_classes << klass
|
68
99
|
@index = nil
|
69
100
|
end
|
70
101
|
|
102
|
+
# True if registry knows a subclass with this error code.
|
71
103
|
def key?(code)
|
72
104
|
index.key?(code)
|
73
105
|
end
|
74
106
|
|
107
|
+
# Return subclass for this error code.
|
75
108
|
def [](code)
|
76
109
|
index[code]
|
77
110
|
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module KStor
|
6
|
+
# rubocop:disable Style/Documentation
|
7
|
+
module Log
|
8
|
+
# rubocop:enable Style/Documentation
|
9
|
+
|
10
|
+
# Simple logger using Ruby Logger.
|
11
|
+
#
|
12
|
+
# It just defines some convenient methods that Journald::Logger has.
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
class SimpleLogger
|
16
|
+
# Create a new logger.
|
17
|
+
#
|
18
|
+
# @return [KStor::Log::SimpleLogger] a simple logger to STDOUT
|
19
|
+
def initialize
|
20
|
+
@logger = Logger.new($stdout)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Set minimum log level
|
24
|
+
#
|
25
|
+
# @param lvl [Integer] log level from constants in Logger class
|
26
|
+
def level=(lvl)
|
27
|
+
@logger.level = lvl
|
28
|
+
end
|
29
|
+
|
30
|
+
# Log a debug message.
|
31
|
+
#
|
32
|
+
# @param msg [String] message
|
33
|
+
def debug(msg)
|
34
|
+
@logger.debug(msg)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Log an informative message.
|
38
|
+
#
|
39
|
+
# @param msg [String] message
|
40
|
+
def info(msg)
|
41
|
+
@logger.info(msg)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Log a warning.
|
45
|
+
#
|
46
|
+
# @param msg [String] message
|
47
|
+
def warn(msg)
|
48
|
+
@logger.warn(msg)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Log an error message.
|
52
|
+
#
|
53
|
+
# @param msg [String] message
|
54
|
+
def error(msg)
|
55
|
+
@logger.error(msg)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Log an exception with full backtrace and all.
|
59
|
+
#
|
60
|
+
# @param exc [Exception] an exception
|
61
|
+
def exception(exc)
|
62
|
+
@logger.error(exc.full_message)
|
63
|
+
end
|
64
|
+
|
65
|
+
alias notice info
|
66
|
+
alias critical error
|
67
|
+
alias alert error
|
68
|
+
alias emergency error
|
69
|
+
end
|
70
|
+
|
71
|
+
DEBUG = Logger::DEBUG
|
72
|
+
INFO = Logger::INFO
|
73
|
+
WARN = Logger::WARN
|
74
|
+
ERROR = Logger::ERROR
|
75
|
+
|
76
|
+
class << self
|
77
|
+
# Create new simple logger to stdout
|
78
|
+
def create_logger
|
79
|
+
SimpleLogger.new
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'journald/logger'
|
4
|
+
|
5
|
+
module KStor
|
6
|
+
# rubocop:disable Style/Documentation
|
7
|
+
module Log
|
8
|
+
# rubocop:enable Style/Documentation
|
9
|
+
|
10
|
+
DEBUG = Journald::LOG_DEBUG
|
11
|
+
INFO = Journald::LOG_INFO
|
12
|
+
WARN = Journald::LOG_WARNING
|
13
|
+
ERROR = Journald::LOG_ERR
|
14
|
+
|
15
|
+
class << self
|
16
|
+
# Create new systemd journald logger
|
17
|
+
def create_logger
|
18
|
+
Journald::Logger.new('kstor')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|