Compare commits
4 Commits
v1.0
...
75075b81fb
| Author | SHA1 | Date | |
|---|---|---|---|
| 75075b81fb | |||
| 0e88cddc24 | |||
| 6dc9100b45 | |||
| 1863e82595 |
@@ -2,7 +2,7 @@
|
|||||||
(:require [clojure.tools.build.api :as b]))
|
(:require [clojure.tools.build.api :as b]))
|
||||||
|
|
||||||
(def lib 'es.rcorral/clj-topt)
|
(def lib 'es.rcorral/clj-topt)
|
||||||
(def version (format "1.0.%s" (b/git-count-revs nil)))
|
(def version (format "1.1.%s" (b/git-count-revs nil)))
|
||||||
(def class-dir "target/classes")
|
(def class-dir "target/classes")
|
||||||
(def uber-file (format "target/%s-%s-standalone.jar" (name lib) version))
|
(def uber-file (format "target/%s-%s-standalone.jar" (name lib) version))
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
NATIVE=~/.sdkman/candidates/java/21.0.2-graalce/bin/native-image
|
NATIVE=~/.sdkman/candidates/java/21.0.2-graalce/bin/native-image
|
||||||
UBERJAR=clj-topt-1.0.32-standalone.jar
|
UBERJAR=clj-topt-1.0.38-standalone.jar
|
||||||
BIN_FILE=totp
|
BIN_FILE=totp
|
||||||
|
|
||||||
echo "Creating uberjar"
|
echo "Creating uberjar"
|
||||||
|
|||||||
221
src/totp/app.clj
221
src/totp/app.clj
@@ -3,18 +3,19 @@
|
|||||||
[totp.data :refer :all]
|
[totp.data :refer :all]
|
||||||
[cli-matic.core :refer [run-cmd]]
|
[cli-matic.core :refer [run-cmd]]
|
||||||
[cli-matic.utils :as U]
|
[cli-matic.utils :as U]
|
||||||
[clojure.pprint :as pp])
|
[clojure.pprint :as pp]
|
||||||
|
[clojure.pprint :as pprint])
|
||||||
(:import [java.util TimerTask Timer])
|
(:import [java.util TimerTask Timer])
|
||||||
(:gen-class))
|
(:gen-class))
|
||||||
|
|
||||||
|
|
||||||
(defn- print-confinuous
|
(defn- print-confinuous
|
||||||
([secret] (print-confinuous secret 30))
|
([secret] (print-confinuous secret "sha1" 6 30))
|
||||||
([secret step]
|
([secret algorithm digits period]
|
||||||
(let [step-millis (* 1000 step)
|
(let [step-millis (* 1000 period)
|
||||||
now (System/currentTimeMillis)
|
now (System/currentTimeMillis)
|
||||||
delay (int (- step-millis (rem now step-millis)))
|
delay (int (- step-millis (rem now step-millis)))
|
||||||
fn-show (fn [s] (println (System/currentTimeMillis) "-> "(get-otp s)))
|
fn-show (fn [s] (println (System/currentTimeMillis) "-> "(get-otp s algorithm digits period)))
|
||||||
task (proxy [TimerTask] []
|
task (proxy [TimerTask] []
|
||||||
(run [] (fn-show secret)))]
|
(run [] (fn-show secret)))]
|
||||||
(println "\n <Generating continuosly, press enter to stop>\n")
|
(println "\n <Generating continuosly, press enter to stop>\n")
|
||||||
@@ -29,34 +30,210 @@
|
|||||||
)
|
)
|
||||||
|
|
||||||
(defn cmd-generate
|
(defn cmd-generate
|
||||||
[& {:keys [secret continuous] :as otps}]
|
[& {:keys [secret continuous algorithm digits period] :as opts}]
|
||||||
;(pp/pprint otps)
|
;;(pp/pprint opts)
|
||||||
(if continuous
|
(if continuous
|
||||||
(print-confinuous secret)
|
(print-confinuous secret algorithm digits period)
|
||||||
(println (get-otp secret))
|
(println (get-otp secret algorithm digits period))))
|
||||||
))
|
|
||||||
|
|
||||||
|
(defn cmd-get
|
||||||
|
[& {:keys [name continuous] :as opts}]
|
||||||
|
;;(pp/pprint opts)
|
||||||
|
(if (exists-config)
|
||||||
|
(let [cfg (load-config)
|
||||||
|
app (get-app cfg name)
|
||||||
|
{:keys [secret algorithm digits period]
|
||||||
|
:or {algorithm "sha1"
|
||||||
|
digits 6
|
||||||
|
period 30}} app]
|
||||||
|
(if (some? secret)
|
||||||
|
(if continuous
|
||||||
|
(print-confinuous secret algorithm digits period)
|
||||||
|
(println (get-otp secret algorithm digits period)))
|
||||||
|
(println "The app" name "is not configured")))
|
||||||
|
(println "Config file not found.")))
|
||||||
|
|
||||||
|
|
||||||
|
(defn cmd-config
|
||||||
|
[& {:keys [command] :as opts}]
|
||||||
|
;;(pp/pprint opts)
|
||||||
|
(case command
|
||||||
|
"info" (println "Configuration file: "
|
||||||
|
(if (exists-config)
|
||||||
|
cfg-file
|
||||||
|
(str "<not found. default:" cfg-file ">")))
|
||||||
|
"init" (if (exists-config)
|
||||||
|
(do
|
||||||
|
(println "Configuration already exists, this will delete it. Are you sure? [N/y]")
|
||||||
|
(case (read-line)
|
||||||
|
"y" (create-cfg-file)
|
||||||
|
"Y" (create-cfg-file)
|
||||||
|
(println "Cancelling operation.")))
|
||||||
|
(create-cfg-file))
|
||||||
|
"show" (do
|
||||||
|
(println "Config file:\n")
|
||||||
|
;(println (slurp cfg-file))
|
||||||
|
(pp/print-table (load-config))
|
||||||
|
)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn cmd-list
|
||||||
|
[& {:keys [sorted] :as opts}]
|
||||||
|
;;(pp/pprint opts)
|
||||||
|
(if (exists-config)
|
||||||
|
(let [apps-list (list-apps (load-config))
|
||||||
|
s-list (if sorted (sort apps-list) apps-list)]
|
||||||
|
(dorun (map #(println %) s-list)))
|
||||||
|
(println "Config file not found.")))
|
||||||
|
|
||||||
|
|
||||||
|
(defn cmd-add
|
||||||
|
[& {:keys [name secret user issuer algorithm digits period update] :as opts}]
|
||||||
|
;;(pp/pprint opts)
|
||||||
|
(if (exists-config)
|
||||||
|
(let [cfg (load-config)]
|
||||||
|
(when (or update (nil? (get-app cfg name))) ;; get-app returns nil if app don't exists
|
||||||
|
(store-config (add-app cfg name secret user issuer algorithm digits period))))
|
||||||
|
(println "Config file not found.")))
|
||||||
|
|
||||||
|
|
||||||
|
(defn cmd-delete
|
||||||
|
[& {:keys [name force] :as opts}]
|
||||||
|
;;(pp/pprint opts)
|
||||||
|
(if (exists-config)
|
||||||
|
(let [cfg (load-config)]
|
||||||
|
(when (or force (some? (get-app cfg name)))
|
||||||
|
(store-config (delete-app cfg name))))
|
||||||
|
(println "Config file not found.")))
|
||||||
|
|
||||||
|
|
||||||
(def cli-options
|
(def cli-options
|
||||||
{:app {:command "totp"
|
{:app {:command "totp"
|
||||||
:version "1.0.0"
|
:version "1.1"
|
||||||
:description ["Generate a TOTP"]}
|
:description ["Generate a TOTP"]}
|
||||||
|
|
||||||
:commands [{:command "generate" :short "g"
|
:commands [{:command "generate"
|
||||||
:description "Generate one TOTP with a given secret in BASE32"
|
:description "Generate one TOTP for a BASE32 secret, ignoring configured apps"
|
||||||
:examples ["totp generate \"MJXW42LBORXQ====\""
|
:examples ["Generate one TOTP for a provided BASE32 secret:"
|
||||||
"totp g \"MJXW42LBORXQ====\""]
|
" totp generate ABCD1234"
|
||||||
:opts [{:option "secret"
|
"Generate one TOTP and refresh it continuosly:"
|
||||||
:short 0
|
" totp generate -c ABCD1234"]
|
||||||
:as "Secret codified in BASE32"
|
:opts [{:option "secret" :short 0
|
||||||
|
:as "Secret encoded in BASE32"
|
||||||
:type :string
|
:type :string
|
||||||
:default :present}
|
:default :present}
|
||||||
{:option "continuous"
|
{:option "continuous" :short "c"
|
||||||
:short "c"
|
|
||||||
:type :with-flag
|
|
||||||
:as "Contiuous mode"
|
:as "Contiuous mode"
|
||||||
|
:type :with-flag
|
||||||
|
:default false}
|
||||||
|
{:option "algorithm" :short "a"
|
||||||
|
:as "Algorithm used for the key generation"
|
||||||
|
:type #{"sha1" "sha256" "sha512"}
|
||||||
|
:default "sha1"}
|
||||||
|
{:option "digits" :short "d"
|
||||||
|
:as "Number of digits for OTP. Usually 6 or 8"
|
||||||
|
:type :int
|
||||||
|
:default 6}
|
||||||
|
{:option "period" :short "p"
|
||||||
|
:as "Validity time in seconds"
|
||||||
|
:type :int
|
||||||
|
:default 30}]
|
||||||
|
:runs cmd-generate}
|
||||||
|
|
||||||
|
{:command "get" :short "g"
|
||||||
|
:description "Generate one TOTP for a configured app"
|
||||||
|
:examples ["Generate one TOTP for a provided app:"
|
||||||
|
" totp get app1"
|
||||||
|
"Generate one TOTP and refresh it continuosly:"
|
||||||
|
" totp get -c app1"]
|
||||||
|
:opts [{:option "name" :short 0
|
||||||
|
:as "Name of the previous configured app"
|
||||||
|
:type :string
|
||||||
|
:default :present}
|
||||||
|
{:option "continuous" :short "c"
|
||||||
|
:as "Contiuous mode"
|
||||||
|
:type :with-flag
|
||||||
:default false}]
|
:default false}]
|
||||||
:runs cmd-generate}]})
|
:runs cmd-get}
|
||||||
|
|
||||||
|
{:command "config" :short "c"
|
||||||
|
:description "Manage configuration"
|
||||||
|
:examples ["Show location for the configuration file:"
|
||||||
|
" totp config info"
|
||||||
|
"Recreate config (warning: it will delete the existing config file):"
|
||||||
|
" totp config init"
|
||||||
|
"Show configuration:"
|
||||||
|
" totp config show"]
|
||||||
|
:opts [{:option "command" :short 0
|
||||||
|
:as "Command to execute. See examples"
|
||||||
|
:type #{"info" "init" "show"}
|
||||||
|
:default :present}]
|
||||||
|
:runs cmd-config}
|
||||||
|
|
||||||
|
{:command "list" :short "l"
|
||||||
|
:description "List existing apps"
|
||||||
|
:examples ["List apps:"
|
||||||
|
" totp list"
|
||||||
|
"List apps sorted by name:"
|
||||||
|
" totp list --sorted"]
|
||||||
|
:opts [{:option "sorted" :short "s"
|
||||||
|
:as "If provided, the list willl be sorted by name"
|
||||||
|
:type :with-flag
|
||||||
|
:default false}]
|
||||||
|
:runs cmd-list}
|
||||||
|
|
||||||
|
{:command "add" :short "a"
|
||||||
|
:description "Add a new application with an unique name"
|
||||||
|
:examples ["Add a new application named 'app1' with a BASE32 secred, with defaults:"
|
||||||
|
" totp add app1 \"MJXW42LBORXQ====\""
|
||||||
|
"Add an application, with all posible configuration params:"
|
||||||
|
" topt add app2 \"MJXW42LBORXQ====\" -u \"user1@server\" -i my_provider -a sha1 -d 6 -p 30 --update"]
|
||||||
|
:opts [{:option "name" :short 0
|
||||||
|
:as "Unique name (alias) for the application"
|
||||||
|
:type :string
|
||||||
|
:default :present}
|
||||||
|
{:option "secret" :short 1
|
||||||
|
:as "Secret encoded in BASE32"
|
||||||
|
:type :string
|
||||||
|
:default :present}
|
||||||
|
{:option "user" :short "u"
|
||||||
|
:as "Username in the format <user>@<server>"
|
||||||
|
:type :string}
|
||||||
|
{:option "issuer" :short "i"
|
||||||
|
:as "The issuer (provider) of the service"
|
||||||
|
:type :string}
|
||||||
|
{:option "algorithm" :short "a"
|
||||||
|
:as "Algorithm used for the key generation"
|
||||||
|
:type #{"sha1" "sha256" "sha512"}
|
||||||
|
:default "sha1"}
|
||||||
|
{:option "digits" :short "d"
|
||||||
|
:as "Number of digits for OTP. Usually 6 or 8"
|
||||||
|
:type :int
|
||||||
|
:default 6}
|
||||||
|
{:option "period" :short "p"
|
||||||
|
:as "Validity time in seconds"
|
||||||
|
:type :int
|
||||||
|
:default 30}
|
||||||
|
{:option "update"
|
||||||
|
:as "Update an app with the same name if exists"
|
||||||
|
:type :with-flag
|
||||||
|
:default false}]
|
||||||
|
:runs cmd-add}
|
||||||
|
|
||||||
|
{:command "delete" :short "d"
|
||||||
|
:description "Removes an existing application by it's unique name"
|
||||||
|
:examples ["Remove the application name app1"
|
||||||
|
" totp remove app1"]
|
||||||
|
:opts [{:option "name" :short 0
|
||||||
|
:as "Unique name of the application"
|
||||||
|
:type :string
|
||||||
|
:default :present}
|
||||||
|
{:option "force" :short "f"
|
||||||
|
:as "Don't ask, just remove"
|
||||||
|
:type :with-flag
|
||||||
|
:default false}]
|
||||||
|
:runs cmd-delete}]})
|
||||||
|
|
||||||
|
|
||||||
(defn -main [& args]
|
(defn -main [& args]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
(ns totp.core
|
(ns totp.core
|
||||||
(:require [alphabase.base32 :as b32])
|
(:require [alphabase.base32 :as b32]
|
||||||
|
[clojure.math :as m])
|
||||||
(:import (javax.crypto Mac)
|
(:import (javax.crypto Mac)
|
||||||
(javax.crypto.spec SecretKeySpec)
|
(javax.crypto.spec SecretKeySpec)
|
||||||
(java.util Base64 Arrays)
|
(java.util Base64 Arrays)
|
||||||
@@ -21,32 +22,42 @@
|
|||||||
(= byte-array-type (type x)))
|
(= byte-array-type (type x)))
|
||||||
|
|
||||||
|
|
||||||
(defmulti hmac-sha1
|
(defn get-alg
|
||||||
"Generates an HMAC-SHA1. The key and the message can be (both) string or array of bytes, nil otherwise"
|
[alg]
|
||||||
(fn [key message]
|
(case alg
|
||||||
|
"sha1" "HmacSHA1"
|
||||||
|
"sha256" "HmacSHA256"
|
||||||
|
"sha512" "HmacSHA512"
|
||||||
|
""))
|
||||||
|
|
||||||
|
|
||||||
|
(defmulti hmac
|
||||||
|
"Generates an HMAC. Algorithms supported: sha1, sha256, sha512.
|
||||||
|
The key and the message can be (both) string or array of bytes, nil otherwise"
|
||||||
|
(fn [algorithm key message]
|
||||||
(cond
|
(cond
|
||||||
(and (string? key) (string? message)) :string
|
(and (string? key) (string? message) (some? (get-alg algorithm))) :string
|
||||||
(and (bytes-array? key) (bytes-array? message)) :byte
|
(and (bytes-array? key) (bytes-array? message) (some? (get-alg algorithm))) :byte
|
||||||
:else :nil)))
|
:else :nil)))
|
||||||
|
|
||||||
;; By default
|
;; By default
|
||||||
(defmethod hmac-sha1 :nil [_ _]
|
(defmethod hmac :nil [_ _ _]
|
||||||
nil)
|
nil)
|
||||||
|
|
||||||
;; When key and message are strings
|
;; When key and message are strings
|
||||||
(defmethod hmac-sha1 :string [key message]
|
(defmethod hmac :string [algorithm key message]
|
||||||
(if (or (empty? key) (empty? message))
|
(if (or (empty? key) (empty? message))
|
||||||
""
|
""
|
||||||
(let [mac (doto (Mac/getInstance "HmacSHA1") (.init (SecretKeySpec. (.getBytes key) "HmacSHA1")))
|
(let [mac (doto (Mac/getInstance (get-alg algorithm)) (.init (SecretKeySpec. (.getBytes key) (get-alg algorithm))))
|
||||||
hmac-bytes (.doFinal mac (.getBytes message))]
|
hmac-bytes (.doFinal mac (.getBytes message))]
|
||||||
;; Return the Base64 encoded HMAC
|
;; Return the Base64 encoded HMAC
|
||||||
(.encodeToString (Base64/getEncoder) hmac-bytes))))
|
(.encodeToString (Base64/getEncoder) hmac-bytes))))
|
||||||
|
|
||||||
;; When key and message are arrays of bytes
|
;; When key and message are arrays of bytes
|
||||||
(defmethod hmac-sha1 :byte [key message]
|
(defmethod hmac :byte [algorithm key message]
|
||||||
(if (nil? message)
|
(if (nil? message)
|
||||||
(bytes (byte-array 0))
|
(bytes (byte-array 0))
|
||||||
(let [mac (doto (Mac/getInstance "HmacSHA1") (.init (SecretKeySpec. key "HmacSHA1")))
|
(let [mac (doto (Mac/getInstance (get-alg algorithm)) (.init (SecretKeySpec. key (get-alg algorithm))))
|
||||||
hmac-bytes (.doFinal mac message)]
|
hmac-bytes (.doFinal mac message)]
|
||||||
;; Return the Base64 encoded HMAC
|
;; Return the Base64 encoded HMAC
|
||||||
(Base64/getEncoder) hmac-bytes)))
|
(Base64/getEncoder) hmac-bytes)))
|
||||||
@@ -72,17 +83,19 @@
|
|||||||
|
|
||||||
(defn get-otp
|
(defn get-otp
|
||||||
"Generate an OTP with the given secret (in base32) for the specified timestep"
|
"Generate an OTP with the given secret (in base32) for the specified timestep"
|
||||||
([secret step]
|
([secret algorithm digits period] ;;algorithm digits period
|
||||||
(when (and secret step)
|
(when (and secret period)
|
||||||
(let [k (b32/decode secret)
|
(let [step (timestamp->steps (System/currentTimeMillis) period)
|
||||||
|
k (b32/decode secret)
|
||||||
c (long->bytes step)
|
c (long->bytes step)
|
||||||
hs (hmac-sha1 k c)
|
hs (hmac algorithm k c)
|
||||||
offset (bit-and (get hs (dec (count hs))) 0x0f) ;; int offset = hs[hs.length-1] & 0xf;
|
offset (bit-and (get hs (dec (count hs))) 0x0f) ;; int offset = hs[hs.length-1] & 0xf;
|
||||||
chunk (Arrays/copyOfRange hs offset (+ offset 4)) ;(take 4 (drop offset hs)) ;; byte[] chunk = Arrays.copyOfRange(hs, offset, offset+4)
|
chunk (Arrays/copyOfRange hs offset (+ offset 4)) ;(take 4 (drop offset hs)) ;; byte[] chunk = Arrays.copyOfRange(hs, offset, offset+4)
|
||||||
]
|
]
|
||||||
(format "%06d" (-> chunk
|
(format (str "%0" digits "d")
|
||||||
(bytes->int)
|
(-> chunk
|
||||||
(bit-and 0x7fffffff)
|
(bytes->int)
|
||||||
(rem 1000000))))))
|
(bit-and 0x7fffffff)
|
||||||
|
(rem (int (m/pow 10 digits))))))))
|
||||||
([secret]
|
([secret]
|
||||||
(get-otp secret (timestamp->steps (System/currentTimeMillis) 30))))
|
(get-otp secret "sha1" 6 30)))
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
(defn join-path
|
(defn join-path
|
||||||
"Joins several subpaths using system's path separator (/ un *NIX and \\ in windows)"
|
"Joins several subpaths using system's path separator (/ un *NIX and \\ in windows)"
|
||||||
[& col]
|
[& col]
|
||||||
(str/join java.io.File/separator col))
|
(str/join java.io.File/separator col))
|
||||||
|
|
||||||
|
|
||||||
@@ -47,8 +47,7 @@
|
|||||||
|
|
||||||
(comment
|
(comment
|
||||||
(exists-config)
|
(exists-config)
|
||||||
(create-cfg?)
|
(create-cfg?))
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
(defn load-config
|
(defn load-config
|
||||||
@@ -61,9 +60,9 @@
|
|||||||
"Store configuration to file"
|
"Store configuration to file"
|
||||||
[cfg]
|
[cfg]
|
||||||
(when cfg
|
(when cfg
|
||||||
(spit cfg-file (str cfg-header (with-out-str
|
(spit cfg-file (str cfg-header (with-out-str
|
||||||
(binding [pp/*print-right-margin* 50]
|
(binding [pp/*print-right-margin* 50]
|
||||||
(pp/pprint cfg)))))))
|
(pp/pprint cfg)))))))
|
||||||
|
|
||||||
|
|
||||||
(defn delete-app
|
(defn delete-app
|
||||||
@@ -72,14 +71,18 @@
|
|||||||
|
|
||||||
|
|
||||||
(defn add-app
|
(defn add-app
|
||||||
[cfg name secret]
|
([cfg name secret] (add-app cfg name secret nil nil "sha1" 6 30))
|
||||||
(conj (delete-app cfg name) {:name name :secret secret}))
|
([cfg name secret user issuer algorithm digits period]
|
||||||
|
(conj (delete-app cfg name) {:name name :secret secret :user user :issuer issuer :algorithm algorithm :digits digits :period period})))
|
||||||
|
|
||||||
|
|
||||||
(defn list-apps
|
(defn list-apps
|
||||||
[cfg]
|
[cfg]
|
||||||
(map :name cfg))
|
(map :name
|
||||||
|
(filter #(contains? % :name) cfg)))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(list-apps (load-config)))
|
||||||
|
|
||||||
(defn get-app
|
(defn get-app
|
||||||
[cfg name]
|
[cfg name]
|
||||||
@@ -91,16 +94,16 @@
|
|||||||
(create-cfg?)
|
(create-cfg?)
|
||||||
(load-config)
|
(load-config)
|
||||||
|
|
||||||
|
(get-app [{:name "abc" :secret "def"} {:name "my-app" :secret "abc123"} {:name "another app" :secret "ABCDEF1234"}] "my-app2")
|
||||||
|
|
||||||
(with-out-str
|
(with-out-str
|
||||||
(binding [pp/*print-right-margin* 50]
|
(binding [pp/*print-right-margin* 50]
|
||||||
(pp/pprint [{:name "abc" :secret "def"} {:name "my-app" :secret "abc123"}])))
|
(pp/pprint [{:name "abc" :secret "def"} {:name "my-app" :secret "abc123"}])))
|
||||||
|
|
||||||
(store-config [{:name "abc" :secret "def"} {:name "my-app" :secret "abc123"}])
|
(store-config [{:name "abc" :secret "def"} {:name "my-app" :secret "abc123"} {:name "another app" :secret "ABCDEF1234"}])
|
||||||
|
|
||||||
(-> nil
|
(-> nil
|
||||||
(add-app "app1" "abc123abc123")
|
(add-app "app1" "abc123abc123")
|
||||||
(add-app "app2" "abc123abc123")
|
(add-app "app2" "abc123abc123")
|
||||||
(add-app "app1" "123456789012")
|
(add-app "app1" "123456789012")
|
||||||
(store-config))
|
(store-config)))
|
||||||
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -25,21 +25,21 @@
|
|||||||
(is (= true (bytes-array? (.getBytes ""))))
|
(is (= true (bytes-array? (.getBytes ""))))
|
||||||
(is (= true (bytes-array? (bytes (byte-array [0 0 0 0 0 0 0 0])))))))
|
(is (= true (bytes-array? (bytes (byte-array [0 0 0 0 0 0 0 0])))))))
|
||||||
|
|
||||||
(deftest hmac-sha1-test
|
(deftest hmac-test
|
||||||
(testing "border cases"
|
(testing "border cases"
|
||||||
(is (= nil (hmac-sha1 nil nil)))
|
(is (= nil (hmac nil nil nil)))
|
||||||
(is (= nil (hmac-sha1 "" nil)))
|
(is (= nil (hmac nil "" nil)))
|
||||||
(is (= nil (hmac-sha1 nil "")))
|
(is (= nil (hmac nil nil "")))
|
||||||
(is (= nil (hmac-sha1 (.getBytes "") nil)))
|
(is (= nil (hmac nil (.getBytes "") nil)))
|
||||||
(is (= nil (hmac-sha1 nil (.getBytes ""))))
|
(is (= nil (hmac nil nil (.getBytes ""))))
|
||||||
(is (= "" (hmac-sha1 "" ""))))
|
(is (= "" (hmac "" "" ""))))
|
||||||
(testing "String params"
|
(testing "String params"
|
||||||
(is (= "63h3K4sN+c3NDEl3EGeA23jq/EY=" (hmac-sha1 "12345" "this is a message")))
|
(is (= "63h3K4sN+c3NDEl3EGeA23jq/EY=" (hmac "sha1" "12345" "this is a message")))
|
||||||
(is (= "MA+ieo7t7MeQfyZR/X52dB1aXDI=" (hmac-sha1 "12345" "this is a longer message
|
(is (= "MA+ieo7t7MeQfyZR/X52dB1aXDI=" (hmac "sha1" "12345" "this is a longer message
|
||||||
with some lines"))))
|
with some lines"))))
|
||||||
(testing "byte[] params"
|
(testing "byte[] params"
|
||||||
(is (Arrays/equals (b64/decode "63h3K4sN+c3NDEl3EGeA23jq/EY=") (hmac-sha1 (.getBytes "12345") (.getBytes "this is a message"))))
|
(is (Arrays/equals (b64/decode "63h3K4sN+c3NDEl3EGeA23jq/EY=") (hmac "sha1" (.getBytes "12345") (.getBytes "this is a message"))))
|
||||||
(is (Arrays/equals (b64/decode "MA+ieo7t7MeQfyZR/X52dB1aXDI=") (hmac-sha1 (.getBytes "12345") (.getBytes "this is a longer message
|
(is (Arrays/equals (b64/decode "MA+ieo7t7MeQfyZR/X52dB1aXDI=") (hmac "sha1" (.getBytes "12345") (.getBytes "this is a longer message
|
||||||
with some lines"))))))
|
with some lines"))))))
|
||||||
|
|
||||||
|
|
||||||
@@ -62,10 +62,10 @@
|
|||||||
|
|
||||||
(deftest get-otp-test
|
(deftest get-otp-test
|
||||||
(testing "Border cases"
|
(testing "Border cases"
|
||||||
(is (nil? (get-otp nil nil)))
|
(is (nil? (get-otp nil nil nil nil)))
|
||||||
(is (nil? (get-otp "" nil)))
|
(is (nil? (get-otp "" nil nil nil)))
|
||||||
(is (nil? (get-otp nil "")))
|
(is (nil? (get-otp nil "" nil nil)))
|
||||||
(is (nil? (get-otp nil 1000))))
|
(is (nil? (get-otp nil 1000 nil nil))))
|
||||||
(testing "Common usage"
|
(testing "Common usage"
|
||||||
(is (= "837552" (get-otp "MJXW42LBORXQ====" 10000)))
|
(is (= 6 (count (get-otp "MJXW42LBORXQ====" "sha1" 6 10000))))
|
||||||
(is (= 6 (count (get-otp "MJXW42LBORXQ===="))))))
|
(is (= 6 (count (get-otp "MJXW42LBORXQ===="))))))
|
||||||
Reference in New Issue
Block a user