Class: Devise::Passwordless::MessageEncryptorTokenizer

Inherits:
Object
  • Object
show all
Defined in:
lib/devise/passwordless/tokenizers/message_encryptor_tokenizer.rb

Class Method Summary collapse

Class Method Details

.decode(token, resource_class, as_of: Time.current, expire_duration: Devise.passwordless_login_within) ⇒ Object

Raises:



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/devise/passwordless/tokenizers/message_encryptor_tokenizer.rb', line 25

def self.decode(token, resource_class, as_of: Time.current, expire_duration: Devise.)
  raise InvalidTokenError if token.blank?
  salt_base64, encrypted_data = token.split(":")
  raise InvalidTokenError if salt_base64.blank? || encrypted_data.blank?
  begin
    salt = Base64.strict_decode64(salt_base64)
  rescue ArgumentError
    raise InvalidTokenError
  end
  len = ActiveSupport::MessageEncryptor.key_len
  key = ActiveSupport::KeyGenerator.new(Devise::Passwordless.secret_key).generate_key(salt, len)
  crypt = ActiveSupport::MessageEncryptor.new(key, serializer: JSON)
  begin
    decrypted_data = crypt.decrypt_and_verify(encrypted_data)
  rescue ActiveSupport::MessageVerifier::InvalidSignature, ActiveSupport::MessageEncryptor::InvalidMessage
    raise InvalidTokenError
  end

  unless (expiration_time = decrypted_data["expires_at"])
    created_at = ActiveSupport::TimeZone["UTC"].at(decrypted_data["created_at"])
    expiration_time = (created_at + expire_duration).to_f
  end

  if as_of.to_f > expiration_time
    raise ExpiredTokenError
  end

  resource = resource_class.find_by(id: decrypted_data["data"]["resource"]["key"])

  if resource_class.
    if ( = resource.try(:current_sign_in_at))
      token_created_at = ActiveSupport::TimeZone["UTC"].at(decrypted_data["created_at"])
      if token_created_at < 
        raise ExpiredTokenError
      end
    end
  end

  [resource, decrypted_data]
end

.encode(resource, extra: nil, expires_at: nil) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/devise/passwordless/tokenizers/message_encryptor_tokenizer.rb', line 3

def self.encode(resource, extra: nil, expires_at: nil)
  now = Time.current
  len = ActiveSupport::MessageEncryptor.key_len
  salt = SecureRandom.random_bytes(len)
  key = ActiveSupport::KeyGenerator.new(Devise::Passwordless.secret_key).generate_key(salt, len)
  crypt = ActiveSupport::MessageEncryptor.new(key, serializer: JSON)
  data = {
    data: {
      resource: {
        key: resource.to_key,
        email: resource.email,
      },
    },
    created_at: now.to_f,
  }
  data[:data][:extra] = extra if extra
  data[:expires_at] = expires_at.to_f if expires_at
  encrypted_data = crypt.encrypt_and_sign(data)
  salt_base64 = Base64.strict_encode64(salt)
  "#{salt_base64}:#{encrypted_data}"
end