Artifact 92003497491a81abb0ef4753135c7606a101f9b342ae71a608bc365948633601:
- Executable file
lastpass2pwman.lisp
— part of check-in
[1ead16f19c]
at
2013-02-03 21:42:51
on branch master
— Store secure notes in the "launch" field as it's 256 vs 64 char
And secure notes are likely to be longer. Since whole file is encrypted
anyway, doesn't matter which field you use to store things in. Saves
patching PWman to make the password field accept more chars.Add note to README regarding this known limitation. (user: atomicules@lavabit.com size: 3231)
;CLisp script for SBCL to convert lastpass CSV export to PWman format ;See README for usage instructions ;Load quicklisp (load "~/.sbclrc") ;Load libraries (ql:quickload "csv-parser") (ql:quickload "xmls") ;Note to self: Start with 2nd *posix-argv* as first is always /path/to/sbcl, etc ;gpgid to encrypt file with (defparameter gpgid (second *posix-argv*)) ;Check for supplied filename, otherwise assume called lastpass.csv (defparameter infile (if (null (third *posix-argv*)) "lastpass.csv" (third *posix-argv*))) ;read the lastpass file and build up hash for each group (defparameter *lastpass* (make-hash-table)) (csv-parser:map-csv-file infile (lambda (ln) (if (gethash (read-from-string (substitute #\- #\Space (sixth ln))) *lastpass*) ;Group ;Note, without (intern (string-upcase or (read-from-string keys aren't set properly and something bizarre happens (setf (gethash (read-from-string (substitute #\- #\Space (sixth ln))) *lastpass*) (append (gethash (read-from-string (substitute #\- #\Space (sixth ln))) *lastpass*) (list ln))) ;append key (setf (gethash (read-from-string (substitute #\- #\Space (sixth ln))) *lastpass*) (list ln)))) :skip-lines 1) ;create key ;Write hash out as XML (with-open-file (stream "pwman.txt" :direction :output :if-exists :supersede) (format stream "<?xml version=\"1.0\"?><PWMan_PasswordList version=\"3\"><PwList name=\"Main\">") ;For each key in hash (with-hash-table-iterator (group *lastpass*) (loop (multiple-value-bind (returned? groupname groupentries) (group) (if returned? (progn (format stream "<PwList name=\"~a\">" groupname) ;Then loop through each entry in group (loop for entry in groupentries do (format stream "<PwItem><name>~a</name><host>~a</host><user>~a</user><passwd>~a</passwd><launch>~a</launch></PwItem>" (xmls:toxml (fifth entry)) (xmls:toxml (first entry)) (xmls:toxml (second entry)) (if (null (third entry)) ;Secure Notes have no password "" ;put nothing in pwman password field if Secure Note (xmls:toxml (third entry))) (if (null (third entry)) (xmls:toxml (fourth entry)) ;Use launch field for Secure Notes as it is longer ""))) (format stream "</PwList>")) (return))))) (format stream "</PwList></PWMan_PasswordList>")) ;Move original file to backup (rename-file (concatenate 'string (sb-unix::posix-getenv "HOME") "/.pwman.db") (concatenate 'string (sb-unix::posix-getenv "HOME") "/.pwman.db.bak")) ;gpg encrpyt the file (let ((proc (sb-ext:run-program "gpg" (list "-a" "-r" gpgid "-o" (concatenate 'string (sb-unix::posix-getenv "HOME") "/.pwman.db") "-e" "pwman.txt") :search :environment))) (if (= 0 (sb-ext:process-exit-code proc)) ;If that was successful, then delete the un-encrypted files (progn (delete-file infile) (delete-file "pwman.txt")) ;If not restore backup and leave plain text files (otherwise will fail next time on above rename) (progn (rename-file (concatenate 'string (sb-unix::posix-getenv "HOME") "/.pwman.db.bak") (concatenate 'string (sb-unix::posix-getenv "HOME") "/.pwman.db")) (print "Couldn't encrypt file, plain text files have not been deleted"))))