Skip to content

Instantly share code, notes, and snippets.

@songjiz
Last active April 13, 2020 14:35
Show Gist options
  • Save songjiz/811d62e01f3958f509e83006295c1a1e to your computer and use it in GitHub Desktop.
Save songjiz/811d62e01f3958f509e83006295c1a1e to your computer and use it in GitHub Desktop.
stateless token base on ActiveSupport::MessageEncryptor
module ResetPasswordSupport
extend ActiveSupport::Concern
class ResetPasswordToken
include StatelessToken
def self.purpose
:reset_password
end
end
module ClassMethods
def find_by_reset_password_token(token)
class_name, id = ResetPasswordToken.decrypt(token)
return unless class_name == name
find(id).tap do |record|
record.reset_password_token = token
end
end
end
attr_accessor :reset_password_token
def generate_reset_password_token(options = {})
self.reset_password_token = ResetPasswordToken.new(self, options).value
end
def reset_password(password, password_confirmation = nil)
self.password = password.presence
self.password_confirmation = password_confirmation.presence
save
end
end
module StatelessToken
extend ActiveSupport::Concern
module ClassMethods
def decrypt(token)
encryptor.decrypt_and_verify(token, purpose: purpose)
rescue ActiveSupport::MessageEncryptor::InvalidMessage
nil
end
def encrypt(data, expires_in: nil, expires_at: nil, **options)
options.merge!(
purpose: purpose,
expires_in: expires_in,
expires_at: expires_at
)
encryptor.encrypt_and_sign data, **options
end
def purpose; end
private
def encryptor
@encryptor ||= ActiveSupport::MessageEncryptor.new(secret)
end
def secret
@secret ||= key_generator.generate_key(salt, key_len)
end
def key_generator
Rails.application.key_generator
end
def salt
to_s
end
def key_len
ActiveSupport::MessageEncryptor.key_len
end
end
def initialize(record, expires_in: nil, expires_at: nil)
@record = record
@expires_in = expires_in
@expires_at = expires_at
end
def payload
[@record.class.name, @record.id]
end
def value
@value ||= self.class.encrypt(payload, expires_in: @expires_in, expires_at: @expires_at)
end
def to_s
value
end
end
class User < ApplicationRecord
include ResetPasswordSupport
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment