require 'spec_helper' describe ROTP::HOTP do before(:all) { @counter = 1234 } subject { ROTP::HOTP.new('a' * 32) } it "should generate a string OTP given a count" do subject.at(@counter).should == "161024" end it "should generate a number if padding is set to false" do subject.at(@counter, false).should == 161024 end it "should not verify a number" do expect { subject.verify(161024, @counter) }.to raise_error end it "should verify a string" do subject.verify("161024", @counter).should be_true end it "should output its provisioning URI" do url = subject.provisioning_uri('mark@percival') params = CGI::parse(URI::parse(url).query) url.should match(/otpauth:\/\/hotp.+/) params["secret"].first.should == "a" * 32 end context "with retries" do it "should verify that retry is a valid number" do subject.verify_with_retries("161024", @counter, -1).should be_false subject.verify_with_retries("161024", @counter, 0).should be_false end it "should verify up to the total number of retries and return the counter" do subject.verify_with_retries("161024", @counter - 10, 10).should == @counter end it "should verify that retry is a valid number" do subject.verify_with_retries("161024", @counter - 20, 10).should be_false end end end describe "HOTP example values from the rfc" do it "should match the RFC" do # 12345678901234567890 in Base32 # GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ hotp = ROTP::HOTP.new("GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ") hotp.at(0).should ==("755224") hotp.at(1).should ==("287082") hotp.at(2).should ==("359152") hotp.at(3).should ==("969429") hotp.at(4).should ==("338314") hotp.at(5).should ==("254676") hotp.at(6).should ==("287922") hotp.at(7).should ==("162583") hotp.at(8).should ==("399871") hotp.at(9).should ==("520489") end it "should verify an OTP and not allow reuse" do hotp = ROTP::HOTP.new("GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ") hotp.verify("520489", 9).should be_true hotp.verify("520489", 10).should be_false end end