Commit b8a3266

mo <mo.khan@gmail.com>
2018-02-10 19:15:44
add command to upgrade the .tfa.pstore to .tfa.yml
1 parent c00efba
Changed files (3)
lib/tfa/cli.rb
@@ -33,13 +33,61 @@ module TFA
       TotpCommand.new(storage).run('', secret)
     end
 
+    desc "upgrade", "upgrade the pstore database to a yml database."
+    def upgrade
+      pstore_path = File.join(directory, ".#{filename}.pstore")
+      yml_path = File.join(directory, ".#{filename}.yml")
+
+      if !File.exist?(pstore_path)
+        say "Unable to detect #{pstore_path}"
+        return ""
+      end
+
+      say "Detected #{pstore_path}"
+      case ask "Would you like to upgrade to #{yml_path}", limited_to: ["yes", "no"]
+      when "yes"
+        say "Let's begin..."
+        pstore_storage = Storage.new(pstore_path)
+        yaml_storage = Storage.new(yml_path)
+        pstore_storage.each do |row|
+          row.each do |name, secret|
+            case ask "Would you like to migrate `#{name}`?", limited_to: ["yes", "no"]
+            when "yes"
+              say "Migrating `#{name}`..."
+              yaml_storage.save(name, secret)
+            end
+          end
+        end
+        case ask "Would you like to delete `#{pstore_path}`? (this action cannot be undone.)", limited_to: ["yes", "no"]
+        when "yes"
+          File.delete(pstore_path)
+        end
+      else
+        say "Nothing to do. Goodbye!"
+      end
+      ""
+    end
+
     private
 
     def storage
-      @storage ||= Storage.new(
-        filename: options[:filename] || 'tfa',
-        directory: options[:directory] || Dir.home,
-      )
+      @storage ||= Storage.new(File.exist?(pstore_path) ? pstore_path : yml_path)
+    end
+
+    def filename
+      options[:filename] || 'tfa'
+    end
+
+    def directory
+      options[:directory] || Dir.home
+    end
+
+    def pstore_path
+      File.join(directory, ".#{filename}.pstore")
+    end
+
+    def yml_path
+      File.join(directory, ".#{filename}.yml")
     end
 
     def clean(secret)
lib/tfa/storage.rb
@@ -2,14 +2,13 @@ module TFA
   class Storage
     include Enumerable
 
-    def initialize(filename: 'tfa', directory: Dir.home)
-      pstore_path = File.join(directory, ".#{filename}.pstore")
-      if File.exist?(pstore_path)
-        @storage = PStore.new(pstore_path)
-      else
-        path = File.join(directory, ".#{filename}.yml")
-        @storage = YAML::Store.new(path)
-      end
+    def initialize(path)
+      @storage =
+        if ".pstore" == File.extname(path)
+          PStore.new(path)
+        else
+          YAML::Store.new(path)
+        end
     end
 
     def each
spec/lib/totp_command_spec.rb
@@ -1,7 +1,7 @@
 module TFA
   describe TotpCommand do
     subject { TotpCommand.new(storage) }
-    let(:storage) { Storage.new(filename: SecureRandom.uuid, directory: Dir.tmpdir) }
+    let(:storage) { Storage.new(File.join(Dir.tmpdir, ".#{SecureRandom.uuid}.yml")) }
 
     def code_for(secret)
       ::ROTP::TOTP.new(secret).now