Class: ROTP::TOTP

Inherits:
OTP
  • Object
show all
Defined in:
lib/rotp/totp.rb

Constant Summary

Constants inherited from OTP

OTP::DEFAULT_DIGITS

Instance Attribute Summary collapse

Attributes inherited from OTP

#digest, #digits, #secret

Instance Method Summary collapse

Methods inherited from OTP

#generate_otp

Constructor Details

#initialize(s, options = {}) ⇒ TOTP

Returns a new instance of TOTP.

Parameters:

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • interval (Integer) — default: 30

    the time interval in seconds for OTP This defaults to 30 which is standard.



9
10
11
12
13
# File 'lib/rotp/totp.rb', line 9

def initialize(s, options = {})
  @interval = options[:interval] || DEFAULT_INTERVAL
  @issuer = options[:issuer]
  super
end

Instance Attribute Details

#intervalObject (readonly)

Returns the value of attribute interval.



5
6
7
# File 'lib/rotp/totp.rb', line 5

def interval
  @interval
end

#issuerObject (readonly)

Returns the value of attribute issuer.



5
6
7
# File 'lib/rotp/totp.rb', line 5

def issuer
  @issuer
end

Instance Method Details

#at(time, padding = true) ⇒ Object

Accepts either a Unix timestamp integer or a Time object. Time objects will be adjusted to UTC automatically

Parameters:

  • time (Time/Integer)

    the time to generate an OTP for

  • [Boolean] (Hash)

    a customizable set of options



19
20
21
22
23
24
25
# File 'lib/rotp/totp.rb', line 19

def at(time, padding=true)
  unless time.class == Time
    time = Time.at(time.to_i)
  end

  generate_otp(timecode(time), padding)
end

#now(padding = true) ⇒ Integer

Generate the current time OTP

Returns:

  • (Integer)

    the OTP as an integer



29
30
31
# File 'lib/rotp/totp.rb', line 29

def now(padding=true)
  generate_otp(timecode(Time.now), padding)
end

#provisioning_uri(name) ⇒ String

Returns the provisioning URI for the OTP This can then be encoded in a QR Code and used to provision the Google Authenticator app

Parameters:

  • name (String)

    of the account

Returns:

  • (String)

    provisioning URI



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/rotp/totp.rb', line 80

def provisioning_uri(name)
  # The format of this URI is documented at:
  # https://github.com/google/google-authenticator/wiki/Key-Uri-Format
  # For compatibility the issuer appears both before that account name and also in the
  # query string.
  issuer_string = issuer.nil? ? "" : "#{URI.encode(issuer)}:"
  params = {
    secret: secret,
    period: interval == 30 ? nil : interval,
    issuer: issuer,
    digits: digits == DEFAULT_DIGITS ? nil : digits,
    algorithm: digest.upcase == 'SHA1' ? nil : digest.upcase,
  }
  encode_params("otpauth://totp/#{issuer_string}#{URI.encode(name)}", params)
end

#verify(otp, time = Time.now) ⇒ Object

Verifies the OTP passed in against the current time OTP

Parameters:

  • otp (String/Integer)

    the OTP to check against



35
36
37
# File 'lib/rotp/totp.rb', line 35

def verify(otp, time = Time.now)
  super(otp, self.at(time))
end

#verify_with_drift(otp, drift, time = Time.now) ⇒ Object

Verifies the OTP passed in against the current time OTP and adjacent intervals up to drift.

Parameters:

  • otp (String)

    the OTP to check against

  • drift (Integer)

    the number of seconds that the client and server are allowed to drift apart



44
45
46
47
48
49
# File 'lib/rotp/totp.rb', line 44

def verify_with_drift(otp, drift, time = Time.now)
  time = time.to_i
  times = (time-drift..time+drift).step(interval).to_a
  times << time + drift if times.last < time + drift
  times.any? { |ti| verify(otp, ti) }
end

#verify_with_drift_and_prior(otp, drift, prior_time = nil, time = Time.now) ⇒ Object

Verifies the OTP passed in against the current time OTP and adjacent intervals up to drift. Excludes OTPs from prior_time and earlier. Returns time value of matching OTP code for use in subsequent call.

Parameters:

  • otp (String)

    the OTP to check against

  • drift (Integer)

    the number of seconds that the client and server are allowed to drift apart

  • time (Integer) (defaults to: Time.now)

    value of previous match



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/rotp/totp.rb', line 59

def verify_with_drift_and_prior(otp, drift, prior_time = nil, time = Time.now)
  # calculate normalized bin start times based on drift
  first_bin = (time - drift).to_i / interval * interval
  last_bin = (time + drift).to_i / interval * interval

  # if prior_time was supplied, adjust first bin if necessary to exclude it
  if prior_time
    prior_bin = prior_time.to_i / interval * interval
    first_bin = prior_bin + interval if prior_bin >= first_bin
    # fail if we've already used the last available OTP code
    return if first_bin > last_bin
  end
  times = (first_bin..last_bin).step(interval).to_a
  times.find { |ti| verify(otp, ti) }
end