I’m not sure if these were all changes in how 1Password exports 1PIF
files, or if I just had a messy vault with lots of edge cases, but these
were changes I needed to make to run the importer on a .1pif file
exported by 1Password 6.5.1 on macOS 10.12.1.

Thanks!

>From e846c9add61cf974e1817f259fb86ed9795c00b0 Mon Sep 17 00:00:00 2001
From: Alex Dunn <[email protected]>
Date: Tue, 29 Nov 2016 09:12:26 -0800
Subject: [PATCH 1/3] 1password2pass: fix 1PIF conversion to JSON

---
 contrib/importers/1password2pass.rb | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/contrib/importers/1password2pass.rb b/contrib/importers/1password2pass.rb
index 79318ee..4a11e6b 100755
--- a/contrib/importers/1password2pass.rb
+++ b/contrib/importers/1password2pass.rb
@@ -2,13 +2,13 @@
 
 # Copyright (C) 2014 Tobias V. Langhoff <[email protected]>. 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 @@
     options.meta = meta
   end
 
-  begin 
+  begin
     opts.parse!
   rescue OptionParser::InvalidOption
     $stderr.puts optparse
@@ -95,15 +95,14 @@
 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"
     pass = {}
     pass[:name] = "#{(options.group + "/") if options.group}#{entry[options.name]}"

>From 4c49ca898a9da5708cec6c617d7451f44d5b5c74 Mon Sep 17 00:00:00 2001
From: Alex Dunn <[email protected]>
Date: Tue, 29 Nov 2016 09:50:19 -0800
Subject: [PATCH 2/3] 1password2pass: more reliable parsing of 1PIF JSON

- skip entries without secureContents fields

- use :designation instead of :name

- handle empty username fields
---
 contrib/importers/1password2pass.rb | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/contrib/importers/1password2pass.rb b/contrib/importers/1password2pass.rb
index 4a11e6b..f44bab7 100755
--- a/contrib/importers/1password2pass.rb
+++ b/contrib/importers/1password2pass.rb
@@ -104,15 +104,24 @@
   # Import 1PIF
   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

>From 645e5dfdaf603782ff92c733564936e6da24845f Mon Sep 17 00:00:00 2001
From: Alex Dunn <[email protected]>
Date: Tue, 29 Nov 2016 09:52:57 -0800
Subject: [PATCH 3/3] 1password2pass: put pass[:name] in doublequotes

It's more likely that there'll be a single quote in the name (e.g.,
"O'Reilly"), so handle those cases.
---
 contrib/importers/1password2pass.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/contrib/importers/1password2pass.rb b/contrib/importers/1password2pass.rb
index f44bab7..e0ca39b 100755
--- a/contrib/importers/1password2pass.rb
+++ b/contrib/importers/1password2pass.rb
@@ -133,7 +133,7 @@
 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?
_______________________________________________
Password-Store mailing list
[email protected]
https://lists.zx2c4.com/mailman/listinfo/password-store

Reply via email to