Compare commits
19 Commits
v1.1
...
017291f784
| Author | SHA1 | Date | |
|---|---|---|---|
| 017291f784 | |||
| 17a7a09ab0 | |||
| 3a6fd107c0 | |||
| 4c31950a88 | |||
| aa71cb1d76 | |||
| c746675045 | |||
| 4052995ba8 | |||
| 44f48fced8 | |||
| c78e89a94b | |||
| 01842dbc8d | |||
| cec35fc16b | |||
| e5fb6e7231 | |||
| 6c017b3262 | |||
| 2e64c26a0a | |||
| c8b9556bcd | |||
| 5c93f4e570 | |||
| dfc3d4e579 | |||
| e7b2683d2c | |||
| 3dd79af7de |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,5 +1,5 @@
|
|||||||
/.clj-kondo/
|
/.clj-kondo/
|
||||||
/.cpcache/
|
/**/.cpcache/
|
||||||
/.lsp/
|
/.lsp/
|
||||||
/target/
|
/target/
|
||||||
.nrepl-port
|
.nrepl-port
|
||||||
|
|||||||
18
README.md
18
README.md
@@ -17,6 +17,8 @@ You can read more about the algorithm here:
|
|||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
First, you must have installed a Java Runtime Environment. Check https://adoptium.net/es if you are
|
First, you must have installed a Java Runtime Environment. Check https://adoptium.net/es if you are
|
||||||
unsure how to install.
|
unsure how to install.
|
||||||
|
|
||||||
@@ -145,11 +147,17 @@ clj-totp.sh import <alias> "<url>"
|
|||||||
- [x] Show several OTPs at once
|
- [x] Show several OTPs at once
|
||||||
|
|
||||||
### v1.2
|
### v1.2
|
||||||
|
- [x] Show progress bar
|
||||||
|
- [x] Styles for progress bar
|
||||||
|
- [x] Native compilation script corrections
|
||||||
|
|
||||||
|
### v2
|
||||||
|
- [x] Restructurate as a multiproject
|
||||||
- [ ] REST API
|
- [ ] REST API
|
||||||
- [ ] User management
|
- [ ] User management
|
||||||
- [ ] Robust BD backend (H2, datomic, or similar)
|
- [ ] Robust BD backend (H2, datomic, or similar)
|
||||||
|
|
||||||
### v1.3
|
### v3
|
||||||
- [ ] Simple web connected to REST API
|
- [ ] Simple web connected to REST API
|
||||||
|
|
||||||
|
|
||||||
@@ -169,14 +177,14 @@ The first step is to install Java JDK, version 11 or newer (version 21 recommend
|
|||||||
|
|
||||||
To execute manually the main function, simple use the `:run` alias:
|
To execute manually the main function, simple use the `:run` alias:
|
||||||
|
|
||||||
```clojure
|
```bash
|
||||||
clojure -M:run <commands and parameters>
|
clojure -M:run/cli <commands and parameters>
|
||||||
```
|
```
|
||||||
|
|
||||||
To build the uberjar:
|
To build the uberjar:
|
||||||
|
|
||||||
```clojure
|
```bash
|
||||||
clojure -T:build uber
|
clojure -T:build :uber/cli
|
||||||
```
|
```
|
||||||
|
|
||||||
There is a utility script to build a native executable using Graal VM. Please, edit the script and
|
There is a utility script to build a native executable using Graal VM. Please, edit the script and
|
||||||
|
|||||||
191
build.clj
191
build.clj
@@ -1,37 +1,174 @@
|
|||||||
(ns build
|
(ns build
|
||||||
(:require [clojure.tools.build.api :as b]))
|
(:refer-clojure :exclude [test])
|
||||||
|
(:require [clojure.tools.build.api :as b]
|
||||||
|
[clojure.java.io :as io]
|
||||||
|
[clojure.pprint :as pp]
|
||||||
|
[clojure.java.basis :as basis]))
|
||||||
|
|
||||||
(def lib 'es.rcorral/clj-totp)
|
(def lib-group "es.rcorral")
|
||||||
(def version (format "1.1.%s" (b/git-count-revs nil)))
|
(def artifact-prefix "clj-totp")
|
||||||
(def target-dir "target")
|
(def subprojs-base "projects")
|
||||||
(def class-dir (str target-dir "/classes"))
|
(def curr-version (format "2.0.%s" (b/git-count-revs nil)))
|
||||||
(def uber-file (format "target/%s-%s-standalone.jar" (name lib) version))
|
|
||||||
|
|
||||||
;; delay to defer side effects (artifact downloads)
|
|
||||||
(def basis (delay (b/create-basis {:project "deps.edn"})))
|
|
||||||
|
|
||||||
(defn clean [_]
|
|
||||||
(b/delete {:path "target"}))
|
|
||||||
|
|
||||||
(defn compile-java [_]
|
|
||||||
(b/javac {:src-dirs ["java"]
|
|
||||||
:class-dir class-dir
|
|
||||||
:basis @basis
|
|
||||||
:javac-opts ["-source" "11" "--target" "11" "-proc:none"]}))
|
|
||||||
|
|
||||||
|
|
||||||
|
;; Builds artifact's full descriptor for each subproject
|
||||||
|
(defn lib [subproj]
|
||||||
|
(symbol (str lib-group "/" artifact-prefix "-" subproj )))
|
||||||
|
|
||||||
|
|
||||||
|
;; Basis for each subproject, using their own deps.edn
|
||||||
|
;; Injects :extra-deps from :build as additional dependencies
|
||||||
|
(defn basis [subproj]
|
||||||
|
(delay (b/create-basis {:project (str subprojs-base "/" subproj "/deps.edn")
|
||||||
|
;; Inject extra deps as deps
|
||||||
|
:extra {:deps (get-in (basis/initial-basis) [:aliases :build :extra-deps])}
|
||||||
|
})))
|
||||||
|
|
||||||
|
|
||||||
|
;; Show basis generated for a subproject
|
||||||
#_{:clojure-lsp/ignore [:clojure-lsp/unused-public-var]}
|
#_{:clojure-lsp/ignore [:clojure-lsp/unused-public-var]}
|
||||||
(defn uber [_]
|
(defn show-basis [subproj]
|
||||||
(clean nil)
|
(println (with-out-str
|
||||||
(b/copy-dir {:src-dirs ["src"]
|
(pp/pprint
|
||||||
|
@(basis subproj)
|
||||||
|
;(basis/initial-basis)
|
||||||
|
))))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(pp/pprint (keys (basis/initial-basis)))
|
||||||
|
(pp/pprint (:deps (basis/initial-basis)))
|
||||||
|
(pp/pprint (:libs (basis/initial-basis)))
|
||||||
|
(pp/pprint (sort (keys (:aliases (basis/initial-basis)))))
|
||||||
|
(get-in (basis/initial-basis) [:aliases :build :extra-deps])
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Target dir for each subproject
|
||||||
|
(defn target-dir [subproj]
|
||||||
|
(str "target/" subproj))
|
||||||
|
|
||||||
|
|
||||||
|
;; Path for compiled classes
|
||||||
|
(defn class-dir [subproj]
|
||||||
|
(str (target-dir subproj) "/" "classes"))
|
||||||
|
|
||||||
|
|
||||||
|
;; Jar file for each subproject. :uber type adds -standalone suffix
|
||||||
|
(defn jar-file [subproj version type]
|
||||||
|
(format "target/%s-%s-%s%s.jar" artifact-prefix subproj version
|
||||||
|
(if (= type :uber) "-standalone" "")))
|
||||||
|
|
||||||
|
|
||||||
|
;; Clean target dir for subproject
|
||||||
|
(defn clean [{:keys [subproj]}]
|
||||||
|
(b/delete {:path (target-dir subproj)})
|
||||||
|
(println "Project" subproj "cleaned"))
|
||||||
|
|
||||||
|
|
||||||
|
;; Compile java classes, only if java subdir exists
|
||||||
|
(defn compile-java [subproj]
|
||||||
|
(let [java-dir (str subprojs-base "/" subproj "/java")]
|
||||||
|
(when (.exists (io/file java-dir))
|
||||||
|
(println "Compiling java code for" subproj)
|
||||||
|
(b/javac {:src-dirs [java-dir]
|
||||||
|
:class-dir (class-dir subproj)
|
||||||
|
:basis @(basis subproj)
|
||||||
|
:javac-opts ["-source" "11" "--target" "11" "-proc:none"]}))))
|
||||||
|
|
||||||
|
|
||||||
|
;; Create a jar file
|
||||||
|
(defn jar
|
||||||
|
"Build a simple jar file, with no dependencies included."
|
||||||
|
[{:keys [subproj version]
|
||||||
|
:or {version curr-version}}]
|
||||||
|
(let [target-dir (target-dir subproj)
|
||||||
|
class-dir (class-dir subproj)
|
||||||
|
src-dir (str subprojs-base "/" subproj "/src")
|
||||||
|
resources-dir (str subprojs-base "/" subproj "/resources")
|
||||||
|
basis (basis subproj)
|
||||||
|
jar-file (jar-file subproj version :plain)]
|
||||||
|
;; Clean only class dir
|
||||||
|
(b/delete {:path class-dir})
|
||||||
|
;; Copy code
|
||||||
|
(b/copy-dir {:src-dirs [src-dir]
|
||||||
:target-dir class-dir})
|
:target-dir class-dir})
|
||||||
(b/copy-file {:src "resources/clj-totp.sh"
|
;; Copy resources
|
||||||
:target "target/clj-totp.sh"})
|
(b/copy-dir {:src-dirs [resources-dir]
|
||||||
(compile-java nil)
|
:target-dir target-dir})
|
||||||
|
;; Compile java code, if exists
|
||||||
|
(compile-java subproj)
|
||||||
|
;; Build jar
|
||||||
|
(b/jar {:class-dir class-dir
|
||||||
|
:basis @basis
|
||||||
|
:jar-file jar-file
|
||||||
|
:lib (lib subproj)
|
||||||
|
:version version})
|
||||||
|
(println "Generated jar file:" jar-file)))
|
||||||
|
|
||||||
|
|
||||||
|
;; Create an uber jar, with all dependencies inside
|
||||||
|
#_{:clojure-lsp/ignore [:clojure-lsp/unused-public-var]}
|
||||||
|
(defn uber
|
||||||
|
"Build a uberjar with all dependencies included"
|
||||||
|
[{:keys [subproj version main-ns]
|
||||||
|
:or {version curr-version}}]
|
||||||
|
(let [target-dir (target-dir subproj)
|
||||||
|
basis (basis subproj)
|
||||||
|
class-dir (class-dir subproj)
|
||||||
|
src-dir (str subprojs-base "/" subproj "/src")
|
||||||
|
resources-dir (str subprojs-base "/" subproj "/resources")
|
||||||
|
uber-file (jar-file subproj version :uber)]
|
||||||
|
;(println "Using basis: ")(show-basis subproj)
|
||||||
|
(b/delete {:path class-dir})
|
||||||
|
(b/copy-dir {:src-dirs [src-dir]
|
||||||
|
:target-dir class-dir})
|
||||||
|
(b/copy-dir {:src-dirs [resources-dir]
|
||||||
|
:target-dir target-dir})
|
||||||
|
(compile-java subproj)
|
||||||
(b/compile-clj {:basis @basis
|
(b/compile-clj {:basis @basis
|
||||||
:ns-compile '[totp.app]
|
:src-dirs [src-dir] :class-dir class-dir})
|
||||||
:class-dir class-dir})
|
|
||||||
(b/uber {:class-dir class-dir
|
(b/uber {:class-dir class-dir
|
||||||
:uber-file uber-file
|
:uber-file uber-file
|
||||||
:basis @basis
|
:basis @basis
|
||||||
:main 'totp.app}))
|
:main main-ns})
|
||||||
|
(println "Generated uberjar executable:" uber-file)))
|
||||||
|
|
||||||
|
|
||||||
|
;; Multimethod to get the name of all subdirs in a dir.
|
||||||
|
;; Accepts strings or files
|
||||||
|
(defmulti get-subdirs type)
|
||||||
|
|
||||||
|
(defmethod get-subdirs
|
||||||
|
java.lang.String [dir]
|
||||||
|
(get-subdirs (io/file dir)))
|
||||||
|
|
||||||
|
(defmethod get-subdirs
|
||||||
|
java.io.File [dir]
|
||||||
|
(if (.isDirectory dir)
|
||||||
|
(filter #(.isDirectory %) (.listFiles dir))
|
||||||
|
(println "Directory" subprojs-base "doesn't exists!")))
|
||||||
|
|
||||||
|
|
||||||
|
;; Get the name of all subdir in a given directory
|
||||||
|
(defn get-subdir-names
|
||||||
|
"Get a list projects in the 'projects' directory"
|
||||||
|
[dir-name]
|
||||||
|
(map #(.getName %) (get-subdirs dir-name)))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(get-subdirs "projects")
|
||||||
|
(get-subdirs (io/file "projects"))
|
||||||
|
(get-subdir-names "projects")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
;; Generate jar files for all projects
|
||||||
|
(defn jar-all
|
||||||
|
"Build jar files for all projects"
|
||||||
|
[& {:keys [version]
|
||||||
|
:or {version curr-version}}]
|
||||||
|
(dorun (map #(jar {:subproj % :version version}) (get-subdir-names subprojs-base))))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(jar-all )
|
||||||
|
|
||||||
|
)
|
||||||
42
clj-totp.iml
42
clj-totp.iml
@@ -1,42 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="JAVA_MODULE" version="4">
|
|
||||||
<component name="BuildSystem">
|
|
||||||
<option name="buildSystemId" value="CLOJURE_DEPS" />
|
|
||||||
<option name="displayName" value="clj-totp" />
|
|
||||||
</component>
|
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
|
||||||
<exclude-output />
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
<orderEntry type="library" name="Deps: org.clojure/clojure:1.12.1" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: lambdaisland/deep-diff2:2.11.216" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: org.clojure/core.specs.alpha:0.4.74" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: lambdaisland/kaocha:1.91.1392" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: expound:0.9.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: org.clojure/spec.alpha:0.5.238" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: org.clojure/tools.cli:1.1.230" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: lambdaisland/clj-diff:1.4.78" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: net.incongru.watchservice/barbary-watchservice:1.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: slingshot:0.12.2" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: fipp:0.6.26" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: com.nextjournal/beholder:1.0.2" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: aero:1.1.6" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: lambdaisland/tools.namespace:0.3.256" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: mvxcvi/arrangement:2.1.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: io.methvin/directory-watcher:0.17.3" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: progrock:0.1.2" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: org.clojure/java.classpath:1.0.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: clojure.java-time:1.4.3" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: org.clojure/core.rrb-vector:0.1.2" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: net.java.dev.jna/jna:5.12.1" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: org.clojure/tools.reader:1.3.6" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: org.tcrawley/dynapath:1.1.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: org.slf4j/slf4j-api:1.7.36" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: hawk:0.2.11" level="project" />
|
|
||||||
<orderEntry type="library" name="Deps: meta-merge:1.0.0" level="project" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
||||||
65
deps.edn
65
deps.edn
@@ -1,27 +1,60 @@
|
|||||||
{:paths ["src" "resources" "target/classes"]
|
{:paths ["src" "resources" "target/classes"]
|
||||||
:deps {org.clojure/clojure {:mvn/version "1.12.1"}
|
:deps {org.clojure/clojure {:mvn/version "1.12.1"}
|
||||||
io.github.clojure/tools.build {:mvn/version "0.10.10"}
|
;; Native image (GraalVM). Tutorial: https://shagunagrawal.me/posts/setup-clojure-with-graalvm-for-native-image/
|
||||||
mvxcvi/alphabase {:mvn/version "3.0.185"} ;; https://github.com/greglook/alphabase
|
com.github.clj-easy/graal-build-time {:mvn/version "1.0.5"}
|
||||||
cli-matic/cli-matic {:mvn/version "0.5.4"} ;; https://github.com/l3nz/cli-matic
|
;; Local subprojects
|
||||||
;; For SQLite
|
clj-totp/core {:local/root "projects/core"}
|
||||||
com.github.seancorfield/next.jdbc {:mvn/version "1.3.1048"}
|
clj-totp/cli {:local/root "projects/cli"}
|
||||||
org.xerial/sqlite-jdbc {:mvn/version "3.50.3.0"}
|
clj-totp/web {:local/root "projects/web"}
|
||||||
;; For Datomic local
|
}
|
||||||
com.datomic/local {:mvn/version "1.0.291"};; https://docs.datomic.com/datomic-local.html
|
|
||||||
;; Native image (GraalVM)
|
|
||||||
com.github.clj-easy/graal-build-time {:mvn/version "1.0.5"};; Tutorial: https://shagunagrawal.me/posts/setup-clojure-with-graalvm-for-native-image/
|
|
||||||
;; Protobuf for java
|
|
||||||
com.google.protobuf/protobuf-java {:mvn/version "3.25.8"}}
|
|
||||||
|
|
||||||
:aliases {;; Execute the app
|
:aliases {;; Execute the app.
|
||||||
:run {:main-opts ["-m" "totp.app"]}
|
:run {:main-opts ["-m" "totp.app"]}
|
||||||
|
;:run {:exec-fn totp.app/-main}
|
||||||
|
|
||||||
|
;; Execute the app (prepared for more subprojects)
|
||||||
|
:run/cli {:main-opts ["-m" "totp.app"]}
|
||||||
|
;:run {:exec-fn totp.app/-main}
|
||||||
|
|
||||||
;; Kaocha runner. You can use the 'kaocha' wrapper located in ~/bin/kaocha
|
;; Kaocha runner. You can use the 'kaocha' wrapper located in ~/bin/kaocha
|
||||||
:test {:extra-paths ["test"]
|
;; Check test.edn for kaocha runner's config
|
||||||
:extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}}
|
:test {:extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}
|
||||||
|
lambdaisland/kaocha-cloverage {:mvn/version "1.1.89"}}
|
||||||
:main-opts ["-m" "kaocha.runner"]}
|
:main-opts ["-m" "kaocha.runner"]}
|
||||||
|
|
||||||
;; Run with clj -T:build function-in-build
|
;; Run with clj -T:build function-in-build
|
||||||
:build {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
|
:build {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
|
||||||
:ns-default build}}}
|
;; Used by all compilations
|
||||||
|
:extra-deps {clj-totp/core {:local/root "projects/core"}}
|
||||||
|
:ns-default build}
|
||||||
|
|
||||||
|
;; Aliases for easy building
|
||||||
|
:build/core {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
|
||||||
|
:ns-default build
|
||||||
|
:exec-fn jar
|
||||||
|
:exec-args {:subproj "core"}}
|
||||||
|
|
||||||
|
:build/cli {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}
|
||||||
|
clj-totp/core {:local/root "projects/core"}}
|
||||||
|
:ns-default build
|
||||||
|
:exec-fn jar
|
||||||
|
:exec-args {:subproj "cli"}}
|
||||||
|
|
||||||
|
:build/web {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
|
||||||
|
:replace-deps {clj-totp/core {:local/root "projects/core"}}
|
||||||
|
:ns-default build
|
||||||
|
:exec-fn jar
|
||||||
|
:exec-args {:subproj "web"}}
|
||||||
|
|
||||||
|
;; Build the three libraries
|
||||||
|
:build/all {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
|
||||||
|
:replace-deps {clj-totp/core {:local/root "projects/core"}}
|
||||||
|
:ns-default build
|
||||||
|
:exec-fn jar-all}
|
||||||
|
|
||||||
|
;; Build uber jar for CLI app
|
||||||
|
:uber/cli {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
|
||||||
|
:ns-default build
|
||||||
|
:exec-fn uber
|
||||||
|
:exec-args {:subproj "cli" :main-ns "totp.app"}}}}
|
||||||
|
|
||||||
|
|||||||
33
native.cmd
Normal file
33
native.cmd
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
@echo off
|
||||||
|
|
||||||
|
setlocal
|
||||||
|
|
||||||
|
REM YOUR LOCAL GRAAL VM INSTALLATION
|
||||||
|
set JAVA_HOME=D:\programas\graalvm-jdk-21.0.7+8.1
|
||||||
|
REM generated file
|
||||||
|
set BIN_FILE=totp
|
||||||
|
|
||||||
|
set DEST_DIR=C:\Users\rubencj\util
|
||||||
|
|
||||||
|
set PATH=%JAVA_HOME%\bin;%CLOJURE_HOME%;%PATH%
|
||||||
|
set NATIVE=%JAVA_HOME%\bin\native-image.cmd
|
||||||
|
|
||||||
|
|
||||||
|
echo Using GraalVM native compiler: %NATIVE%
|
||||||
|
|
||||||
|
echo Creating uberjar
|
||||||
|
clojure -T:build uber
|
||||||
|
|
||||||
|
set UBERJAR=
|
||||||
|
for /f "delims=" %%a in ('dir /b /s target\clj-totp-*-standalone.jar') do @set UBERJAR=%%a
|
||||||
|
echo Created uberjar: %UBERJAR%
|
||||||
|
|
||||||
|
echo "Creating native image"
|
||||||
|
cmd /c %NATIVE% -jar %UBERJAR% -o target\%BIN_FILE% -H:+ReportExceptionStackTraces --features=clj_easy.graal_build_time.InitClojureClasses --report-unsupported-elements-at-runtime --verbose --no-fallback -H:ReflectionConfigurationFiles=reflect_config.json -H:-CheckToolchain --initialize-at-build-time=org.fusesource.jansi.Ansi
|
||||||
|
|
||||||
|
|
||||||
|
echo Executable created: target\%BIN_FILE%.exe
|
||||||
|
|
||||||
|
copy target\%BIN_FILE%.exe %DEST_DIR%
|
||||||
|
echo Native image copied to %DEST_DIR%\%BIN_FILE%.exe
|
||||||
17
native.sh
17
native.sh
@@ -8,8 +8,23 @@ clojure -T:build uber
|
|||||||
UBERJAR=$(realpath --relative-to=target target/clj-totp-*-standalone.jar)
|
UBERJAR=$(realpath --relative-to=target target/clj-totp-*-standalone.jar)
|
||||||
|
|
||||||
echo "Creating native image"
|
echo "Creating native image"
|
||||||
$NATIVE -jar target/$UBERJAR -o target/$BIN_FILE -H:+ReportExceptionStackTraces --features=clj_easy.graal_build_time.InitClojureClasses --report-unsupported-elements-at-runtime --verbose --no-fallback -H:ReflectionConfigurationFiles=./reflect_config.json
|
$NATIVE -jar target/$UBERJAR -o target/$BIN_FILE\
|
||||||
|
-H:+ReportExceptionStackTraces\
|
||||||
|
-H:ReflectionConfigurationFiles=./reflect_config.json\
|
||||||
|
--verbose --no-fallback\
|
||||||
|
--features=clj_easy.graal_build_time.InitClojureClasses\
|
||||||
|
--report-unsupported-elements-at-runtime\
|
||||||
|
--strict-image-heap\
|
||||||
|
-march=native\
|
||||||
|
-R:MaxHeapSize=10m\
|
||||||
|
--initialize-at-build-time=org.fusesource.jansi.Ansi\
|
||||||
|
--initialize-at-build-time='org.fusesource.jansi.Ansi$Color'\
|
||||||
|
--initialize-at-build-time='org.fusesource.jansi.Ansi$Attribute'\
|
||||||
|
'--initialize-at-build-time=org.fusesource.jansi.Ansi$1'
|
||||||
|
|
||||||
echo "Executable created on target/$BIN_FILE"
|
echo "Executable created on target/$BIN_FILE"
|
||||||
cp target/$BIN_FILE ~/bin
|
cp target/$BIN_FILE ~/bin
|
||||||
echo "Copied to ~/bin/$BIN_FILE"
|
echo "Copied to ~/bin/$BIN_FILE"
|
||||||
|
|
||||||
|
echo "Compress executable for distribution"
|
||||||
|
xz -fv target/$BIN_FILE
|
||||||
|
|||||||
15
projects/cli/deps.edn
Executable file
15
projects/cli/deps.edn
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
{:paths ["src" "resources" "target/classes"]
|
||||||
|
:deps {;clj-totp/core {:local/root "../core"}
|
||||||
|
org.clojure/clojure {:mvn/version "1.12.1"}
|
||||||
|
cli-matic/cli-matic {:mvn/version "0.5.4"} ;; https://github.com/l3nz/cli-matic
|
||||||
|
;; Progress bar
|
||||||
|
com.github.pmonks/spinner {:mvn/version "2.0.284"}}
|
||||||
|
|
||||||
|
:aliases {;; Execute the app
|
||||||
|
;:run {:main-opts ["-m" "totp.app"]}
|
||||||
|
|
||||||
|
;; Kaocha runner. You can use the 'kaocha' wrapper located in ~/bin/kaocha
|
||||||
|
:test {:extra-paths ["test"]
|
||||||
|
:extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}}
|
||||||
|
:main-opts ["-m" "kaocha.runner"]}}}
|
||||||
|
|
||||||
@@ -4,33 +4,63 @@
|
|||||||
[totp.data :refer :all]
|
[totp.data :refer :all]
|
||||||
[cli-matic.core :refer [run-cmd]]
|
[cli-matic.core :refer [run-cmd]]
|
||||||
[clojure.pprint :as pp]
|
[clojure.pprint :as pp]
|
||||||
[clojure.string :as str])
|
[clojure.string :as str]
|
||||||
|
[progress.determinate :as pd])
|
||||||
(:import [java.util TimerTask Timer])
|
(:import [java.util TimerTask Timer])
|
||||||
(:gen-class))
|
(:gen-class))
|
||||||
|
|
||||||
|
(def DEFAULT_BAR_STYLE :coloured-ascii-boxes)
|
||||||
|
|
||||||
|
(defn print-timer
|
||||||
|
([] (print-timer 1 30 DEFAULT_BAR_STYLE))
|
||||||
|
([bar-style] (print-timer 1 30 bar-style))
|
||||||
|
([start period bar-style]
|
||||||
|
(let [a (atom start)]
|
||||||
|
(pd/animate! a :opts {:total period
|
||||||
|
;:line 1
|
||||||
|
:label "Next TOTP: "
|
||||||
|
;:redraw-rate 60 ;; updates per second
|
||||||
|
:style (get pd/styles bar-style)}
|
||||||
|
;(println)
|
||||||
|
(run! (fn [_] (Thread/sleep 1000) (swap! a inc)) (range start (inc period)))
|
||||||
|
;(println)
|
||||||
|
))))
|
||||||
|
|
||||||
|
|
||||||
(defn- print-confinuous
|
(defn- print-confinuous
|
||||||
([secret] (print-confinuous secret "sha1" 6 30))
|
([secret] (print-confinuous secret "sha1" 6 30 true DEFAULT_BAR_STYLE))
|
||||||
([secret algorithm digits period]
|
([secret algorithm digits period bar bar-style]
|
||||||
(let [step-millis (* 1000 period)
|
(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 (format "[%d] %s" (System/currentTimeMillis) (get-otp s algorithm digits period))))
|
delay-sec (int (/ delay 1000))
|
||||||
|
fn-show (fn [s] (println (format "%n[%d] %s%n"
|
||||||
|
(System/currentTimeMillis)
|
||||||
|
(get-otp s algorithm digits period))))
|
||||||
task (proxy [TimerTask] []
|
task (proxy [TimerTask] []
|
||||||
(run [] (fn-show secret)))]
|
(run [] (println) (fn-show secret)))
|
||||||
|
task-bar (proxy [TimerTask] []
|
||||||
|
(run [] (print-timer bar-style)))
|
||||||
|
task-init (proxy [TimerTask] []
|
||||||
|
(run [] (print-timer (- period delay-sec) period bar-style)))]
|
||||||
(println "\n <Generating continuosly, press enter to stop>\n")
|
(println "\n <Generating continuosly, press enter to stop>\n")
|
||||||
;; (println "Now:" now ", Delay:" delay ", Next execution: " (+ now delay))
|
;; (println "Now:" now ", Delay:" delay ", Next execution: " (+ now delay))
|
||||||
(println "Refresing in" (int (/ delay 1000)) "seconds")
|
(println "Refresing in" delay-sec "seconds")
|
||||||
(fn-show secret)
|
(fn-show secret)
|
||||||
|
;; Now, start the tasks
|
||||||
|
(when bar
|
||||||
|
(. (new Timer) (schedule task-init 0))
|
||||||
|
(. (new Timer) (scheduleAtFixedRate task-bar delay step-millis)))
|
||||||
(. (new Timer) (scheduleAtFixedRate task delay step-millis)))
|
(. (new Timer) (scheduleAtFixedRate task delay step-millis)))
|
||||||
(read-line))) ;; Waits for a key press
|
;; Waits for a key press
|
||||||
|
(read-line)))
|
||||||
|
|
||||||
|
|
||||||
(defn cmd-generate
|
(defn cmd-generate
|
||||||
[& {:keys [secret continuous algorithm digits period]}]
|
[& {:keys [secret continuous algorithm digits period bar bar-style]}]
|
||||||
;;(pp/pprint opts)
|
;;(pp/pprint opts)
|
||||||
(if continuous
|
(if continuous
|
||||||
(print-confinuous secret algorithm digits period)
|
(print-confinuous secret algorithm digits period bar bar-style)
|
||||||
(println (get-otp secret algorithm digits period))))
|
(println (get-otp secret algorithm digits period))))
|
||||||
|
|
||||||
|
|
||||||
@@ -49,28 +79,45 @@
|
|||||||
(let [step-millis (* 1000 period)
|
(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)))
|
||||||
|
delay-sec (int (/ delay 1000))
|
||||||
fn-show (fn [s]
|
fn-show (fn [s]
|
||||||
|
(println "\n")
|
||||||
(dorun (map print-app s))
|
(dorun (map print-app s))
|
||||||
(println "")) ;; Separate each
|
(println) ;; Separate each
|
||||||
|
)
|
||||||
task (proxy [TimerTask] []
|
task (proxy [TimerTask] []
|
||||||
(run [] (fn-show apps)))]
|
(run [] (fn-show apps)))]
|
||||||
(println "\n <Generating continuosly, press enter to stop>\n")
|
(println "\n <Generating continuosly, press enter to stop>\n")
|
||||||
;; (println "Now:" now ", Delay:" delay ", Next execution: " (+ now delay))
|
;; (println "Now:" now ", Delay:" delay ", Next execution: " (+ now delay))
|
||||||
(println "Refresing in" (int (/ delay 1000)) "seconds")
|
(println "Refresing in" delay-sec "seconds")
|
||||||
(fn-show apps)
|
(fn-show apps)
|
||||||
|
;; Now, start the tasks
|
||||||
(. (new Timer) (scheduleAtFixedRate task delay step-millis)))
|
(. (new Timer) (scheduleAtFixedRate task delay step-millis)))
|
||||||
(read-line))) ;; Waits for a key press
|
)) ;; Waits for a key press
|
||||||
|
|
||||||
|
|
||||||
(defn cmd-get-multi
|
(defn cmd-get-multi
|
||||||
[& {:keys [continuous _arguments]}]
|
[& {:keys [continuous bar bar-style _arguments]}]
|
||||||
;(pp/pprint opts)
|
;(pp/pprint opts)
|
||||||
(with-config
|
(with-config
|
||||||
(let [apps (filter some? #_{:clj-kondo/ignore [:unresolved-symbol]}
|
(let [apps (filter some? #_{:clj-kondo/ignore [:unresolved-symbol]}
|
||||||
(map #(get-app cfg %) _arguments))]
|
(map #(get-app cfg %) _arguments))]
|
||||||
;(println "found apps: " apps)
|
;(println "found apps: " apps)
|
||||||
(if continuous
|
(if continuous
|
||||||
(print-app-continuous 30 apps)
|
(let [period 30
|
||||||
|
step-millis (* 1000 period)
|
||||||
|
now (System/currentTimeMillis)
|
||||||
|
delay (int (- step-millis (rem now step-millis)))
|
||||||
|
delay-sec (int (/ delay 1000))
|
||||||
|
task-bar (proxy [TimerTask] []
|
||||||
|
(run [] (print-timer bar-style)))
|
||||||
|
task-init (proxy [TimerTask] []
|
||||||
|
(run [] (print-timer (- period delay-sec) period bar-style)))]
|
||||||
|
(print-app-continuous period apps)
|
||||||
|
(when bar
|
||||||
|
(. (new Timer) (schedule task-init 0))
|
||||||
|
(. (new Timer) (scheduleAtFixedRate task-bar delay step-millis)))
|
||||||
|
(read-line))
|
||||||
(dorun (map #(print-app %) apps))))))
|
(dorun (map #(print-app %) apps))))))
|
||||||
|
|
||||||
|
|
||||||
@@ -153,7 +200,7 @@
|
|||||||
|
|
||||||
(def cli-options
|
(def cli-options
|
||||||
{:app {:command "totp"
|
{:app {:command "totp"
|
||||||
:version "1.1"
|
:version "1.2"
|
||||||
:description ["Generate a TOTP"]}
|
:description ["Generate a TOTP"]}
|
||||||
|
|
||||||
:commands [;; Generate a TOTP with given params
|
:commands [;; Generate a TOTP with given params
|
||||||
@@ -182,7 +229,15 @@
|
|||||||
{:option "period" :short "p"
|
{:option "period" :short "p"
|
||||||
:as "Validity time in seconds"
|
:as "Validity time in seconds"
|
||||||
:type :int
|
:type :int
|
||||||
:default 30}]
|
:default 30}
|
||||||
|
{:option "bar" :short "b"
|
||||||
|
:as "Show progress bar"
|
||||||
|
:type :with-flag
|
||||||
|
:default true}
|
||||||
|
{:option "bar-style" :short "s"
|
||||||
|
:as "Progress bar style"
|
||||||
|
:type #{:ascii-basic :ascii-boxes :coloured-ascii-boxes :emoji-circles :emoji-boxes}
|
||||||
|
:default :coloured-ascii-boxes}]
|
||||||
:runs cmd-generate}
|
:runs cmd-generate}
|
||||||
;; Generate a TOTP for a configured app
|
;; Generate a TOTP for a configured app
|
||||||
{:command "get" :short "g"
|
{:command "get" :short "g"
|
||||||
@@ -198,7 +253,15 @@
|
|||||||
{:option "continuous" :short "c"
|
{:option "continuous" :short "c"
|
||||||
:as "Contiuous mode"
|
:as "Contiuous mode"
|
||||||
:type :with-flag
|
:type :with-flag
|
||||||
:default false}]
|
:default false}
|
||||||
|
{:option "bar" :short "b"
|
||||||
|
:as "Show progress bar"
|
||||||
|
:type :with-flag
|
||||||
|
:default true}
|
||||||
|
{:option "bar-style" :short "s"
|
||||||
|
:as "Progress bar style"
|
||||||
|
:type #{:ascii-basic :ascii-boxes :coloured-ascii-boxes :emoji-circles :emoji-boxes}
|
||||||
|
:default :coloured-ascii-boxes}]
|
||||||
:runs cmd-get-multi}
|
:runs cmd-get-multi}
|
||||||
;; Check and init your config file
|
;; Check and init your config file
|
||||||
{:command "config" :short "c"
|
{:command "config" :short "c"
|
||||||
1
projects/cli/tests.edn
Normal file
1
projects/cli/tests.edn
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#kaocha/v1 {}
|
||||||
1
projects/core/.cpcache/4091673994.basis
Normal file
1
projects/core/.cpcache/4091673994.basis
Normal file
File diff suppressed because one or more lines are too long
1
projects/core/.cpcache/4091673994.cp
Normal file
1
projects/core/.cpcache/4091673994.cp
Normal file
File diff suppressed because one or more lines are too long
1
projects/core/.cpcache/425892293.basis
Normal file
1
projects/core/.cpcache/425892293.basis
Normal file
File diff suppressed because one or more lines are too long
1
projects/core/.cpcache/425892293.cp
Normal file
1
projects/core/.cpcache/425892293.cp
Normal file
File diff suppressed because one or more lines are too long
2
projects/core/.cpcache/425892293.main
Normal file
2
projects/core/.cpcache/425892293.main
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
-m
|
||||||
|
kaocha.runner
|
||||||
12
projects/core/deps.edn
Executable file
12
projects/core/deps.edn
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
{:paths ["src" "resources" "target/classes"]
|
||||||
|
:deps {org.clojure/clojure {:mvn/version "1.12.1"}
|
||||||
|
mvxcvi/alphabase {:mvn/version "3.0.185"} ;; https://github.com/greglook/alphabase
|
||||||
|
;; Protobuf for java
|
||||||
|
com.google.protobuf/protobuf-java {:mvn/version "3.25.8"}
|
||||||
|
}
|
||||||
|
|
||||||
|
:aliases {;; Kaocha runner. You can use the 'kaocha' wrapper located in ~/bin/kaocha
|
||||||
|
:test {:extra-paths ["test"]
|
||||||
|
:extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}}
|
||||||
|
:main-opts ["-m" "kaocha.runner"]}}}
|
||||||
|
|
||||||
BIN
projects/core/target/classes/alphabase/base32$decode.class
Normal file
BIN
projects/core/target/classes/alphabase/base32$decode.class
Normal file
Binary file not shown.
Binary file not shown.
BIN
projects/core/target/classes/alphabase/base32$decode_STAR_.class
Normal file
BIN
projects/core/target/classes/alphabase/base32$decode_STAR_.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/alphabase/base32$encode.class
Normal file
BIN
projects/core/target/classes/alphabase/base32$encode.class
Normal file
Binary file not shown.
Binary file not shown.
BIN
projects/core/target/classes/alphabase/base32$encode_STAR_.class
Normal file
BIN
projects/core/target/classes/alphabase/base32$encode_STAR_.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/alphabase/base32$fn__170.class
Normal file
BIN
projects/core/target/classes/alphabase/base32$fn__170.class
Normal file
Binary file not shown.
Binary file not shown.
BIN
projects/core/target/classes/alphabase/base32__init.class
Normal file
BIN
projects/core/target/classes/alphabase/base32__init.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/alphabase/base64$decode.class
Normal file
BIN
projects/core/target/classes/alphabase/base64$decode.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/alphabase/base64$encode.class
Normal file
BIN
projects/core/target/classes/alphabase/base64$encode.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/alphabase/base64$fn__230.class
Normal file
BIN
projects/core/target/classes/alphabase/base64$fn__230.class
Normal file
Binary file not shown.
Binary file not shown.
BIN
projects/core/target/classes/alphabase/base64__init.class
Normal file
BIN
projects/core/target/classes/alphabase/base64__init.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/alphabase/bytes$byte_array.class
Normal file
BIN
projects/core/target/classes/alphabase/bytes$byte_array.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/alphabase/bytes$byte_seq.class
Normal file
BIN
projects/core/target/classes/alphabase/bytes$byte_seq.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/alphabase/bytes$bytes_EQ_.class
Normal file
BIN
projects/core/target/classes/alphabase/bytes$bytes_EQ_.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/alphabase/bytes$bytes_QMARK_.class
Normal file
BIN
projects/core/target/classes/alphabase/bytes$bytes_QMARK_.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/alphabase/bytes$compare.class
Normal file
BIN
projects/core/target/classes/alphabase/bytes$compare.class
Normal file
Binary file not shown.
Binary file not shown.
BIN
projects/core/target/classes/alphabase/bytes$concat.class
Normal file
BIN
projects/core/target/classes/alphabase/bytes$concat.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/alphabase/bytes$copy.class
Normal file
BIN
projects/core/target/classes/alphabase/bytes$copy.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/alphabase/bytes$copy_slice.class
Normal file
BIN
projects/core/target/classes/alphabase/bytes$copy_slice.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/alphabase/bytes$fn__144.class
Normal file
BIN
projects/core/target/classes/alphabase/bytes$fn__144.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/alphabase/bytes$from_byte.class
Normal file
BIN
projects/core/target/classes/alphabase/bytes$from_byte.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/alphabase/bytes$from_string.class
Normal file
BIN
projects/core/target/classes/alphabase/bytes$from_string.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/alphabase/bytes$get_byte.class
Normal file
BIN
projects/core/target/classes/alphabase/bytes$get_byte.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/alphabase/bytes$init_bytes.class
Normal file
BIN
projects/core/target/classes/alphabase/bytes$init_bytes.class
Normal file
Binary file not shown.
Binary file not shown.
BIN
projects/core/target/classes/alphabase/bytes$random_bytes.class
Normal file
BIN
projects/core/target/classes/alphabase/bytes$random_bytes.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/alphabase/bytes$set_byte.class
Normal file
BIN
projects/core/target/classes/alphabase/bytes$set_byte.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/alphabase/bytes$to_byte.class
Normal file
BIN
projects/core/target/classes/alphabase/bytes$to_byte.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/alphabase/bytes$to_string.class
Normal file
BIN
projects/core/target/classes/alphabase/bytes$to_string.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/alphabase/bytes__init.class
Normal file
BIN
projects/core/target/classes/alphabase/bytes__init.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/core$bytes__GT_int.class
Normal file
BIN
projects/core/target/classes/totp/core$bytes__GT_int.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/core$bytes_array_QMARK_.class
Normal file
BIN
projects/core/target/classes/totp/core$bytes_array_QMARK_.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/core$fn__195.class
Normal file
BIN
projects/core/target/classes/totp/core$fn__195.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/core$fn__203$fn__204.class
Normal file
BIN
projects/core/target/classes/totp/core$fn__203$fn__204.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/core$fn__203.class
Normal file
BIN
projects/core/target/classes/totp/core$fn__203.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/core$fn__213.class
Normal file
BIN
projects/core/target/classes/totp/core$fn__213.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/core$fn__215.class
Normal file
BIN
projects/core/target/classes/totp/core$fn__215.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/core$fn__219.class
Normal file
BIN
projects/core/target/classes/totp/core$fn__219.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/core$get_alg.class
Normal file
BIN
projects/core/target/classes/totp/core$get_alg.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/core$get_otp.class
Normal file
BIN
projects/core/target/classes/totp/core$get_otp.class
Normal file
Binary file not shown.
Binary file not shown.
BIN
projects/core/target/classes/totp/core$long__GT_bytes.class
Normal file
BIN
projects/core/target/classes/totp/core$long__GT_bytes.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/core$timestamp__GT_steps.class
Normal file
BIN
projects/core/target/classes/totp/core$timestamp__GT_steps.class
Normal file
Binary file not shown.
101
projects/core/target/classes/totp/core.clj
Normal file
101
projects/core/target/classes/totp/core.clj
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
(ns totp.core
|
||||||
|
(:require [alphabase.base32 :as b32]
|
||||||
|
[clojure.math :as m])
|
||||||
|
(:import (javax.crypto Mac)
|
||||||
|
(javax.crypto.spec SecretKeySpec)
|
||||||
|
(java.util Base64 Arrays)
|
||||||
|
(java.nio ByteBuffer)))
|
||||||
|
|
||||||
|
(def ^:private byte-array-type (type (.getBytes "")))
|
||||||
|
|
||||||
|
(defn timestamp->steps
|
||||||
|
"Converts from UNIX timestamp in milliseconds to a number os steps of 's' seconds of duration"
|
||||||
|
[time, step-size]
|
||||||
|
(if (or (nil? time) (nil? step-size) (zero? step-size))
|
||||||
|
0
|
||||||
|
(int (quot time (* 1000 step-size)))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn bytes-array?
|
||||||
|
"Return true if x is a byte[]"
|
||||||
|
[x]
|
||||||
|
(= byte-array-type (type x)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn get-alg
|
||||||
|
[alg]
|
||||||
|
(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
|
||||||
|
(and (string? key) (string? message) (some? (get-alg algorithm))) :string
|
||||||
|
(and (bytes-array? key) (bytes-array? message) (some? (get-alg algorithm))) :byte
|
||||||
|
:else :nil)))
|
||||||
|
|
||||||
|
;; By default
|
||||||
|
(defmethod hmac :nil [_ _ _]
|
||||||
|
nil)
|
||||||
|
|
||||||
|
;; When key and message are strings
|
||||||
|
(defmethod hmac :string [algorithm key message]
|
||||||
|
(if (or (empty? key) (empty? message))
|
||||||
|
""
|
||||||
|
(let [mac (doto (Mac/getInstance (get-alg algorithm)) (.init (SecretKeySpec. (.getBytes key) (get-alg algorithm))))
|
||||||
|
hmac-bytes (.doFinal mac (.getBytes message))]
|
||||||
|
;; Return the Base64 encoded HMAC
|
||||||
|
(.encodeToString (Base64/getEncoder) hmac-bytes))))
|
||||||
|
|
||||||
|
;; When key and message are arrays of bytes
|
||||||
|
(defmethod hmac :byte [algorithm key message]
|
||||||
|
(if (nil? message)
|
||||||
|
(bytes (byte-array 0))
|
||||||
|
(let [mac (doto (Mac/getInstance (get-alg algorithm)) (.init (SecretKeySpec. key (get-alg algorithm))))
|
||||||
|
hmac-bytes (.doFinal mac message)]
|
||||||
|
;; Return the Base64 encoded HMAC
|
||||||
|
(Base64/getEncoder) hmac-bytes)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn long->bytes
|
||||||
|
"Converts a long to an array of 8 bytes"
|
||||||
|
[l]
|
||||||
|
;;Java equivalent: ByteBuffer.allocate(Long.SIZE / Byte.SIZE).putLong(someLong).array();
|
||||||
|
(when (integer? l)
|
||||||
|
(-> (ByteBuffer/allocate (/ Long/SIZE Byte/SIZE))
|
||||||
|
(.putLong l)
|
||||||
|
(.array))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn bytes->int
|
||||||
|
"Converts an array of 4 bytes to an integer"
|
||||||
|
[bytes]
|
||||||
|
;;Java equivalent: ByteBuffer.wrap(data).getInt()
|
||||||
|
(when (some? bytes)
|
||||||
|
(.getInt (ByteBuffer/wrap bytes))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn get-otp
|
||||||
|
"Generate an OTP with the given secret (in base32) for the specified timestep"
|
||||||
|
([secret algorithm digits period] ;;algorithm digits period
|
||||||
|
(when (and secret period)
|
||||||
|
(let [step (timestamp->steps (System/currentTimeMillis) period)
|
||||||
|
k (b32/decode secret)
|
||||||
|
c (long->bytes step)
|
||||||
|
hs (hmac algorithm k c)
|
||||||
|
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)
|
||||||
|
]
|
||||||
|
(format (str "%0" digits "d")
|
||||||
|
(-> chunk
|
||||||
|
(bytes->int)
|
||||||
|
(bit-and 0x7fffffff)
|
||||||
|
(rem (int (m/pow 10 digits))))))))
|
||||||
|
([secret]
|
||||||
|
(get-otp secret "sha1" 6 30)))
|
||||||
BIN
projects/core/target/classes/totp/core__init.class
Normal file
BIN
projects/core/target/classes/totp/core__init.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/data$add_app.class
Normal file
BIN
projects/core/target/classes/totp/data$add_app.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/data$create_app.class
Normal file
BIN
projects/core/target/classes/totp/data$create_app.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/data$create_cfg_QMARK_.class
Normal file
BIN
projects/core/target/classes/totp/data$create_cfg_QMARK_.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/data$create_cfg_file.class
Normal file
BIN
projects/core/target/classes/totp/data$create_cfg_file.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/data$delete_app$fn__250.class
Normal file
BIN
projects/core/target/classes/totp/data$delete_app$fn__250.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/data$delete_app.class
Normal file
BIN
projects/core/target/classes/totp/data$delete_app.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/data$exists_config.class
Normal file
BIN
projects/core/target/classes/totp/data$exists_config.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/data$fn__235.class
Normal file
BIN
projects/core/target/classes/totp/data$fn__235.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/data$get_app$fn__260.class
Normal file
BIN
projects/core/target/classes/totp/data$get_app$fn__260.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/data$get_app.class
Normal file
BIN
projects/core/target/classes/totp/data$get_app.class
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
projects/core/target/classes/totp/data$join_path.class
Normal file
BIN
projects/core/target/classes/totp/data$join_path.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/data$list_apps$fn__256.class
Normal file
BIN
projects/core/target/classes/totp/data$list_apps$fn__256.class
Normal file
Binary file not shown.
BIN
projects/core/target/classes/totp/data$list_apps.class
Normal file
BIN
projects/core/target/classes/totp/data$list_apps.class
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user