[new] Use Truss exceptions on errors
Ref. https://cljdoc.org/d/com.taoensso/truss/CURRENT/api/taoensso.truss#*ctx*
This commit is contained in:
parent
da57206b0d
commit
8d62dc2826
6 changed files with 87 additions and 86 deletions
|
|
@ -4,6 +4,7 @@
|
|||
(:require
|
||||
[clojure.string :as str]
|
||||
[clojure.java.io :as jio]
|
||||
[taoensso.truss :as truss]
|
||||
[taoensso.encore :as enc]
|
||||
[taoensso.nippy
|
||||
[impl :as impl]
|
||||
|
|
@ -695,7 +696,7 @@
|
|||
(sm-count? len) (do (write-id out id-kw-sm) (write-sm-count out len))
|
||||
(md-count? len) (do (write-id out id-kw-md) (write-md-count out len))
|
||||
;; :else (do (write-id out id-kw-lg) (write-lg-count out len)) ; Unrealistic
|
||||
:else (throw (ex-info "Keyword too long" {:name s})))
|
||||
:else (truss/ex-info! "Keyword too long" {:name s}))
|
||||
|
||||
(.write out ba 0 len)))
|
||||
|
||||
|
|
@ -707,7 +708,7 @@
|
|||
(sm-count? len) (do (write-id out id-sym-sm) (write-sm-count out len))
|
||||
(md-count? len) (do (write-id out id-sym-md) (write-md-count out len))
|
||||
;; :else (do (write-id out id-sym-lg) (write-lg-count out len)) ; Unrealistic
|
||||
:else (throw (ex-info "Symbol too long" {:name s})))
|
||||
:else (truss/ex-info! "Symbol too long" {:name s}))
|
||||
|
||||
(.write out ba 0 len)))
|
||||
|
||||
|
|
@ -906,7 +907,7 @@
|
|||
(sm-count? len) (do (write-id out id-sz-quarantined-sm) (write-bytes-sm out class-name-ba))
|
||||
(md-count? len) (do (write-id out id-sz-quarantined-md) (write-bytes-md out class-name-ba))
|
||||
;; :else (do (write-id out id-sz-quarantined-lg) (write-bytes-md out class-name-ba)) ; Unrealistic
|
||||
:else (throw (ex-info "Serializable class name too long" {:name class-name})))
|
||||
:else (truss/ex-info! "Serializable class name too long" {:name class-name}))
|
||||
|
||||
;; Legacy: write object directly to out.
|
||||
;; (.writeObject (ObjectOutputStream. out) x)
|
||||
|
|
@ -931,8 +932,8 @@
|
|||
:else (do (write-id out id-reader-lg) (write-bytes-lg out edn-ba)))
|
||||
true)))
|
||||
|
||||
(defn ^:deprecated try-write-serializable [out x] (enc/catching (write-serializable out x)))
|
||||
(defn ^:deprecated try-write-readable [out x] (enc/catching (write-readable out x)))
|
||||
(defn ^:deprecated try-write-serializable [out x] (truss/catching :all (write-serializable out x)))
|
||||
(defn ^:deprecated try-write-readable [out x] (truss/catching :all (write-readable out x)))
|
||||
|
||||
(defn- try-pr-edn [x]
|
||||
(try
|
||||
|
|
@ -1028,7 +1029,7 @@
|
|||
(when first-occurance? (-freeze-with-meta! x-val out)))
|
||||
|
||||
:else
|
||||
;; (throw (ex-info "Max cache size exceeded" {:idx idx}))
|
||||
;; (truss/ex-info! "Max cache size exceeded" {:idx idx})
|
||||
(-freeze-with-meta! x-val out) ; Just freeze uncached
|
||||
))
|
||||
|
||||
|
|
@ -1045,7 +1046,7 @@
|
|||
(vswap! cache_ assoc idx x)
|
||||
x)
|
||||
v))
|
||||
(throw (ex-info "Can't thaw without cache available. See `with-cache`." {}))))))
|
||||
(truss/ex-info! "Can't thaw without cache available. See `with-cache`." {})))))
|
||||
|
||||
(comment
|
||||
(thaw (freeze [(cache "foo") (cache "foo") (cache "foo")]))
|
||||
|
|
@ -1129,7 +1130,7 @@
|
|||
(sm-count? len) (do (write-id out id-record-sm) (write-bytes-sm out class-name-ba))
|
||||
(md-count? len) (do (write-id out id-record-md) (write-bytes-md out class-name-ba))
|
||||
;; :else (do (write-id out id-record-lg) (write-bytes-md out class-name-ba)) ; Unrealistic
|
||||
:else (throw (ex-info "Record class name too long" {:name class-name})))
|
||||
:else (truss/ex-info! "Record class name too long" {:name class-name}))
|
||||
|
||||
(-freeze-without-meta! (into {} x) out)))
|
||||
|
||||
|
|
@ -1191,14 +1192,13 @@
|
|||
:if-let [fff *final-freeze-fallback*] (fff out x) ; Deprecated
|
||||
:else
|
||||
(let [t (type x)]
|
||||
(throw
|
||||
(ex-info (str "Failed to freeze type: " t)
|
||||
(enc/assoc-some
|
||||
{:type t
|
||||
:as-str (try-pr-edn x)}
|
||||
{:serializable-error e1
|
||||
:readable-error e2})
|
||||
(or e1 e2))))))))
|
||||
(truss/ex-info! (str "Failed to freeze type: " t)
|
||||
(enc/assoc-some
|
||||
{:type t
|
||||
:as-str (try-pr-edn x)}
|
||||
{:serializable-error e1
|
||||
:readable-error e2})
|
||||
(or e1 e2)))))))
|
||||
|
||||
;;;;
|
||||
|
||||
|
|
@ -1212,9 +1212,8 @@
|
|||
(defn- wrap-header [data-ba head-meta]
|
||||
(if-let [head-ba (get-head-ba head-meta)]
|
||||
(enc/ba-concat head-ba data-ba)
|
||||
(throw
|
||||
(ex-info (str "Unrecognized header meta: " head-meta)
|
||||
{:head-meta head-meta}))))
|
||||
(truss/ex-info! (str "Unrecognized header meta: " head-meta)
|
||||
{:head-meta head-meta})))
|
||||
|
||||
(comment (wrap-header (.getBytes "foo") {:compressor-id :lz4
|
||||
:encryptor-id nil}))
|
||||
|
|
@ -1377,7 +1376,7 @@
|
|||
|
||||
(defmacro ^:private editable? [coll] `(instance? clojure.lang.IEditableCollection ~coll))
|
||||
|
||||
(defn- xform* [xform] (enc/catching-xform {:error/msg "Error thrown via `*thaw-xform*`"} xform))
|
||||
(defn- xform* [xform] (truss/catching-xform {:error/msg "Error thrown via `*thaw-xform*`"} xform))
|
||||
|
||||
(let [rf! (fn rf! ([x] (persistent! x)) ([acc x] (conj! acc x)))
|
||||
rf* (fn rf* ([x] x) ([acc x] (conj acc x)))]
|
||||
|
|
@ -1414,14 +1413,12 @@
|
|||
(try
|
||||
(custom-reader in)
|
||||
(catch Exception e
|
||||
(throw
|
||||
(ex-info
|
||||
(str "Reader exception for custom type id: " type-id)
|
||||
{:type-id type-id, :prefixed? prefixed?} e))))
|
||||
(throw
|
||||
(ex-info
|
||||
(str "No reader provided for custom type id: " type-id)
|
||||
{:type-id type-id, :prefixed? prefixed?}))))
|
||||
(truss/ex-info!
|
||||
(str "Reader exception for custom type id: " type-id)
|
||||
{:type-id type-id, :prefixed? prefixed?} e)))
|
||||
(truss/ex-info!
|
||||
(str "No reader provided for custom type id: " type-id)
|
||||
{:type-id type-id, :prefixed? prefixed?})))
|
||||
|
||||
(defn- read-edn [edn]
|
||||
(try
|
||||
|
|
@ -1498,9 +1495,9 @@
|
|||
[^DataInput in class-name]
|
||||
(if (thaw-serializable-allowed? class-name)
|
||||
(read-object in class-name)
|
||||
(throw ; No way to skip bytes, so best we can do is throw
|
||||
(ex-info "Cannot thaw object: `taoensso.nippy/*thaw-serializable-allowlist*` check failed. This is a security feature. See `*thaw-serializable-allowlist*` docstring or https://github.com/ptaoussanis/nippy/issues/130 for details!"
|
||||
{:class-name class-name}))))
|
||||
(truss/ex-info! ; No way to skip bytes, so best we can do is throw
|
||||
"Cannot thaw object: `taoensso.nippy/*thaw-serializable-allowlist*` check failed. This is a security feature. See `*thaw-serializable-allowlist*` docstring or https://github.com/ptaoussanis/nippy/issues/130 for details!"
|
||||
{:class-name class-name})))
|
||||
|
||||
(defn- read-record [in class-name]
|
||||
(let [content (thaw-from-in! in)]
|
||||
|
|
@ -1753,15 +1750,13 @@
|
|||
|
||||
(if (neg? type-id)
|
||||
(read-custom! in nil type-id) ; Unprefixed custom type
|
||||
(throw
|
||||
(ex-info
|
||||
(str "Unrecognized type id (" type-id "). Data frozen with newer Nippy version?")
|
||||
{:type-id type-id}))))
|
||||
(truss/ex-info!
|
||||
(str "Unrecognized type id (" type-id "). Data frozen with newer Nippy version?")
|
||||
{:type-id type-id})))
|
||||
|
||||
(catch Throwable t
|
||||
(throw
|
||||
(ex-info (str "Thaw failed against type-id: " type-id)
|
||||
{:type-id type-id} t))))))
|
||||
(truss/ex-info! (str "Thaw failed against type-id: " type-id)
|
||||
{:type-id type-id} t)))))
|
||||
|
||||
(let [head-sig head-sig] ; Not ^:const
|
||||
(defn- try-parse-header [^bytes ba]
|
||||
|
|
@ -1781,20 +1776,20 @@
|
|||
:lzma2 lzma2-compressor
|
||||
:lz4 lz4-compressor
|
||||
:zstd zstd-compressor
|
||||
:no-header (throw (ex-info ":auto not supported on headerless data." {}))
|
||||
:else (throw (ex-info ":auto not supported for non-standard compressors." {}))
|
||||
(do (throw (ex-info (str "Unrecognized :auto compressor id: " compressor-id)
|
||||
{:compressor-id compressor-id})))))
|
||||
:no-header (truss/ex-info! ":auto not supported on headerless data." {})
|
||||
:else (truss/ex-info! ":auto not supported for non-standard compressors." {})
|
||||
(do (truss/ex-info! (str "Unrecognized :auto compressor id: " compressor-id)
|
||||
{:compressor-id compressor-id}))))
|
||||
|
||||
(defn- get-auto-encryptor [encryptor-id]
|
||||
(case encryptor-id
|
||||
nil nil
|
||||
:aes128-gcm-sha512 aes128-gcm-encryptor
|
||||
:aes128-cbc-sha512 aes128-cbc-encryptor
|
||||
:no-header (throw (ex-info ":auto not supported on headerless data." {}))
|
||||
:else (throw (ex-info ":auto not supported for non-standard encryptors." {}))
|
||||
(do (throw (ex-info (str "Unrecognized :auto encryptor id: " encryptor-id)
|
||||
{:encryptor-id encryptor-id})))))
|
||||
:no-header (truss/ex-info! ":auto not supported on headerless data." {})
|
||||
:else (truss/ex-info! ":auto not supported for non-standard encryptors." {})
|
||||
(do (truss/ex-info! (str "Unrecognized :auto encryptor id: " encryptor-id)
|
||||
{:encryptor-id encryptor-id}))))
|
||||
|
||||
(def ^:private err-msg-unknown-thaw-failure "Possible decryption/decompression error, unfrozen/damaged data, etc.")
|
||||
(def ^:private err-msg-unrecognized-header "Unrecognized (but apparently well-formed) header. Data frozen with newer Nippy version?")
|
||||
|
|
@ -1841,24 +1836,23 @@
|
|||
(fn ex
|
||||
([ msg] (ex nil msg))
|
||||
([e msg]
|
||||
(throw
|
||||
(ex-info (str "Thaw failed. " msg)
|
||||
{:opts
|
||||
(assoc opts
|
||||
:compressor compressor
|
||||
:encryptor encryptor)
|
||||
(truss/ex-info! (str "Thaw failed. " msg)
|
||||
{:opts
|
||||
(assoc opts
|
||||
:compressor compressor
|
||||
:encryptor encryptor)
|
||||
|
||||
:bindings
|
||||
(enc/assoc-some {}
|
||||
'*freeze-fallback* *freeze-fallback*
|
||||
'*final-freeze-fallback* *final-freeze-fallback*
|
||||
'*auto-freeze-compressor* *auto-freeze-compressor*
|
||||
'*custom-readers* *custom-readers*
|
||||
'*incl-metadata?* *incl-metadata?*
|
||||
'*thaw-serializable-allowlist* *thaw-serializable-allowlist*
|
||||
'*thaw-xform* *thaw-xform*)}
|
||||
:bindings
|
||||
(enc/assoc-some {}
|
||||
'*freeze-fallback* *freeze-fallback*
|
||||
'*final-freeze-fallback* *final-freeze-fallback*
|
||||
'*auto-freeze-compressor* *auto-freeze-compressor*
|
||||
'*custom-readers* *custom-readers*
|
||||
'*incl-metadata?* *incl-metadata?*
|
||||
'*thaw-serializable-allowlist* *thaw-serializable-allowlist*
|
||||
'*thaw-xform* *thaw-xform*)}
|
||||
|
||||
e))))
|
||||
e)))
|
||||
|
||||
thaw-data
|
||||
(fn [data-ba compressor-id encryptor-id ex-fn]
|
||||
|
|
@ -2243,5 +2237,5 @@
|
|||
(alter-var-root *thaw-serializable-allowlist* f) and/or
|
||||
(alter-var-root *freeze-serializable-allow-list* f) instead."
|
||||
[f]
|
||||
(alter-var-root *freeze-serializable-allowlist* (fn [old] (f (enc/have set? old))))
|
||||
(alter-var-root *thaw-serializable-allowlist* (fn [old] (f (enc/have set? old))))))
|
||||
(alter-var-root *freeze-serializable-allowlist* (fn [old] (f (truss/have set? old))))
|
||||
(alter-var-root *thaw-serializable-allowlist* (fn [old] (f (truss/have set? old))))))
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
(ns ^:no-doc taoensso.nippy.compression
|
||||
"Private, implementation detail."
|
||||
(:require [taoensso.encore :as enc])
|
||||
(:require
|
||||
[taoensso.truss :as truss]
|
||||
[taoensso.encore :as enc])
|
||||
(:import
|
||||
[java.nio ByteBuffer]
|
||||
[java.io
|
||||
|
|
@ -156,7 +158,7 @@
|
|||
(.read xzs ba 0 len-decomp)
|
||||
(if (== -1 (.read xzs)) ; Good practice as extra safety measure
|
||||
nil
|
||||
(throw (ex-info "LZMA2 Decompress failed: corrupt data?" {:ba ba})))
|
||||
(truss/ex-info! "LZMA2 Decompress failed: corrupt data?" {:ba ba}))
|
||||
ba)))
|
||||
|
||||
;;;; Public API
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
"Low-level crypto utils.
|
||||
Private & alpha, very likely to change!"
|
||||
(:refer-clojure :exclude [rand-nth])
|
||||
(:require [taoensso.encore :as enc]))
|
||||
(:require
|
||||
[taoensso.truss :as truss]
|
||||
[taoensso.encore :as enc]))
|
||||
|
||||
;; Note that AES128 may be preferable to AES256 due to known attack
|
||||
;; vectors specific to AES256, Ref. <https://goo.gl/qU4CCV>
|
||||
|
|
@ -45,7 +47,7 @@
|
|||
(defn take-ba ^bytes [n ^bytes ba] (java.util.Arrays/copyOf ba ^int n)) ; Pads if ba too small
|
||||
(defn utf8->ba ^bytes [^String s] (.getBytes s "UTF-8"))
|
||||
(defn- add-salt ^bytes [?salt-ba ba] (if ?salt-ba (enc/ba-concat ?salt-ba ba) ba))
|
||||
(defn pwd-as-ba ^bytes [utf8-or-ba] (if (string? utf8-or-ba) (utf8->ba utf8-or-ba) (enc/have enc/bytes? utf8-or-ba)))
|
||||
(defn pwd-as-ba ^bytes [utf8-or-ba] (if (string? utf8-or-ba) (utf8->ba utf8-or-ba) (truss/have enc/bytes? utf8-or-ba)))
|
||||
|
||||
(comment (seq (pwd-as-ba "foo")))
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
(ns ^:no-doc taoensso.nippy.encryption
|
||||
"Private, implementation detail."
|
||||
(:require
|
||||
[taoensso.truss :as truss]
|
||||
[taoensso.encore :as enc]
|
||||
[taoensso.nippy.crypto :as crypto]))
|
||||
|
||||
|
|
@ -14,11 +15,11 @@
|
|||
(decrypt ^bytes [encryptor pwd ba]))
|
||||
|
||||
(defn- throw-destructure-ex [typed-password]
|
||||
(throw (ex-info
|
||||
(str "Expected password form: "
|
||||
"[<#{:salted :cached}> <password-string>].\n "
|
||||
"See `aes128-encryptor` docstring for details!")
|
||||
{:typed-password typed-password})))
|
||||
(truss/ex-info!
|
||||
(str "Expected password form: "
|
||||
"[<#{:salted :cached}> <password-string>].\n "
|
||||
"See `aes128-encryptor` docstring for details!")
|
||||
{:typed-password typed-password}))
|
||||
|
||||
(defn- destructure-typed-pwd [typed-password]
|
||||
(if (vector? typed-password)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
"Private, implementation detail."
|
||||
(:require
|
||||
[clojure.string :as str]
|
||||
[taoensso.truss :as truss]
|
||||
[taoensso.encore :as enc]))
|
||||
|
||||
;;;; Fallback type tests
|
||||
|
|
@ -63,7 +64,7 @@
|
|||
(when x
|
||||
(if (string? x)
|
||||
(if (= x "") #{} (set (mapv str/trim (str/split x #"[,:]"))))
|
||||
(enc/have set? x))))
|
||||
(truss/have set? x))))
|
||||
|
||||
(comment
|
||||
(mapv classname-set [nil #{"foo"} "" "foo, bar:baz"])
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
[clojure.test.check :as tc]
|
||||
[clojure.test.check.generators :as tc-gens]
|
||||
[clojure.test.check.properties :as tc-props]
|
||||
[taoensso.truss :as truss :refer [throws?]]
|
||||
[taoensso.encore :as enc :refer [ba=]]
|
||||
[taoensso.nippy :as nippy :refer [freeze thaw]]
|
||||
[taoensso.nippy.compression :as compr]
|
||||
|
|
@ -75,9 +76,9 @@
|
|||
#(freeze % {:compressor nippy/zstd-compressor}))
|
||||
test-data)))
|
||||
|
||||
(is (enc/throws? Exception (thaw (freeze test-data {:password "malformed"}))))
|
||||
(is (enc/throws? Exception (thaw (freeze test-data {:password [:salted "p"]}))))
|
||||
(is (enc/throws? Exception (thaw (freeze test-data {:password [:salted "p"]}))))
|
||||
(is (throws? Exception (thaw (freeze test-data {:password "malformed"}))))
|
||||
(is (throws? Exception (thaw (freeze test-data {:password [:salted "p"]}))))
|
||||
(is (throws? Exception (thaw (freeze test-data {:password [:salted "p"]}))))
|
||||
|
||||
(is
|
||||
(= "payload"
|
||||
|
|
@ -94,12 +95,12 @@
|
|||
(let [n range-uint+] (= (thaw (freeze n)) n))
|
||||
(let [n (- range-uint+)] (= (thaw (freeze n)) n))]))
|
||||
|
||||
(is (enc/throws? :ex-info "Failed to freeze type" (nippy/freeze (fn []))))
|
||||
(is (throws? :ex-info "Failed to freeze type" (nippy/freeze (fn []))))
|
||||
|
||||
(testing "Clojure v1.10+ metadata protocol extensions"
|
||||
[(is (enc/throws? :ex-info "Failed to freeze type" (nippy/freeze (with-meta [] {:a :A, 'b (fn [])}))))
|
||||
(is (= {:a :A} (meta (nippy/thaw (nippy/freeze (with-meta [] {:a :A, 'b/c (fn [])}))))))
|
||||
(is (= nil (meta (nippy/thaw (nippy/freeze (with-meta [] { 'b/c (fn [])})))))
|
||||
[(is (throws? :ex-info "Failed to freeze type" (nippy/freeze (with-meta [] {:a :A, 'b (fn [])}))))
|
||||
(is (= {:a :A} (meta (nippy/thaw (nippy/freeze (with-meta [] {:a :A, 'b/c (fn [])}))))))
|
||||
(is (= nil (meta (nippy/thaw (nippy/freeze (with-meta [] { 'b/c (fn [])})))))
|
||||
"Don't attach empty metadata")])
|
||||
|
||||
(is (gen-test 1600 [gen-data] (= gen-data (thaw (freeze gen-data)))) "Generative")])
|
||||
|
|
@ -112,7 +113,7 @@
|
|||
(deftest _types
|
||||
[(testing "Extend to custom type"
|
||||
[(is
|
||||
(enc/throws? Exception ; No thaw extension yet
|
||||
(throws? Exception ; No thaw extension yet
|
||||
(do
|
||||
(alter-var-root #'nippy/*custom-readers* (constantly {}))
|
||||
(nippy/extend-freeze MyType 1 [x s]
|
||||
|
|
@ -323,7 +324,7 @@
|
|||
[(is (= nippy/*thaw-serializable-allowlist* #{"base.1" "base.2" "add.1" "add.2"})
|
||||
"JVM properties override initial allowlist values")
|
||||
|
||||
(is (enc/throws? Exception (nippy/freeze sem {:serializable-allowlist #{}}))
|
||||
(is (throws? Exception (nippy/freeze sem {:serializable-allowlist #{}}))
|
||||
"Can't freeze Serializable objects unless approved by allowlist")
|
||||
|
||||
(is (sem?
|
||||
|
|
@ -435,8 +436,8 @@
|
|||
|
||||
(is (= (binding [nippy/*thaw-xform* (map (fn [x] (/ 1 0)))] (thaw (freeze []))) []) "rf not run on empty colls")
|
||||
|
||||
(let [ex (enc/throws :default (binding [nippy/*thaw-xform* (map (fn [x] (/ 1 0)))] (thaw (freeze [:a :b]))))]
|
||||
(is (= (-> ex enc/ex-cause enc/ex-cause ex-data :call) '(rf acc in)) "Error thrown via `*thaw-xform*`"))])
|
||||
(let [ex (truss/throws :default (binding [nippy/*thaw-xform* (map (fn [x] (/ 1 0)))] (thaw (freeze [:a :b]))))]
|
||||
(is (= (-> ex ex-cause ex-cause ex-data :call) '(rf acc in)) "Error thrown via `*thaw-xform*`"))])
|
||||
|
||||
;;;; Compressors
|
||||
|
||||
|
|
@ -453,7 +454,7 @@
|
|||
(print ".") (flush)
|
||||
(dotimes [_ 1000]
|
||||
(is
|
||||
(nil? (enc/catching (compr/decompress c (crypto/rand-bytes 1024))))
|
||||
(nil? (truss/catching :all (compr/decompress c (crypto/rand-bytes 1024))))
|
||||
"Decompression never crashes JVM, even against invalid data")))
|
||||
(println)))
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue