blob: df0f266605182607b615760b1b6398fae6905cf6 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
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}"
|