Skip to content

Instantly share code, notes, and snippets.

@jellea
Created October 31, 2016 23:13
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jellea/e028356a805af1f6a9c0dfbec4186560 to your computer and use it in GitHub Desktop.
Save jellea/e028356a805af1f6a9c0dfbec4186560 to your computer and use it in GitHub Desktop.
Lastpass csv to Keepass xml converter
(ns last2kee.core
(:require [clojure.set :as set]
[clojure.data.csv :as csv]
[clojure.data.xml :as xml]
[clojure.string :as string]
[clojure.java.io :as io]))
(defn csvvec-to-map [csvdata]
(map #(zipmap (first csvdata) %) (rest csvdata)))
(defn read-lastpass-csv [file-name]
(with-open [in-file (io/reader file-name)]
(doall
(csv/read-csv in-file))))
(defn map-kv [f m]
(reduce-kv #(conj %1 (f %2 %3)) [] m))
(defn escape-chars [v]
(string/escape v {\< "&lt;", \> "&gt;", \& "&amp;", \" "&quot;" \' "&apos;"}))
(defn safe-uuid []
(apply str (string/split (str (java.util.UUID/randomUUID)) #"-")))
(defn gen-field [k v]
[:String {}
[:Key {} (escape-chars (name k))]
(if (= k :Password)
[:Value {:ProtectInMemory "True"} v]
[:Value {} (escape-chars v)])])
(defn gen-entry [row]
(let [row* (set/rename-keys row {"name" :Title "extra" :Notes "url" :URL, "username" :UserName, "password" :Password})]
(into
[:Entry {}
[:UUID {} (safe-uuid)]]
(map-kv gen-field row*))))
(defn gen-keepass-xml [data]
(xml/sexp-as-element
[:KeePassFile {}
[:Meta]
[:Root {}
(into
[:Group {
[:UUID {} (safe-uuid)]
[:Name {} "LastPass import"]]
(map gen-entry data))]]))
(defn write-xml [data file-name]
(with-open [out-file (java.io.OutputStreamWriter.
(java.io.FileOutputStream. file-name) "UTF-8")]
(xml/emit data out-file)))
(comment
(-> (read-lastpass-csv "lastpass.csv")
(csvvec-to-map)
(gen-keepass-xml)
(write-xml "keepass.xml")))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment