Class: PasskeyAuth::MagicLink

Inherits:
ApplicationRecord
  • Object
show all
Defined in:
app/models/passkey_auth/magic_link.rb,
app/models/passkey_auth/magic_link/short_code.rb

Defined Under Namespace

Classes: ShortCode

Constant Summary collapse

PURPOSES =
%w[login recovery email_confirmation].freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.cleanup_expiredObject



71
72
73
# File 'app/models/passkey_auth/magic_link.rb', line 71

def self.cleanup_expired
  expired.destroy_all
end

.consume_by_email_and_code(email, code, ip:, user_agent:) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
# File 'app/models/passkey_auth/magic_link.rb', line 54

def self.consume_by_email_and_code(email, code, ip:, user_agent:)
  cleaned_code  = code&.upcase&.strip
  cleaned_email = email&.downcase&.strip

  # Use configured email attribute
  email_attr = PasskeyAuth.user_email_attribute
  link = includes(:user).find_by(short_code: cleaned_code, user: { email_attr => cleaned_email })

  return unless link

  link.use!(ip: ip, user_agent: user_agent) ? link : nil
end

.consume_by_token(token, ip:, user_agent:) ⇒ Object



46
47
48
49
50
51
52
# File 'app/models/passkey_auth/magic_link.rb', line 46

def self.consume_by_token(token, ip:, user_agent:)
  link = find_by(token: token)

  return unless link

  link.use!(ip: ip, user_agent: user_agent) ? link : nil
end

.generate_short_codeObject



67
68
69
# File 'app/models/passkey_auth/magic_link.rb', line 67

def self.generate_short_code
  ShortCode.generate
end

Instance Method Details

#expired?Boolean

Returns:

  • (Boolean)


22
23
24
# File 'app/models/passkey_auth/magic_link.rb', line 22

def expired?
  expires_at <= Time.current
end

#invalid_reasonObject



75
76
77
78
79
80
81
82
83
# File 'app/models/passkey_auth/magic_link.rb', line 75

def invalid_reason
  if expired?
    :expired
  elsif used?
    :used
  else
    :generic
  end
end

#use!(ip: nil, user_agent: nil) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
# File 'app/models/passkey_auth/magic_link.rb', line 34

def use!(ip: nil, user_agent: nil)
  with_lock do
    return false unless valid_for_use?

    update!(
      used_at: Time.current,
      ip_address: ip,
      user_agent: user_agent
    )
  end
end

#used?Boolean

Returns:

  • (Boolean)


26
27
28
# File 'app/models/passkey_auth/magic_link.rb', line 26

def used?
  used_at.present?
end

#valid_for_use?Boolean

Returns:

  • (Boolean)


30
31
32
# File 'app/models/passkey_auth/magic_link.rb', line 30

def valid_for_use?
  !expired? && !used?
end