From 0fb529fc0ea2e6ff1f5ed88902510322e2c8a693 Mon Sep 17 00:00:00 2001 From: Alex Dunn Date: Wed, 21 Dec 2016 06:22:13 +0100 Subject: 1password2pass: modernization --- contrib/importers/1password2pass.rb | 38 ++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/contrib/importers/1password2pass.rb b/contrib/importers/1password2pass.rb index 79318ee..e0ca39b 100755 --- a/contrib/importers/1password2pass.rb +++ b/contrib/importers/1password2pass.rb @@ -2,13 +2,13 @@ # Copyright (C) 2014 Tobias V. Langhoff . All Rights Reserved. # This file is licensed under GPLv2+. Please see COPYING for more information. -# +# # 1Password Importer -# +# # Reads files exported from 1Password and imports them into pass. Supports comma # and tab delimited text files, as well as logins (but not other items) stored # in the 1Password Interchange File (1PIF) format. -# +# # Supports using the title (default) or URL as pass-name, depending on your # preferred organization. Also supports importing metadata, adding them with # `pass insert --multiline`; the username and URL are compatible with @@ -44,7 +44,7 @@ optparse = OptionParser.new do |opts| options.meta = meta end - begin + begin opts.parse! rescue OptionParser::InvalidOption $stderr.puts optparse @@ -95,25 +95,33 @@ if File.extname(filename) =~ /.txt/i elsif File.extname(filename) =~ /.1pif/i require "json" - # 1PIF is almost JSON, but not quite - pif = "[#{File.open(filename).read}]" - pif.gsub!(/^\*\*\*.*\*\*\*$/, ",") - pif = JSON.parse(pif, {symbolize_names: true}) - options.name = :location if options.name == :url + # 1PIF is almost JSON, but not quite. Remove the ***...*** lines + # separating records, and then remove the trailing comma + pif = File.open(filename).read.gsub(/^\*\*\*.*\*\*\*$/, ",").chomp.chomp(",") + # Import 1PIF - pif.each do |entry| + JSON.parse("[#{pif}]", symbolize_names: true).each do |entry| next unless entry[:typeName] == "webforms.WebForm" + next if entry[:secureContents][:fields].nil? + pass = {} + pass[:name] = "#{(options.group + "/") if options.group}#{entry[options.name]}" + pass[:title] = entry[:title] + pass[:password] = entry[:secureContents][:fields].detect do |field| - field[:name] == "password" - end[:value] - pass[:login] = entry[:secureContents][:fields].detect do |field| - field[:name] == "username" + field[:designation] == "password" end[:value] + + username = entry[:secureContents][:fields].detect do |field| + field[:designation] == "username" + end + # might be nil + pass[:login] = username[:value] if username + pass[:url] = entry[:location] pass[:notes] = entry[:secureContents][:notesPlain] passwords << pass @@ -125,7 +133,7 @@ puts "Read #{passwords.length} passwords." errors = [] # Save the passwords passwords.each do |pass| - IO.popen("pass insert #{"-f " if options.force}-m '#{pass[:name]}' > /dev/null", "w") do |io| + IO.popen("pass insert #{"-f " if options.force}-m \"#{pass[:name]}\" > /dev/null", "w") do |io| io.puts pass[:password] if options.meta io.puts "login: #{pass[:login]}" unless pass[:login].to_s.empty? -- cgit v1.2.3