Created
July 2, 2012 19:29
-
-
Save bricker/3035153 to your computer and use it in GitHub Desktop.
Ruby serialization with JSON and YAML
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
session['_auth_user_backend'] = 'django.contrib.auth.backends.ModelBackend' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
> flash = ActionDispatch::Flash::FlashHash.new() | |
> flash[:notice] = "Success!" | |
> flash | |
#=> #<ActionDispatch::Flash::FlashHash:0x007fc46f95edc8 @used=#<Set: {}>, @closed=false, @flashes={:notice=>"Success!"}, @now=nil> | |
> encoded = ActiveSupport::JSON.encode(flash) | |
#=> "[[\"notice\",\"Success!\"]]" | |
> ActiveSupport::JSON.decode(encoded) | |
#=> [["notice", "Success!"]] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
> puts encoded = YAML.dump(flash) | |
#=> --- !ruby/object:ActionDispatch::Flash::FlashHash | |
#=> used: !ruby/object:Set | |
#=> hash: {} | |
#=> closed: false | |
#=> flashes: | |
#=> :notice: Success! | |
#=> now: | |
> YAML.load(encoded) | |
#=> #<ActionDispatch::Flash::FlashHash:0x007fc46fe972e0 @used=#<Set: {}>, @closed=false, @flashes={:notice=>"Success!"}, @now=nil> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def load(self): | |
dd = self._session_key.split("--") | |
# make sure we got both elements | |
if len(dd) == 2: | |
data = re.sub('%3D','=',dd[0]) | |
# now make sure digest is valid | |
if dd[1] == self.generate_digest(data): | |
# valid. decode and load data | |
decoded_data = base64.b64decode(data) | |
# First load with YAML, if there is a YAML syntax error, then load with JSON | |
try: | |
print "trying yaml..." | |
obj = yaml.load(decoded_data) | |
except ValueError: | |
print "trying json..." | |
obj = simplejson.loads(decoded_data) | |
except: | |
print "Couldn't load data. A new session will be created." | |
obj = False | |
if obj: | |
print "got object" | |
# intercept _session_expiry | |
if obj.has_key("_session_expiry"): | |
obj['_session_expiry'] = datetime.datetime.fromtimestamp(int(obj['_session_expiry'])) | |
return obj | |
else: | |
# if we get here, it was invalid and we should generate a new session | |
self.create() | |
return {} | |
def _get_session_key(self): | |
obj = getattr(self, '_session_cache', {}) | |
# intercept _session_expiry | |
if obj.has_key("_session_expiry") and isinstance(obj['_session_expiry'],datetime.datetime): | |
obj['_session_expiry'] = obj['_session_expiry'].strftime("%s") | |
# add session_id if it's not present | |
if not obj.has_key("session_id"): | |
obj['session_id'] = rand.bytes(16).encode('hex_codec') | |
# Dump to YAML, then encode as base64 | |
enc = base64.b64encode(yaml.dump(obj)) | |
return "--".join([re.sub('=','%3D',enc),self.generate_digest(enc)]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class YAMLVerifier < ActiveSupport::MessageVerifier | |
def verify(signed_message) | |
raise InvalidSignature if signed_message.blank? | |
data, digest = signed_message.split("--") | |
if data.present? && digest.present? && secure_compare(digest, generate_digest(data)) | |
# First load with @serializer (YAML), if there is a YAML syntax error, then decode with JSON | |
begin | |
@serializer.load(::Base64.decode64(data)) | |
rescue Psych::SyntaxError | |
Rails.logger.info "Caught YAML syntax error. Decoding with JSON." | |
ActiveSupport::JSON.decode(Base64.decode64(data.gsub('%3D','='))) | |
end | |
else | |
raise InvalidSignature | |
end | |
end | |
def generate(value) | |
data = ::Base64.strict_encode64(@serializer.dump(convert(value))) | |
"#{data}--#{generate_digest(data)}" | |
end | |
def convert(value) | |
# If it isn't present, add in session_expiry to support django | |
if value.is_a?(Hash) | |
if !value.has_key?("_session_expiry") | |
value['_session_expiry'] = (Time.now() + 30*86400).strftime("%s") # expire in 30 days | |
end | |
end | |
return value | |
end | |
end | |
module ActionDispatch | |
class Cookies | |
class SignedCookieJar | |
def initialize(parent_jar, secret) | |
ensure_secret_secure(secret) | |
@parent_jar = parent_jar | |
@verifier = YAMLVerifier.new(secret, serializer: YAML) | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment