#!/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 flagsrequire'optparse'optparse=OptionParser.newdo|opts|opts.banner="Usage: #{$0} [options] filename"FORCE=falseopts.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"){putsopts;exit}opts.parse!end# Check for a filenameifARGV.empty?putsoptparseexit0end# Get filename of csv filefilename=ARGV.join(" ")puts"Reading '#{filename}'..."classRecorddefinitializename,url,username,password,extra,grouping,fav@name,@url,@username,@password,@extra,@grouping,@fav=name,url,username,password,extra,grouping,favenddefnames=""s<<@grouping+"/"unless@grouping.empty?s<<@nameunless@name==nils.gsub(/ /,"_").gsub(/'/,"")enddefto_ss=""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?returnsendend# Extract individual recordsentries=[]entry=""beginfile=File.open(filename)file.eachdo|line|ifline=~/^(http|ftp|ssh)/entries.push(entry)entry=""endentry+=lineendentries.push(entry)entries.shiftputs"#{entries.length} records found!"rescueputs"Couldn't find #{filename}!"exit1end# Parse records and create Record objectsrecords=[]entries.eachdo|e|args=e.split(",")url=args.shiftusername=args.shiftpassword=args.shiftfav=args.popgrouping=args.popgrouping=DEFAULT_GROUPifgrouping==nilname=args.popextra=args.join(",")[1...-1]records<<Record.new(name,url,username,password,extra,grouping,fav)endputs"Records parsed: #{records.length}"successful=0errors=[]records.eachdo|r|ifFile.exist?("#{r.name}.gpg")andFORCE==falseputs"skipped #{r.name}: already exists"nextendprint"Creating record #{r.name}..."IO.popen("pass insert -m '#{r.name}' > /dev/null",'w')do|io|io.putsrendif$?==0puts" done!"successful+=1elseputs" error!"errors<<rendendputs"#{successful} records successfully imported!"iferrors.length>0puts"There were #{errors.length} errors:"errors.each{|e|printe.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