Skip to content

Instantly share code, notes, and snippets.

@mostlyobvious
Created July 26, 2026 08:40
Show Gist options
  • Select an option

  • Save mostlyobvious/5d2f2968b2f3adc0a5c000c7b9fcaeac to your computer and use it in GitHub Desktop.

Select an option

Save mostlyobvious/5d2f2968b2f3adc0a5c000c7b9fcaeac to your computer and use it in GitHub Desktop.
require "bundler/inline"
require "json"
require "openssl"
require "base64"
gemfile { gem "ruby_event_store" }
class TicketHolderEmailProvided < RubyEventStore::Event
def self.encryption_schema = { email: ->(data) { data.fetch(:user_id) } }
end
class InMemoryEncryptionKeyRepository
DEFAULT_CIPHER = "aes-256-cbc".freeze
def initialize
@keys = {}
end
def key_of(identifier, cipher: DEFAULT_CIPHER)
@keys[[identifier, cipher]]
end
def create(identifier, cipher: DEFAULT_CIPHER)
@keys[[identifier, cipher]] = RubyEventStore::Mappers::EncryptionKey.new(
cipher: cipher,
key: random_key(cipher)
)
end
def forget(identifier)
@keys = @keys.reject { |(id, _)| id.eql?(identifier) }
end
private
def random_key(cipher)
crypto = OpenSSL::Cipher.new(cipher)
crypto.encrypt
crypto.random_key
end
end
key_repository = InMemoryEncryptionKeyRepository.new
key_repository.create(user_id = 21_37)
res =
RubyEventStore::Client.new(
repository: RubyEventStore::InMemoryRepository.new(serializer: JSON),
mapper:
Class
.new(RubyEventStore::Mappers::PipelineMapper) do
def initialize(key_repository)
super(
RubyEventStore::Mappers::Pipeline.new(
RubyEventStore::Mappers::Transformation::Encryption.new(
key_repository,
serializer: RubyEventStore::Serializers::YAML,
forgotten_data: RubyEventStore::Mappers::ForgottenData.new
),
Class.new do
def dump(record)
RubyEventStore::Record.new(
event_id: record.event_id,
event_type: record.event_type,
data:
process_data(
deep_dup(record.data),
encryption_schema(
Object.const_get(record.event_type)
),
Base64.method(:strict_encode64)
),
metadata:
process_metadata(
deep_dup(record.metadata),
encryption_schema(
Object.const_get(record.event_type)
),
Base64.method(:strict_encode64)
),
timestamp: record.timestamp,
valid_at: record.valid_at
)
end
def load(record)
RubyEventStore::Record.new(
event_id: record.event_id,
event_type: record.event_type,
data:
process_data(
deep_dup(record.data),
encryption_schema(
Object.const_get(record.event_type)
),
Base64.method(:strict_decode64)
),
metadata:
process_metadata(
deep_dup(record.metadata),
encryption_schema(
Object.const_get(record.event_type)
),
Base64.method(:strict_decode64)
),
timestamp: record.timestamp,
valid_at: record.valid_at
)
end
private
def encryption_schema(event_class)
event_class.respond_to?(:encryption_schema) ? event_class.encryption_schema : {}
end
def deep_dup(hash)
duplicate = hash.dup
duplicate.each { |k, v| duplicate[k] = v.instance_of?(Hash) ? deep_dup(v) : v }
end
def process_data(data, schema, method)
schema.reduce(data) do |acc, (key, _)|
acc[key] = method.call(data[key]) if data.has_key?(key)
acc
end
end
def process_metadata(metadata, schema, method)
schema.reduce(metadata) do |acc, (key, _)|
acc[:encryption][key][:iv] = method.call(
metadata[:encryption][key][:iv]
) if metadata[:encryption].has_key?(key)
acc
end
end
end
.new,
RubyEventStore::Mappers::Transformation::PreserveTypes.new.register(
Symbol,
serializer: ->(v) { v.to_s },
deserializer: ->(v) { v.to_sym }
),
RubyEventStore::Mappers::Transformation::SymbolizeMetadataKeys.new
)
)
end
end
.new(key_repository)
)
res.append(
TicketHolderEmailProvided.new(
data: {
email: "kaka@dudu.me",
user_id: user_id
}
)
)
binding.irb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment