Commit fe86724

mo khan <mo@mokhan.ca>
2014-07-25 19:50:34
implement time based one time password generation.
1 parent 0afd424
lib/in/console.rb
@@ -1,8 +1,7 @@
 module In
   class Console
-    def initialize(filename = "secrets", authenticator)
+    def initialize(filename = "secrets")
       @storage = PStore.new(File.join(Dir.home, ".#{filename}.pstore"))
-      @authenticator = authenticator
     end
 
     def run(command)
@@ -20,7 +19,7 @@ module In
       when "show"
         ShowCommand.new(@storage)
       when "totp"
-        TotpCommand.new(@storage, @authenticator)
+        TotpCommand.new(@storage)
       end
     end
   end
lib/in/totp_command.rb
@@ -1,8 +1,7 @@
 module In
   class TotpCommand
-    def initialize(storage, authenticator)
+    def initialize(storage)
       @storage = storage
-      @authenticator = authenticator
     end
 
     def run(arguments)
@@ -10,7 +9,7 @@ module In
       secret = @storage.transaction(true) do
         @storage[name]
       end
-      @authenticator.totp(secret)
+      ::ROTP::TOTP.new(secret).now
     end
   end
 end
lib/in.rb
@@ -4,3 +4,4 @@ require "in/add_command"
 require "in/show_command"
 require "in/totp_command"
 require "in/console"
+require "rotp"
spec/lib/console_spec.rb
@@ -1,8 +1,7 @@
 module In
   describe Console do
-    subject { Console.new('testing', authenticator) }
-    let(:secret) { SecureRandom.uuid }
-    let(:authenticator) { Object.new }
+    subject { Console.new('testing') }
+    let(:secret) { ::ROTP::Base32.random_base32 }
 
     it "saves a new secret" do
       subject.run("add development #{secret}")
@@ -10,11 +9,8 @@ module In
     end
 
     it "creates a totp for a certain key" do
-      totp = rand(100)
       subject.run("add development #{secret}")
-
-      authenticator.stub(:totp).with(secret).and_return(totp)
-      expect(subject.run("totp development")).to eql(totp)
+      expect(subject.run("totp development")).to_not be_nil
     end
   end
 end
spec/lib/totp_command_spec.rb
@@ -0,0 +1,22 @@
+require "tempfile"
+
+module In
+  describe TotpCommand do
+    subject { TotpCommand.new(storage) }
+    let(:secret) { ::ROTP::Base32.random_base32 }
+    let(:storage) { PStore.new(Tempfile.new('test').path) }
+
+    before :each do
+      storage.transaction do
+        storage['development'] = secret
+      end
+    end
+
+    describe "#run" do
+      it "returns a time based one time password for the authentication secret given" do
+        correct_code = ::ROTP::TOTP.new(secret).now
+        expect(subject.run(["development"])).to eql(correct_code)
+      end
+    end
+  end
+end
in.gemspec
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
   spec.version       = In::VERSION
   spec.authors       = ["mo khan"]
   spec.email         = ["mo@mokhan.ca"]
-  spec.summary       = %q{TODO: Write a short summary. Required.}
-  spec.description   = %q{TODO: Write a longer description. Optional.}
+  spec.summary       = %q{A CLI to manage your one time passwords.}
+  spec.description   = %q{A CLI to manage your one time passwords.}
   spec.homepage      = ""
   spec.license       = "MIT"
 
@@ -18,6 +18,7 @@ Gem::Specification.new do |spec|
   spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
   spec.require_paths = ["lib"]
 
+  spec.add_dependency "rotp"
   spec.add_development_dependency "bundler", "~> 1.6"
   spec.add_development_dependency "rake"
   spec.add_development_dependency "rspec"