aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib')
-rwxr-xr-xcontrib/importers/roboform2pass.rb162
1 files changed, 162 insertions, 0 deletions
diff --git a/contrib/importers/roboform2pass.rb b/contrib/importers/roboform2pass.rb
new file mode 100755
index 0000000..df0f266
--- /dev/null
+++ b/contrib/importers/roboform2pass.rb
@@ -0,0 +1,162 @@
+#!/usr/bin/env ruby
+
+# Copyright 2015 Sergey Makridenkov <sergey@makridenkov.com>.
+# Released under MIT License.
+#
+# Usage:
+# 1. Save roboform print lists (like File > Print lists > Logins) to ~/roboform_print_lists.
+# 2. Run import: ./roboform2pass.rb ~/roboform_print_lists
+
+
+require 'nokogiri'
+
+class Login
+ def initialize
+ self.fields = {}
+ self.raw = []
+ end
+
+ attr_accessor :key
+ attr_accessor :password
+ attr_accessor :url
+ attr_accessor :fields
+ attr_accessor :raw
+
+ def ask_required_info
+ ask!(:key) if blank?(key)
+ find_password!
+ if blank?(password)
+ ask!(:password)
+ puts ''
+ end
+ end
+
+ def save
+ if valid?
+ IO.popen("pass insert -m -f '#{path}' > /dev/null", "w") do |pass_io|
+ pass_io.puts password
+ pass_io.puts "Url: #{url}" if present?(url)
+ pass_io.puts "Fields: #{fields}" if fields.any?
+ pass_io.puts "Notes: #{raw}" if raw.any?
+ end
+
+ $? == 0
+ end
+ end
+
+ private
+
+ def path
+ key = self.key.downcase.gsub(/[^\w\.\/]/, '_').gsub(/_{2,}/, '_')
+ "roboform/#{key}"
+ end
+
+ def valid?
+ present?(key) && present?(password)
+ end
+
+ def find_password!
+ fields.each do |key, val|
+ key = key.downcase
+ if key.include?('password') || key.include?('pwd') || key.include?('pass')
+ self.password = val
+ end
+ end
+ end
+
+ def ask!(field)
+ puts Colorize.red("#{field.capitalize} is empty for login:")
+ print_self
+ print Colorize.green "Please type #{field}: "
+ self.send("#{field}=", gets.chomp)
+ end
+
+ def print_self
+ puts Colorize.yellow "\tKey:\t#{key}" if present?(key)
+ puts Colorize.yellow "\tPassword:\t#{password}" if present?(password)
+ puts Colorize.yellow "\tUrl:\t#{url}" if present?(url)
+ puts Colorize.yellow "\tFields:\t#{fields}" if fields.any?
+ puts Colorize.yellow "\tRaw:\t#{raw}" if raw.any?
+ end
+
+ def blank?(str)
+ !str || str.strip.empty?
+ end
+
+ def present?(str)
+ !blank?(str)
+ end
+end
+
+class Colorize
+ class << self
+ def red(mes)
+ colorize(31, mes)
+ end
+
+ def green(mes)
+ colorize(32, mes)
+ end
+
+ def yellow(mes)
+ colorize(33, mes)
+ end
+
+ def pink(mes)
+ colorize(35, mes)
+ end
+
+ private
+
+ def colorize(color_code, mes)
+ "\e[#{color_code}m#{mes}\e[0m"
+ end
+ end
+end
+
+
+print_list_dir = ARGV.pop
+unless print_list_dir
+ raise "No dir/to/roboform/print_lists"
+end
+print_list_dir = File.expand_path(print_list_dir)
+
+# parse logins
+logins_path = Dir.glob("#{print_list_dir}/RoboForm Logins*.html").first
+unless logins_path
+ raise 'Login HTML (RoboForm Logins*.html) not found'
+end
+
+html_logins = Nokogiri::HTML(File.open(logins_path))
+
+saved_logins = 0
+
+html_logins.css('table').each do |table|
+ login = Login.new
+
+ table.css('tr').each do |tr|
+ caption = tr.at_css('.caption')
+ subcaption = tr.at_css('.subcaption')
+ key = tr.at_css('.field')
+
+ if caption
+ login.key = caption.text()
+ elsif subcaption
+ login.url = subcaption.text()
+ elsif key
+ login.fields[key.text()] = tr.at_css('.wordbreakfield').text()
+ else
+ login.raw << tr.at_css('.wordbreakfield').text()
+ end
+ end
+
+ if login.fields.any?
+ login.ask_required_info
+ if login.save
+ saved_logins += 1
+ end
+ end
+end
+
+puts "Imported passwords: #{saved_logins}"
+