ruby_event_store 0.39.0 → 0.40.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/ruby_event_store.rb +24 -6
- data/lib/ruby_event_store/broker.rb +43 -0
- data/lib/ruby_event_store/client.rb +3 -3
- data/lib/ruby_event_store/dispatcher.rb +18 -0
- data/lib/ruby_event_store/errors.rb +13 -12
- data/lib/ruby_event_store/event.rb +1 -0
- data/lib/ruby_event_store/mappers.rb +10 -0
- data/lib/ruby_event_store/mappers/default.rb +8 -24
- data/lib/ruby_event_store/mappers/encryption_key.rb +72 -0
- data/lib/ruby_event_store/mappers/encryption_mapper.rb +8 -239
- data/lib/ruby_event_store/mappers/forgotten_data.rb +28 -0
- data/lib/ruby_event_store/mappers/in_memory_encryption_key_repository.rb +32 -0
- data/lib/ruby_event_store/mappers/null_mapper.rb +2 -18
- data/lib/ruby_event_store/mappers/pipeline.rb +29 -0
- data/lib/ruby_event_store/mappers/pipeline_mapper.rb +20 -0
- data/lib/ruby_event_store/mappers/protobuf.rb +9 -47
- data/lib/ruby_event_store/mappers/transformation/domain_event.rb +24 -0
- data/lib/ruby_event_store/mappers/transformation/encryption.rb +125 -0
- data/lib/ruby_event_store/mappers/transformation/event_class_remapper.rb +22 -0
- data/lib/ruby_event_store/mappers/transformation/item.rb +55 -0
- data/lib/ruby_event_store/mappers/transformation/proto_event.rb +15 -0
- data/lib/ruby_event_store/mappers/transformation/protobuf_encoder.rb +28 -0
- data/lib/ruby_event_store/mappers/transformation/protobuf_nested_struct_metadata.rb +29 -0
- data/lib/ruby_event_store/mappers/transformation/serialization.rb +32 -0
- data/lib/ruby_event_store/mappers/transformation/serialized_record.rb +25 -0
- data/lib/ruby_event_store/mappers/transformation/stringify_metadata_keys.rb +22 -0
- data/lib/ruby_event_store/mappers/transformation/symbolize_metadata_keys.rb +22 -0
- data/lib/ruby_event_store/pub_sub.rb +21 -0
- data/lib/ruby_event_store/spec/broker_lint.rb +3 -3
- data/lib/ruby_event_store/spec/dispatcher_lint.rb +2 -2
- data/lib/ruby_event_store/subscriptions.rb +108 -0
- data/lib/ruby_event_store/version.rb +1 -1
- metadata +24 -6
- data/lib/ruby_event_store/pub_sub/broker.rb +0 -45
- data/lib/ruby_event_store/pub_sub/dispatcher.rb +0 -20
- data/lib/ruby_event_store/pub_sub/subscriptions.rb +0 -110
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 257a578c0c9d6dac951fd1a21fc739227b3169cb14af5535b3c782501280461c
|
4
|
+
data.tar.gz: 55b40e9ab1dd90afb841ed1b92a8e950ea6aa3285ce0f187443f92341dbcfb31
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 90fa7cccf1b1832c441b2f63701e2a931afc778f819f9df6152463b90a9533adb087254adb879de64e6a94a4c9f35463da2cc14d481012ff5a0a3e1f6f8240c5
|
7
|
+
data.tar.gz: 70a286e9f88972228b392a4a56ef37035a0d571c9f75b19376313dc8147e518a270f70a2f1097983d6d547e1590c9c51f2005095d4d8229ad3919d3cffd4dac7
|
data/lib/ruby_event_store.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
-
require 'ruby_event_store/
|
2
|
-
require 'ruby_event_store/
|
3
|
-
require 'ruby_event_store/
|
1
|
+
require 'ruby_event_store/dispatcher'
|
2
|
+
require 'ruby_event_store/subscriptions'
|
3
|
+
require 'ruby_event_store/broker'
|
4
|
+
require 'ruby_event_store/pub_sub'
|
4
5
|
require 'ruby_event_store/in_memory_repository'
|
5
6
|
require 'ruby_event_store/projection'
|
6
7
|
require 'ruby_event_store/errors'
|
@@ -15,11 +16,28 @@ require 'ruby_event_store/stream'
|
|
15
16
|
require 'ruby_event_store/expected_version'
|
16
17
|
require 'ruby_event_store/serialized_record'
|
17
18
|
require 'ruby_event_store/transform_keys'
|
19
|
+
require 'ruby_event_store/mappers'
|
20
|
+
require 'ruby_event_store/mappers/encryption_key'
|
21
|
+
require 'ruby_event_store/mappers/in_memory_encryption_key_repository'
|
22
|
+
require 'ruby_event_store/mappers/transformation/domain_event'
|
23
|
+
require 'ruby_event_store/mappers/transformation/encryption'
|
24
|
+
require 'ruby_event_store/mappers/transformation/event_class_remapper'
|
25
|
+
require 'ruby_event_store/mappers/transformation/item'
|
26
|
+
require 'ruby_event_store/mappers/transformation/proto_event'
|
27
|
+
require 'ruby_event_store/mappers/transformation/protobuf_encoder'
|
28
|
+
require 'ruby_event_store/mappers/transformation/protobuf_nested_struct_metadata'
|
29
|
+
require 'ruby_event_store/mappers/transformation/serialization'
|
30
|
+
require 'ruby_event_store/mappers/transformation/serialized_record'
|
31
|
+
require 'ruby_event_store/mappers/transformation/stringify_metadata_keys'
|
32
|
+
require 'ruby_event_store/mappers/transformation/symbolize_metadata_keys'
|
33
|
+
require 'ruby_event_store/mappers/pipeline'
|
34
|
+
require 'ruby_event_store/mappers/pipeline_mapper'
|
18
35
|
require 'ruby_event_store/mappers/default'
|
19
|
-
require 'ruby_event_store/mappers/
|
20
|
-
require 'ruby_event_store/mappers/null_mapper'
|
21
|
-
require 'ruby_event_store/mappers/instrumented_mapper'
|
36
|
+
require 'ruby_event_store/mappers/forgotten_data'
|
22
37
|
require 'ruby_event_store/mappers/encryption_mapper'
|
38
|
+
require 'ruby_event_store/mappers/instrumented_mapper'
|
39
|
+
require 'ruby_event_store/mappers/null_mapper'
|
40
|
+
require 'ruby_event_store/mappers/protobuf'
|
23
41
|
require 'ruby_event_store/batch_enumerator'
|
24
42
|
require 'ruby_event_store/correlated_commands'
|
25
43
|
require 'ruby_event_store/link_by_metadata'
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module RubyEventStore
|
2
|
+
class Broker
|
3
|
+
def initialize(subscriptions:, dispatcher:)
|
4
|
+
@subscriptions = subscriptions
|
5
|
+
@dispatcher = dispatcher
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(event, serialized_event)
|
9
|
+
subscribers = subscriptions.all_for(event.type)
|
10
|
+
subscribers.each do |subscriber|
|
11
|
+
dispatcher.call(subscriber, event, serialized_event)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_subscription(subscriber, event_types)
|
16
|
+
verify_subscription(subscriber)
|
17
|
+
subscriptions.add_subscription(subscriber, event_types)
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_global_subscription(subscriber)
|
21
|
+
verify_subscription(subscriber)
|
22
|
+
subscriptions.add_global_subscription(subscriber)
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_thread_subscription(subscriber, event_types)
|
26
|
+
verify_subscription(subscriber)
|
27
|
+
subscriptions.add_thread_subscription(subscriber, event_types)
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_thread_global_subscription(subscriber)
|
31
|
+
verify_subscription(subscriber)
|
32
|
+
subscriptions.add_thread_global_subscription(subscriber)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
attr_reader :subscriptions, :dispatcher
|
37
|
+
|
38
|
+
def verify_subscription(subscriber)
|
39
|
+
raise SubscriberNotExist, "subscriber must be first argument or block" unless subscriber
|
40
|
+
raise InvalidHandler.new("Handler #{subscriber} is invalid for dispatcher #{dispatcher}") unless dispatcher.verify(subscriber)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -5,12 +5,12 @@ module RubyEventStore
|
|
5
5
|
|
6
6
|
def initialize(repository:,
|
7
7
|
mapper: Mappers::Default.new,
|
8
|
-
subscriptions:
|
9
|
-
dispatcher:
|
8
|
+
subscriptions: Subscriptions.new,
|
9
|
+
dispatcher: Dispatcher.new,
|
10
10
|
clock: ->{ Time.now.utc })
|
11
11
|
@repository = repository
|
12
12
|
@mapper = mapper
|
13
|
-
@broker =
|
13
|
+
@broker = Broker.new(subscriptions: subscriptions, dispatcher: dispatcher)
|
14
14
|
@clock = clock
|
15
15
|
@metadata = Concurrent::ThreadLocalVar.new
|
16
16
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module RubyEventStore
|
2
|
+
class Dispatcher
|
3
|
+
def call(subscriber, event, _)
|
4
|
+
subscriber = subscriber.new if Class === subscriber
|
5
|
+
subscriber.call(event)
|
6
|
+
end
|
7
|
+
|
8
|
+
def verify(subscriber)
|
9
|
+
begin
|
10
|
+
subscriber_instance = Class === subscriber ? subscriber.new : subscriber
|
11
|
+
rescue ArgumentError
|
12
|
+
false
|
13
|
+
else
|
14
|
+
subscriber_instance.respond_to?(:call)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,17 +1,18 @@
|
|
1
1
|
module RubyEventStore
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
2
|
+
Error = Class.new(StandardError)
|
3
|
+
WrongExpectedEventVersion = Class.new(Error)
|
4
|
+
InvalidExpectedVersion = Class.new(Error)
|
5
|
+
IncorrectStreamData = Class.new(Error)
|
6
|
+
SubscriberNotExist = Class.new(Error)
|
7
|
+
InvalidPageStart = Class.new(Error)
|
8
|
+
InvalidPageStop = Class.new(Error)
|
9
|
+
InvalidPageSize = Class.new(Error)
|
10
|
+
EventDuplicatedInStream = Class.new(Error)
|
11
|
+
ReservedInternalName = Class.new(Error)
|
12
|
+
InvalidHandler = Class.new(Error)
|
13
|
+
ProtobufEncodingFailed = Class.new(Error)
|
13
14
|
|
14
|
-
class EventNotFound <
|
15
|
+
class EventNotFound < Error
|
15
16
|
attr_reader :event_id
|
16
17
|
|
17
18
|
def initialize(event_id)
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module RubyEventStore
|
2
|
+
module Mappers
|
3
|
+
def self.const_missing(const_name)
|
4
|
+
super unless const_name.equal?(:MissingEncryptionKey)
|
5
|
+
warn "`RubyEventStore::Mappers::MissingEncryptionKey` has been deprecated. Use `RubyEventStore::Mappers::Transformation::Encryption::MissingEncryptionKey` instead."
|
6
|
+
|
7
|
+
Transformation::Encryption::MissingEncryptionKey
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -2,32 +2,16 @@ require 'yaml'
|
|
2
2
|
|
3
3
|
module RubyEventStore
|
4
4
|
module Mappers
|
5
|
-
class Default
|
5
|
+
class Default < PipelineMapper
|
6
6
|
def initialize(serializer: YAML, events_class_remapping: {})
|
7
|
-
|
8
|
-
|
7
|
+
super(Pipeline.new(
|
8
|
+
transformations: [
|
9
|
+
Transformation::EventClassRemapper.new(events_class_remapping),
|
10
|
+
Transformation::SymbolizeMetadataKeys.new,
|
11
|
+
Transformation::Serialization.new(serializer: serializer),
|
12
|
+
]
|
13
|
+
))
|
9
14
|
end
|
10
|
-
|
11
|
-
def event_to_serialized_record(domain_event)
|
12
|
-
SerializedRecord.new(
|
13
|
-
event_id: domain_event.event_id,
|
14
|
-
metadata: serializer.dump(domain_event.metadata.to_h),
|
15
|
-
data: serializer.dump(domain_event.data),
|
16
|
-
event_type: domain_event.class.name
|
17
|
-
)
|
18
|
-
end
|
19
|
-
|
20
|
-
def serialized_record_to_event(record)
|
21
|
-
event_type = events_class_remapping.fetch(record.event_type) { record.event_type }
|
22
|
-
Object.const_get(event_type).new(
|
23
|
-
event_id: record.event_id,
|
24
|
-
metadata: TransformKeys.symbolize(serializer.load(record.metadata)),
|
25
|
-
data: serializer.load(record.data)
|
26
|
-
)
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
attr_reader :serializer, :events_class_remapping
|
31
15
|
end
|
32
16
|
end
|
33
17
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module RubyEventStore
|
2
|
+
module Mappers
|
3
|
+
class EncryptionKey
|
4
|
+
def initialize(cipher:, key:)
|
5
|
+
@cipher = cipher
|
6
|
+
@key = key
|
7
|
+
end
|
8
|
+
|
9
|
+
def encrypt(message, iv)
|
10
|
+
crypto = prepare_encrypt(cipher)
|
11
|
+
crypto.iv = iv
|
12
|
+
crypto.key = key
|
13
|
+
|
14
|
+
if crypto.authenticated?
|
15
|
+
encrypt_authenticated(crypto, message)
|
16
|
+
else
|
17
|
+
crypto.update(message) + crypto.final
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def decrypt(message, iv)
|
22
|
+
crypto = prepare_decrypt(cipher)
|
23
|
+
crypto.iv = iv
|
24
|
+
crypto.key = key
|
25
|
+
ciphertext =
|
26
|
+
if crypto.authenticated?
|
27
|
+
ciphertext_from_authenticated(crypto, message)
|
28
|
+
else
|
29
|
+
message
|
30
|
+
end
|
31
|
+
(crypto.update(ciphertext) + crypto.final).force_encoding("UTF-8")
|
32
|
+
end
|
33
|
+
|
34
|
+
def random_iv
|
35
|
+
crypto = prepare_encrypt(cipher)
|
36
|
+
crypto.random_iv
|
37
|
+
end
|
38
|
+
|
39
|
+
attr_reader :cipher, :key
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def ciphertext_from_authenticated(crypto, message)
|
44
|
+
prepare_auth_data(crypto)
|
45
|
+
crypto.auth_tag = message[-16...message.length]
|
46
|
+
message[0...-16]
|
47
|
+
end
|
48
|
+
|
49
|
+
def encrypt_authenticated(crypto, message)
|
50
|
+
prepare_auth_data(crypto)
|
51
|
+
crypto.update(message) + crypto.final + crypto.auth_tag
|
52
|
+
end
|
53
|
+
|
54
|
+
def prepare_auth_data(crypto)
|
55
|
+
crypto.auth_data = ""
|
56
|
+
crypto
|
57
|
+
end
|
58
|
+
|
59
|
+
def prepare_encrypt(cipher)
|
60
|
+
crypto = OpenSSL::Cipher.new(cipher)
|
61
|
+
crypto.encrypt
|
62
|
+
crypto
|
63
|
+
end
|
64
|
+
|
65
|
+
def prepare_decrypt(cipher)
|
66
|
+
crypto = OpenSSL::Cipher.new(cipher)
|
67
|
+
crypto.decrypt
|
68
|
+
crypto
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -1,245 +1,14 @@
|
|
1
1
|
module RubyEventStore
|
2
2
|
module Mappers
|
3
|
-
class
|
4
|
-
FORGOTTEN_DATA = 'FORGOTTEN_DATA'.freeze
|
5
|
-
|
6
|
-
def initialize(string = FORGOTTEN_DATA)
|
7
|
-
@string = string
|
8
|
-
end
|
9
|
-
|
10
|
-
def to_s
|
11
|
-
@string
|
12
|
-
end
|
13
|
-
|
14
|
-
def ==(other)
|
15
|
-
@string == other
|
16
|
-
end
|
17
|
-
|
18
|
-
def method_missing(*)
|
19
|
-
self
|
20
|
-
end
|
21
|
-
|
22
|
-
def respond_to_missing?(*)
|
23
|
-
true
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
class InMemoryEncryptionKeyRepository
|
28
|
-
DEFAULT_CIPHER = 'aes-256-gcm'.freeze
|
29
|
-
|
30
|
-
def initialize
|
31
|
-
@keys = {}
|
32
|
-
end
|
33
|
-
|
34
|
-
def key_of(identifier, cipher: DEFAULT_CIPHER)
|
35
|
-
@keys[[identifier, cipher]]
|
36
|
-
end
|
37
|
-
|
38
|
-
def create(identifier, cipher: DEFAULT_CIPHER)
|
39
|
-
crypto = prepare_encrypt(cipher)
|
40
|
-
@keys[[identifier, cipher]] = EncryptionKey.new(cipher: cipher, key: crypto.random_key)
|
41
|
-
end
|
42
|
-
|
43
|
-
def forget(identifier)
|
44
|
-
@keys = @keys.reject { |(id, _)| id.eql?(identifier) }
|
45
|
-
end
|
46
|
-
|
47
|
-
private
|
48
|
-
|
49
|
-
def prepare_encrypt(cipher)
|
50
|
-
crypto = OpenSSL::Cipher.new(cipher)
|
51
|
-
crypto.encrypt
|
52
|
-
crypto
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
class EncryptionKey
|
57
|
-
def initialize(cipher:, key:)
|
58
|
-
@cipher = cipher
|
59
|
-
@key = key
|
60
|
-
end
|
61
|
-
|
62
|
-
def encrypt(message, iv)
|
63
|
-
crypto = prepare_encrypt(cipher)
|
64
|
-
crypto.iv = iv
|
65
|
-
crypto.key = key
|
66
|
-
|
67
|
-
if crypto.authenticated?
|
68
|
-
encrypt_authenticated(crypto, message)
|
69
|
-
else
|
70
|
-
crypto.update(message) + crypto.final
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def decrypt(message, iv)
|
75
|
-
crypto = prepare_decrypt(cipher)
|
76
|
-
crypto.iv = iv
|
77
|
-
crypto.key = key
|
78
|
-
ciphertext =
|
79
|
-
if crypto.authenticated?
|
80
|
-
ciphertext_from_authenticated(crypto, message)
|
81
|
-
else
|
82
|
-
message
|
83
|
-
end
|
84
|
-
(crypto.update(ciphertext) + crypto.final).force_encoding("UTF-8")
|
85
|
-
end
|
86
|
-
|
87
|
-
def random_iv
|
88
|
-
crypto = prepare_encrypt(cipher)
|
89
|
-
crypto.random_iv
|
90
|
-
end
|
91
|
-
|
92
|
-
attr_reader :cipher, :key
|
93
|
-
|
94
|
-
private
|
95
|
-
|
96
|
-
def ciphertext_from_authenticated(crypto, message)
|
97
|
-
prepare_auth_data(crypto)
|
98
|
-
crypto.auth_tag = message[-16...message.length]
|
99
|
-
message[0...-16]
|
100
|
-
end
|
101
|
-
|
102
|
-
def encrypt_authenticated(crypto, message)
|
103
|
-
prepare_auth_data(crypto)
|
104
|
-
crypto.update(message) + crypto.final + crypto.auth_tag
|
105
|
-
end
|
106
|
-
|
107
|
-
def prepare_auth_data(crypto)
|
108
|
-
crypto.auth_data = ""
|
109
|
-
crypto
|
110
|
-
end
|
111
|
-
|
112
|
-
def prepare_encrypt(cipher)
|
113
|
-
crypto = OpenSSL::Cipher.new(cipher)
|
114
|
-
crypto.encrypt
|
115
|
-
crypto
|
116
|
-
end
|
117
|
-
|
118
|
-
def prepare_decrypt(cipher)
|
119
|
-
crypto = OpenSSL::Cipher.new(cipher)
|
120
|
-
crypto.decrypt
|
121
|
-
crypto
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
class MissingEncryptionKey < StandardError
|
126
|
-
def initialize(key_identifier)
|
127
|
-
super %Q|Could not find encryption key for '#{key_identifier}'|
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
class EncryptionMapper
|
132
|
-
class Leaf
|
133
|
-
def self.===(hash)
|
134
|
-
hash.keys.sort.eql? %i(cipher identifier iv)
|
135
|
-
end
|
136
|
-
end
|
137
|
-
private_constant :Leaf
|
138
|
-
|
3
|
+
class EncryptionMapper < PipelineMapper
|
139
4
|
def initialize(key_repository, serializer: YAML, forgotten_data: ForgottenData.new)
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
metadata = domain_event.metadata.to_h
|
147
|
-
crypto_description = encryption_metadata(domain_event.data, encryption_schema(domain_event))
|
148
|
-
metadata[:encryption] = crypto_description unless crypto_description.empty?
|
149
|
-
|
150
|
-
SerializedRecord.new(
|
151
|
-
event_id: domain_event.event_id,
|
152
|
-
metadata: serializer.dump(metadata),
|
153
|
-
data: serializer.dump(encrypt_data(deep_dup(domain_event.data), crypto_description)),
|
154
|
-
event_type: domain_event.class.to_s
|
155
|
-
)
|
156
|
-
end
|
157
|
-
|
158
|
-
def serialized_record_to_event(record)
|
159
|
-
metadata = serializer.load(record.metadata)
|
160
|
-
crypto_description = Hash(metadata.delete(:encryption))
|
161
|
-
|
162
|
-
Object.const_get(record.event_type).new(
|
163
|
-
event_id: record.event_id,
|
164
|
-
data: decrypt_data(serializer.load(record.data), crypto_description),
|
165
|
-
metadata: metadata,
|
166
|
-
)
|
167
|
-
end
|
168
|
-
|
169
|
-
private
|
170
|
-
attr_reader :key_repository, :serializer, :forgotten_data
|
171
|
-
|
172
|
-
def encryption_schema(event)
|
173
|
-
event.class.respond_to?(:encryption_schema) ? event.class.encryption_schema : {}
|
174
|
-
end
|
175
|
-
|
176
|
-
def deep_dup(hash)
|
177
|
-
duplicate = hash.dup
|
178
|
-
duplicate.each do |k, v|
|
179
|
-
duplicate[k] = v.instance_of?(Hash) ? deep_dup(v) : v
|
180
|
-
end
|
181
|
-
duplicate
|
182
|
-
end
|
183
|
-
|
184
|
-
def encryption_metadata(data, schema)
|
185
|
-
schema.inject({}) do |acc, (key, value)|
|
186
|
-
case value
|
187
|
-
when Hash
|
188
|
-
acc[key] = encryption_metadata(data, value)
|
189
|
-
when Proc
|
190
|
-
key_identifier = value.call(data)
|
191
|
-
encryption_key = key_repository.key_of(key_identifier) or raise MissingEncryptionKey.new(key_identifier)
|
192
|
-
acc[key] = {
|
193
|
-
cipher: encryption_key.cipher,
|
194
|
-
iv: encryption_key.random_iv,
|
195
|
-
identifier: key_identifier,
|
196
|
-
}
|
197
|
-
end
|
198
|
-
acc
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
def encrypt_data(data, meta)
|
203
|
-
meta.reduce(data) do |acc, (key, value)|
|
204
|
-
acc[key] = encrypt_attribute(acc, key, value)
|
205
|
-
acc
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
def decrypt_data(data, meta)
|
210
|
-
meta.reduce(data) do |acc, (key, value)|
|
211
|
-
acc[key] = decrypt_attribute(data, key, value)
|
212
|
-
acc
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
def encrypt_attribute(data, attribute, meta)
|
217
|
-
case meta
|
218
|
-
when Leaf
|
219
|
-
value = data.fetch(attribute)
|
220
|
-
return unless value
|
221
|
-
|
222
|
-
encryption_key = key_repository.key_of(meta.fetch(:identifier))
|
223
|
-
encryption_key.encrypt(serializer.dump(value), meta.fetch(:iv))
|
224
|
-
when Hash
|
225
|
-
encrypt_data(data.fetch(attribute), meta)
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
def decrypt_attribute(data, attribute, meta)
|
230
|
-
case meta
|
231
|
-
when Leaf
|
232
|
-
cryptogram = data.fetch(attribute)
|
233
|
-
return unless cryptogram
|
234
|
-
|
235
|
-
encryption_key = key_repository.key_of(meta.fetch(:identifier), cipher: meta.fetch(:cipher)) or return forgotten_data
|
236
|
-
serializer.load(encryption_key.decrypt(cryptogram, meta.fetch(:iv)))
|
237
|
-
when Hash
|
238
|
-
decrypt_data(data.fetch(attribute), meta)
|
239
|
-
end
|
240
|
-
rescue OpenSSL::Cipher::CipherError
|
241
|
-
forgotten_data
|
5
|
+
super(Pipeline.new(
|
6
|
+
transformations: [
|
7
|
+
Transformation::Encryption.new(key_repository, serializer: serializer, forgotten_data: forgotten_data),
|
8
|
+
Transformation::Serialization.new(serializer: serializer),
|
9
|
+
]
|
10
|
+
))
|
242
11
|
end
|
243
12
|
end
|
244
13
|
end
|
245
|
-
end
|
14
|
+
end
|