Skip to content

Commit

Permalink
Use OTP::URI for TOTP#provisioning_uri generation
Browse files Browse the repository at this point in the history
  • Loading branch information
atcruice committed Jul 13, 2020
1 parent c75d3e1 commit 941f819
Show file tree
Hide file tree
Showing 2 changed files with 4 additions and 94 deletions.
14 changes: 1 addition & 13 deletions lib/rotp/totp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,7 @@ def verify(otp, drift_ahead: 0, drift_behind: 0, after: nil, at: Time.now)
# @param [String] name of the account
# @return [String] provisioning URI
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? ? '' : "#{Addressable::URI.escape(issuer)}:"
params = {
secret: secret,
period: interval == 30 ? nil : interval,
issuer: Addressable::URI.encode(issuer),
digits: digits == DEFAULT_DIGITS ? nil : digits,
algorithm: digest.casecmp('SHA1').zero? ? nil : digest.upcase
}
encode_params("otpauth://totp/#{issuer_string}#{Addressable::URI.escape(name)}", params)
OTP::URI.new(self, account_name: name).to_s
end

private
Expand Down
84 changes: 3 additions & 81 deletions spec/lib/rotp/totp_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -221,87 +221,9 @@ def get_timecodes(at, b, a)
end

describe '#provisioning_uri' do
let(:uri) { totp.provisioning_uri('mark@percival') }
let(:params) { CGI.parse URI.parse(uri).query }

context 'without issuer' do
it 'has the correct format' do
expect(uri).to match %r{\Aotpauth:\/\/totp.+}
end

it 'includes the secret as parameter' do
expect(params['secret'].first).to eq 'JBSWY3DPEHPK3PXP'
end
end

context 'with default digits' do
it 'does does not include digits parameter' do
expect(params['digits'].first).to be_nil
end
end

context 'with non-default digits' do
let(:totp) { ROTP::TOTP.new 'JBSWY3DPEHPK3PXP', digits: 8 }

it 'does does not include digits parameter' do
expect(params['digits'].first).to eq '8'
end
end

context 'with issuer' do
let(:totp) { ROTP::TOTP.new 'JBSWY3DPEHPK3PXP', issuer: 'FooCo' }

it 'has the correct format' do
expect(uri).to match %r{\Aotpauth:\/\/totp/FooCo:.+}
end

it 'includes the secret as parameter' do
expect(params['secret'].first).to eq 'JBSWY3DPEHPK3PXP'
end

it 'includes the issuer as parameter' do
expect(params['issuer'].first).to eq 'FooCo'
end

context 'with spaces in issuer' do
let(:totp) { ROTP::TOTP.new 'JBSWY3DPEHPK3PXP', issuer: 'Foo Co' }

it 'includes the uri encoded issuer as parameter' do
expect(params['issuer'].first).to eq 'Foo%20Co'
end
end
end

context 'with custom interval' do
let(:totp) { ROTP::TOTP.new 'JBSWY3DPEHPK3PXP', interval: 60 }

it 'has the correct format' do
expect(uri).to match %r{\Aotpauth:\/\/totp.+}
end

it 'includes the secret as parameter' do
expect(params['secret'].first).to eq 'JBSWY3DPEHPK3PXP'
end

it 'includes the interval as period parameter' do
expect(params['period'].first).to eq '60'
end
end

context 'with custom digest' do
let(:totp) { ROTP::TOTP.new 'JBSWY3DPEHPK3PXP', digest: 'sha256' }

it 'has the correct format' do
expect(uri).to match %r{\Aotpauth:\/\/totp.+}
end

it 'includes the secret as parameter' do
expect(params['secret'].first).to eq 'JBSWY3DPEHPK3PXP'
end

it 'includes the digest as algorithm parameter' do
expect(params['algorithm'].first).to eq 'SHA256'
end
it 'accepts the account name' do
expect(totp.provisioning_uri('mark@percival'))
.to eq 'otpauth://totp/mark%40percival?secret=JBSWY3DPEHPK3PXP'
end
end

Expand Down

0 comments on commit 941f819

Please sign in to comment.