class Motion::Serializer
Constants
- HASH_PEPPER
- NULL_BYTE
Attributes
revision[R]
secret[R]
Public Class Methods
minimum_secret_byte_length()
click to toggle source
# File lib/motion/serializer.rb, line 18 def self.minimum_secret_byte_length ActiveSupport::MessageEncryptor.key_len end
new( secret: Motion.config.secret, revision: Motion.config.revision )
click to toggle source
# File lib/motion/serializer.rb, line 22 def initialize( secret: Motion.config.secret, revision: Motion.config.revision ) unless secret.each_byte.count >= self.class.minimum_secret_byte_length raise BadSecretError.new(self.class.minimum_secret_byte_length) end raise BadRevisionError if revision.include?(NULL_BYTE) @secret = secret @revision = revision end
Public Instance Methods
deserialize(serialized_component)
click to toggle source
# File lib/motion/serializer.rb, line 50 def deserialize(serialized_component) state_with_revision = decrypt_and_verify(serialized_component) serialized_revision, state = state_with_revision.split(NULL_BYTE, 2) component = load(inflate(state)) if revision == serialized_revision component else component.class.upgrade_from(serialized_revision, component) end end
serialize(component)
click to toggle source
# File lib/motion/serializer.rb, line 40 def serialize(component) state = deflate(dump(component)) state_with_revision = "#{revision}#{NULL_BYTE}#{state}" [ salted_digest(state_with_revision), encrypt_and_sign(state_with_revision) ] end
weak_digest(component)
click to toggle source
# File lib/motion/serializer.rb, line 36 def weak_digest(component) dump(component).hash end
Private Instance Methods
decrypt_and_verify(cypertext)
click to toggle source
# File lib/motion/serializer.rb, line 86 def decrypt_and_verify(cypertext) encryptor.decrypt_and_verify(cypertext) rescue ActiveSupport::MessageEncryptor::InvalidMessage, ActiveSupport::MessageVerifier::InvalidSignature raise InvalidSerializedStateError end
deflate(dumped_component)
click to toggle source
# File lib/motion/serializer.rb, line 74 def deflate(dumped_component) LZ4.compress(dumped_component) end
derive_encryptor_key()
click to toggle source
# File lib/motion/serializer.rb, line 105 def derive_encryptor_key secret.byteslice(0, self.class.minimum_secret_byte_length) end
derive_hash_salt()
click to toggle source
# File lib/motion/serializer.rb, line 109 def derive_hash_salt Digest::SHA256.digest(HASH_PEPPER + secret) end
dump(component)
click to toggle source
# File lib/motion/serializer.rb, line 64 def dump(component) Marshal.dump(component) rescue TypeError => e raise UnrepresentableStateError.new(component, e.message) end
encrypt_and_sign(cleartext)
click to toggle source
# File lib/motion/serializer.rb, line 82 def encrypt_and_sign(cleartext) encryptor.encrypt_and_sign(cleartext) end
encryptor()
click to toggle source
# File lib/motion/serializer.rb, line 97 def encryptor @encryptor ||= ActiveSupport::MessageEncryptor.new(derive_encryptor_key) end
hash_salt()
click to toggle source
# File lib/motion/serializer.rb, line 101 def hash_salt @hash_salt ||= derive_hash_salt end
inflate(deflated_state)
click to toggle source
# File lib/motion/serializer.rb, line 78 def inflate(deflated_state) LZ4.uncompress(deflated_state) end
load(state)
click to toggle source
# File lib/motion/serializer.rb, line 70 def load(state) Marshal.load(state) end
salted_digest(input)
click to toggle source
# File lib/motion/serializer.rb, line 93 def salted_digest(input) Digest::SHA256.base64digest(hash_salt + input) end