diff --git a/README.md b/README.md index bcf5f78..4af8711 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ Current [semantic](http://semver.org/) version: ```clojure [com.taoensso/nippy "1.2.1"] ; Stable -[com.taoensso/nippy "2.0.0-alpha8"] ; Development (notes below) +[com.taoensso/nippy "2.0.0-alpha9"] ; Development (notes below) ``` -2.x adds pluggable compression, crypto support (also pluggable), an improved API (including much better error messages), and hugely improved performance. It **is backwards compatible**, but please note that the old `freeze-to-bytes`/`thaw-from-bytes` API has been **deprecated** in favor of `freeze`/`thaw`. **PLEASE REPORT ANY PROBLEMS!** +v2 adds pluggable compression, crypto support (also pluggable), an improved API (including much better error messages), easier integration into other tools/libraries, and hugely improved performance. It **is backwards compatible**, but please note that the old `freeze-to-bytes`/`thaw-from-bytes` API has been **deprecated** in favor of `freeze`/`thaw`. **PLEASE REPORT ANY PROBLEMS!** # Nippy, a Clojure serialization library @@ -20,7 +20,8 @@ Nippy is an attempt to provide a reliable, high-performance **drop-in alternativ * **Reader-fallback** for difficult/future types (including Clojure 1.4+ tagged literals). * **Full test coverage** for every supported type. * Fully pluggable **compression**, including built-in high-performance [Snappy](http://code.google.com/p/snappy/) compressor. - * Fully pluggable **encryption**, including built-in high-strength AES128 enabled with a single `:password [:salted "my-password"]` option. (2.0.0+) + * Fully pluggable **encryption**, including built-in high-strength AES128 enabled with a single `:password [:salted "my-password"]` option. (v2+) + * Utils for **easy integration into 3rd-party tools/libraries**. (v2+) ## Getting started @@ -103,7 +104,7 @@ Couldn't be simpler! ### Encryption (currently in **ALPHA**) -As of 2.0.0, Nippy also gives you **dead simple data encryption**. Add a single option to your usual freeze/thaw calls like so: +Nippy v2+ also gives you **dead simple data encryption**. Add a single option to your usual freeze/thaw calls like so: ```clojure (nippy/freeze nippy/stress-data {:password [:salted "my-password"]}) ; Encrypt diff --git a/project.clj b/project.clj index 89565ca..b81e797 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject com.taoensso/nippy "2.0.0-alpha8" +(defproject com.taoensso/nippy "2.0.0-alpha9" :description "Clojure serialization library" :url "https://github.com/ptaoussanis/nippy" :license {:name "Eclipse Public License" diff --git a/src/clj/taoensso/nippy.clj b/src/clj/taoensso/nippy.clj index 15d8620..ceac984 100644 --- a/src/clj/taoensso/nippy.clj +++ b/src/clj/taoensso/nippy.clj @@ -269,7 +269,8 @@ [^bytes ba & [{:keys [read-eval? password compressor encryptor legacy-opts] :or {legacy-opts {:compressed? true} compressor snappy-compressor - encryptor aes128-encryptor}}]] + encryptor aes128-encryptor} + :as opts}]] (let [ex (fn [msg & [e]] (throw (Exception. (str "Thaw failed: " msg) e))) try-thaw-data @@ -301,7 +302,8 @@ (and compressed? (not compressor)) (ex "Compressed data. Try again with compressor.") (and encrypted? (not password)) - (ex "Encrypted data. Try again with password.") + (if (::tools-thaw? opts) ::need-password + (ex "Encrypted data. Try again with password.")) :else (try (try-thaw-data data-ba head-meta) (catch Exception _ (try-thaw-data ba nil)))) @@ -383,4 +385,4 @@ :or {compressed? true}}] (thaw ba {:legacy-opts {:compressed? compressed?} :read-eval? read-eval? - :password nil})) + :password nil})) \ No newline at end of file diff --git a/src/clj/taoensso/nippy/tools.clj b/src/clj/taoensso/nippy/tools.clj new file mode 100644 index 0000000..0087fcc --- /dev/null +++ b/src/clj/taoensso/nippy/tools.clj @@ -0,0 +1,46 @@ +(ns taoensso.nippy.tools + "Alpha - subject to change. + Utilities for third-party tools that want to add fully-user-configurable Nippy + support. Used by Carmine and Faraday." + {:author "Peter Taoussanis"} + (:require [taoensso.nippy :as nippy] + [taoensso.nippy.utils :as utils])) + +(defrecord WrappedForFreezing [value opts]) +(defn wrapped-for-freezing? [x] (instance? WrappedForFreezing x)) +(defn wrap-for-freezing + "Wraps arg (any freezable data type) so that (tools/freeze ) + will freeze the arg using given options." + [value & [opts]] (WrappedForFreezing. value opts)) + +(defn freeze + "Like `nippy/freeze` but takes options from special argument wrapper when + present." + [x & [{:keys [default-opts]}]] + (if (wrapped-for-freezing? x) + (nippy/freeze (:value x) (or (:opts x) default-opts)) + (nippy/freeze x default-opts))) + +(comment (freeze (wrap-for-freezing "wrapped")) + (freeze "unwrapped")) + +(defrecord EncryptedFrozen [ba]) +(defn encrypted-frozen? [x] (instance? EncryptedFrozen x)) + +(def ^:dynamic *thaw-opts* nil) +(defmacro with-thaw-opts [opts & body] `(binding [*thaw-opts* ~opts] ~@body)) + +(defn thaw + "Like `nippy/thaw` but takes options from *thaw-opts* binding, and wraps + encrypted bytes for easy identification when no password has been provided + for decryption." + [ba & {:keys [default-opts]}] + (let [result (nippy/thaw ba (merge (or *thaw-opts* default-opts) + {:taoensso.nippy/tools-thaw? true}))] + (if (= result :taoensso.nippy/need-password) + (EncryptedFrozen. ba) + result))) + +(comment (thaw (nippy/freeze "c" {:password [:cached "p"]})) + (with-thaw-opts {:password [:cached "p"]} + (thaw (nippy/freeze "c" {:password [:cached "p"]})))) \ No newline at end of file