ruby_event_store 0.39.0 → 0.40.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/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
|