/usr/share/pass/lastpass2pass.rb is in pass 1.6.5-3.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
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 | #!/usr/bin/env ruby
# Copyright (C) 2012 Alex Sayers <alex.sayers@gmail.com>. All Rights Reserved.
# This file is licensed under the GPLv2+. Please see COPYING for more information.
# LastPass Importer
#
# Reads CSV files exported from LastPass and imports them into pass.
# Usage:
#
# Go to lastpass.com and sign in. Next click on your username in the top-right
# corner. In the drop-down meny that appears, click "Export". After filling in
# your details again, copy the text and save it somewhere on your disk. Make sure
# you copy the whole thing, and resist the temptation to "Save Page As" - the
# script doesn't like HTML.
#
# Fire up a terminal and run the script, passing the file you saved as an argument.
# It should look something like this:
#
#$ ./lastpass2pass.rb path/to/passwords_file.csv
# Parse flags
require 'optparse'
optparse = OptionParser.new do |opts|
opts.banner = "Usage: #{$0} [options] filename"
FORCE = false
opts.on("-f", "--force", "Overwrite existing records") { FORCE = true }
DEFAULT_GROUP = ""
opts.on("-d", "--default GROUP", "Place uncategorised records into GROUP") { |group| DEFAULT_GROUP = group }
opts.on("-h", "--help", "Display this screen") { puts opts; exit }
opts.parse!
end
# Check for a filename
if ARGV.empty?
puts optparse
exit 0
end
# Get filename of csv file
filename = ARGV.join(" ")
puts "Reading '#{filename}'..."
class Record
def initialize name, url, username, password, extra, grouping, fav
@name, @url, @username, @password, @extra, @grouping, @fav = name, url, username, password, extra, grouping, fav
end
def name
s = ""
s << @grouping + "/" unless @grouping.empty?
s << @name
s.gsub(/ /, "_").gsub(/'/, "")
end
def to_s
s = ""
s << "#{@password}\n---\n"
s << "#{@grouping} / " unless @grouping.empty?
s << "#{@name}\n"
s << "username: #{@username}\n" unless @username.empty?
s << "password: #{@password}\n" unless @password.empty?
s << "url: #{@url}\n" unless @url == "http://sn"
s << "#{@extra}\n" unless @extra.nil?
return s
end
end
# Extract individual records
entries = []
entry = ""
begin
file = File.open(filename)
file.each do |line|
if line =~ /^http/
entries.push(entry)
entry = ""
end
entry += line
end
entries.push(entry)
entries.shift
puts "#{entries.length} records found!"
rescue
puts "Couldn't find #{filename}!"
exit 1
end
# Parse records and create Record objects
records = []
entries.each do |e|
args = e.split(",")
url = args.shift
username = args.shift
password = args.shift
fav = args.pop
grouping = args.pop
grouping = DEFAULT_GROUP if grouping.empty?
name = args.pop
extra = args.join(",")[1...-1]
records << Record.new(name, url, username, password, extra, grouping, fav)
end
puts "Records parsed: #{records.length}"
successful = 0
errors = []
records.each do |r|
print "Creating record #{r.name}..."
IO.popen("pass insert -m#{"f" if FORCE} '#{r.name}' > /dev/null", 'w') do |io|
io.puts r
end
if $? == 0
puts " done!"
successful += 1
else
puts " error!"
errors << r
end
end
puts "#{successful} records successfully imported!"
if errors
puts "There were #{errors.length} errors:"
errors.each { |e| print e.name + (e == errors.last ? ".\n" : ", ")}
puts "These probably occurred because an identically-named record already existed, or because there were multiple entries with the same name in the csv file."
end
|