~miikka/clj-branca

5705f015d5331886c0103cfc656b6ca5f6878bb3 — Miikka Koskinen 1 year, 2 months ago 047474d
feat: allow passing the current time as an Inst

https://todo.sr.ht/~miikka/clj-branca/2
3 files changed, 23 insertions(+), 10 deletions(-)

M doc/user-guide.adoc
M src/clj_branca/core.clj
M test/clj_branca/core_test.clj
M doc/user-guide.adoc => doc/user-guide.adoc +1 -1
@@ 88,7 88,7 @@ calling `branca/decode`. For example, to limit token lifetime to an hour:

If the token is expired, `branca/decode` <<error-handling,throws an exception>>.
If you need to implement more complex TTL logic, you can get the token timestamp
along the payload by calling `branca/decode*`.
as seconds since the Unix epoch along the payload by calling `branca/decode*`.

[source,clojure]
----

M src/clj_branca/core.clj => src/clj_branca/core.clj +8 -3
@@ 19,8 19,13 @@
                      {:type ::invalid-key})))
    key))

(defn- to-ms [timestamp]
  (if (inst? timestamp)
    (quot (inst-ms timestamp) 1000)
    timestamp))

(defn- get-now [options]
  (or (:now options)
  (or (some-> (:now options) (to-ms))
      (quot (System/currentTimeMillis) 1000)))

(defn- ^ByteBuffer get-header


@@ 47,7 52,7 @@

  | key | description |
  | --- | ------------|
  | now | The token timestamp as seconds since the UNIX epoch. Default: system time. |
  | now | The token timestamp as Inst or seconds since the UNIX epoch. Default: system time. |
  "
  ([key payload] (encode key payload nil))
  ([key payload options]


@@ 116,7 121,7 @@

  | key | description |
  | --- | ------------|
  | now | The current time as seconds since the UNIX epoch. Default: system time. |
  | now | The current time as Inst or seconds since the UNIX epoch. Default: system time. |
  | ttl | Token time-to-live in seconds. If set, throws if the token has expired. Default: nil. |
  "
  ([key token] (:payload (decode* key token)))

M test/clj_branca/core_test.clj => test/clj_branca/core_test.clj +14 -6
@@ 4,19 4,27 @@
            [clj-branca.crypto :as crypto]
            [clj-branca.test-utils :refer [decode-base64]]
            [clojure.edn :as edn]
            [clojure.test :refer [deftest is testing]]))
            [clojure.test :refer [deftest is testing]])
  (:import java.time.Instant
           java.util.Date))

(def +key+ "supersecretkeyyoushouldnotcommit")

(deftest roundtrip-test
  (let [roundtrip #(branca/decode +key+ (branca/encode +key+ %))]
    (is (= nil (seq (roundtrip (byte-array 0))))
    (is (= "Hello world!" (String. (roundtrip (.getBytes "Hello world!"))))))))
  (let [encode-decode #(branca/decode +key+ (branca/encode +key+ %))]
    (is (= nil (seq (encode-decode (byte-array 0))))
    (is (= "Hello world!" (String. (encode-decode (.getBytes "Hello world!"))))))))

(deftest options-test
(deftest timestamp-test
  (let [encode-decode #(branca/decode* +key+ (branca/encode +key+ (.getBytes "hello") %))]
    (is (= 1234 (:timestamp (encode-decode {:now 1234}))))
    (is (= 1234 (:timestamp (encode-decode {:now (Date. 1234000)}))))
    (is (= 1234 (:timestamp (encode-decode {:now (Instant/ofEpochSecond 1234)}))))))

(deftest ttl-test
  (let [old-token (branca/encode +key+ (.getBytes "hello") {:now 1234})
        new-token (branca/encode +key+ (.getBytes "hello"))]
    (is (= 1234 (:timestamp (branca/decode* +key+ old-token nil))))
    (is (= "hello" (String. (branca/decode +key+ old-token))))
    (is (thrown-with-msg? clojure.lang.ExceptionInfo #"Expired token" (branca/decode +key+ old-token {:ttl 3600})))
    (is (= "hello" (String. (branca/decode +key+ new-token {:ttl 3600}))))))