Compare commits
21 Commits
e165dc107f
...
v1.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 5651cc1ab2 | |||
| 96ed6ae1e9 | |||
| d8c3f5ee67 | |||
| 9eeb3571d5 | |||
| 58a17dc5bd | |||
| 4f29260f9b | |||
| df82cf3f44 | |||
| f32986f2db | |||
| 1205a79f19 | |||
| 38126f987a | |||
| fa0de1f624 | |||
| efec0ca07c | |||
| 4361782861 | |||
| 8d0fb81a9d | |||
| 4a1abd7fd7 | |||
| b7d3c6ce86 | |||
| 0a4e531b2f | |||
| a22f4a5670 | |||
| f408834726 | |||
| 09d8cd0e10 | |||
| d448ebe001 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,6 +1,7 @@
|
||||
/.clj-kondo/
|
||||
/.cpcache/
|
||||
/.lsp/
|
||||
/target/
|
||||
.nrepl-port
|
||||
.calva
|
||||
|
||||
|
||||
3
.idea/.gitignore
generated
vendored
3
.idea/.gitignore
generated
vendored
@@ -1,3 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
6
.idea/ClojureProjectResolveSettings.xml
generated
6
.idea/ClojureProjectResolveSettings.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ClojureProjectResolveSettings">
|
||||
<currentScheme>IDE</currentScheme>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/clj-kondo.xml
generated
6
.idea/clj-kondo.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="KondoProjectSettings">
|
||||
<option name="useCljKondo" value="YES" />
|
||||
</component>
|
||||
</project>
|
||||
18
.idea/clojure-deps.xml
generated
18
.idea/clojure-deps.xml
generated
@@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DepsProjectsManager">
|
||||
<option name="dirTypeMappings">
|
||||
<set>
|
||||
<FolderState>
|
||||
<option name="dirUrl" value="file://$PROJECT_DIR$/test" />
|
||||
<option name="type" value="TEST_SOURCE" />
|
||||
</FolderState>
|
||||
</set>
|
||||
</option>
|
||||
<option name="projectFiles">
|
||||
<set>
|
||||
<option value="file://$PROJECT_DIR$/deps.edn" />
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
8
.idea/dictionaries/project.xml
generated
8
.idea/dictionaries/project.xml
generated
@@ -1,8 +0,0 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="project">
|
||||
<words>
|
||||
<w>hotp</w>
|
||||
<w>topt</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
||||
9
.idea/libraries/Deps__aero_1_1_6.xml
generated
9
.idea/libraries/Deps__aero_1_1_6.xml
generated
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: aero:1.1.6">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/aero/aero/1.1.6/aero-1.1.6.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: clojure.java-time:1.4.3">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/clojure/java-time/clojure.java-time/1.4.3/clojure.java-time-1.4.3.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: com.nextjournal/beholder:1.0.2">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/nextjournal/beholder/1.0.2/beholder-1.0.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
9
.idea/libraries/Deps__expound_0_9_0.xml
generated
9
.idea/libraries/Deps__expound_0_9_0.xml
generated
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: expound:0.9.0">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/expound/expound/0.9.0/expound-0.9.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
9
.idea/libraries/Deps__fipp_0_6_26.xml
generated
9
.idea/libraries/Deps__fipp_0_6_26.xml
generated
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: fipp:0.6.26">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/fipp/fipp/0.6.26/fipp-0.6.26.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
9
.idea/libraries/Deps__hawk_0_2_11.xml
generated
9
.idea/libraries/Deps__hawk_0_2_11.xml
generated
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: hawk:0.2.11">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/hawk/hawk/0.2.11/hawk-0.2.11.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: io.methvin/directory-watcher:0.17.3">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/methvin/directory-watcher/0.17.3/directory-watcher-0.17.3.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: lambdaisland/clj-diff:1.4.78">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/lambdaisland/clj-diff/1.4.78/clj-diff-1.4.78.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: lambdaisland/deep-diff2:2.11.216">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/lambdaisland/deep-diff2/2.11.216/deep-diff2-2.11.216.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: lambdaisland/kaocha:1.91.1392">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/lambdaisland/kaocha/1.91.1392/kaocha-1.91.1392.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: lambdaisland/tools.namespace:0.3.256">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/lambdaisland/tools.namespace/0.3.256/tools.namespace-0.3.256.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
9
.idea/libraries/Deps__meta_merge_1_0_0.xml
generated
9
.idea/libraries/Deps__meta_merge_1_0_0.xml
generated
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: meta-merge:1.0.0">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/meta-merge/meta-merge/1.0.0/meta-merge-1.0.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: mvxcvi/arrangement:2.1.0">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/mvxcvi/arrangement/2.1.0/arrangement-2.1.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: net.incongru.watchservice/barbary-watchservice:1.0">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/net/incongru/watchservice/barbary-watchservice/1.0/barbary-watchservice-1.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: net.java.dev.jna/jna:5.12.1">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/net/java/dev/jna/jna/5.12.1/jna-5.12.1.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: org.clojure/clojure:1.12.1">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/clojure/clojure/1.12.1/clojure-1.12.1.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: org.clojure/core.rrb-vector:0.1.2">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/clojure/core.rrb-vector/0.1.2/core.rrb-vector-0.1.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: org.clojure/core.specs.alpha:0.4.74">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/clojure/core.specs.alpha/0.4.74/core.specs.alpha-0.4.74.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: org.clojure/java.classpath:1.0.0">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/clojure/java.classpath/1.0.0/java.classpath-1.0.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: org.clojure/spec.alpha:0.5.238">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/clojure/spec.alpha/0.5.238/spec.alpha-0.5.238.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: org.clojure/tools.cli:1.1.230">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/clojure/tools.cli/1.1.230/tools.cli-1.1.230.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: org.clojure/tools.reader:1.3.6">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/clojure/tools.reader/1.3.6/tools.reader-1.3.6.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: org.slf4j/slf4j-api:1.7.36">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: org.tcrawley/dynapath:1.1.0">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/tcrawley/dynapath/1.1.0/dynapath-1.1.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
9
.idea/libraries/Deps__progrock_0_1_2.xml
generated
9
.idea/libraries/Deps__progrock_0_1_2.xml
generated
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: progrock:0.1.2">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/progrock/progrock/0.1.2/progrock-0.1.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
9
.idea/libraries/Deps__slingshot_0_12_2.xml
generated
9
.idea/libraries/Deps__slingshot_0_12_2.xml
generated
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Deps: slingshot:0.12.2">
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/slingshot/slingshot/0.12.2/slingshot-0.12.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
6
.idea/misc.xml
generated
6
.idea/misc.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="IDE SDK" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/clj-totp.iml" filepath="$PROJECT_DIR$/clj-totp.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
12
.idea/runConfigurations/REPL_for_clj_totp.xml
generated
12
.idea/runConfigurations/REPL_for_clj_totp.xml
generated
@@ -1,12 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="REPL for clj-totp" type="ClojureREPL" factoryName="Local" activateToolWindowBeforeRun="false">
|
||||
<option name="configVersion" value="1" />
|
||||
<option name="displayName" value="REPL for clj-totp" />
|
||||
<option name="execution" value="DEPS" />
|
||||
<module name="clj-totp" />
|
||||
<option name="options" />
|
||||
<option name="profiles" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
88
README.md
88
README.md
@@ -1,33 +1,55 @@
|
||||
# clj-totp
|
||||
|
||||
TOTP (Time-based One Time Password) in clojure. It can be used in the command line, web API o simple embedded web.
|
||||
|
||||
## What is TOPT
|
||||
|
||||
The TOPT is a standard used to generate a time-based password. Usually, this password is used as a second
|
||||
factor authentication.
|
||||
|
||||
You can read more about the algorithm here:
|
||||
|
||||
- Wikipedia: https://en.wikipedia.org/wiki/Time-based_one-time_password
|
||||
- TOTP RFC: https://web.archive.org/web/20110711124823/http://tools.ietf.org/html/rfc6238
|
||||
- HOTP RFC: https://www.ietf.org/rfc/rfc4226.txt
|
||||
|
||||
|
||||
## The inside
|
||||
|
||||
This project is done 100% in clojure. It uses `deps.edn` for configuring the project.
|
||||
|
||||
## Implementation timeline
|
||||
|
||||
### v1.0
|
||||
- [ ] Functional TOTP generation
|
||||
- [ ] Get TOTP from command line
|
||||
- [ ] Store configuration in a simple BD (sqlite, for example)
|
||||
|
||||
### v1.1
|
||||
- [ ] REST API
|
||||
- [ ] User management
|
||||
|
||||
### v1.2
|
||||
- [ ] Simple web connected to REST API
|
||||
# clj-totp
|
||||
|
||||
TOTP (Timebased One Time Password) in clojure. It can be used in the command line, web API o simple embeded web.
|
||||
|
||||
## What is TOPT
|
||||
|
||||
The TOPT is an standad used to generate a time-based password. Usually, this password is used as a second
|
||||
factor authentication.
|
||||
|
||||
You can red more about the algorith here:
|
||||
|
||||
- Wikipedia: https://en.wikipedia.org/wiki/Time-based_one-time_password
|
||||
- TOTP RFC: https://web.archive.org/web/20110711124823/http://tools.ietf.org/html/rfc6238
|
||||
- HOTP RFC: https://www.ietf.org/rfc/rfc4226.txt
|
||||
|
||||
## The inside
|
||||
|
||||
This project is done 100% in clojure. It uses `deps.edn` for configuring the project.
|
||||
|
||||
## Features
|
||||
|
||||
### v1.0
|
||||
- Functional TOTP generation
|
||||
- Get TOTP from command line
|
||||
- Continuous update every 30 seconds
|
||||
|
||||
## Usage
|
||||
You can use the `clojure` command to run the program:
|
||||
```
|
||||
clojure -M:run <params>
|
||||
```
|
||||
|
||||
If you prefer using the distributed jar:
|
||||
```
|
||||
java -jar clj-topt-1.0.35-standalone.jar <params>
|
||||
```
|
||||
|
||||
You can use the binary (compiled with GraalVM) in linux environments:
|
||||
```
|
||||
totp <params>
|
||||
```
|
||||
|
||||
All three methods are equivalent.
|
||||
|
||||
### Generate a single TOTP
|
||||
You can simple run:
|
||||
```
|
||||
totp generate <secret in BASE32>
|
||||
```
|
||||
|
||||
If want to update coninously the generated TOTP, you cand add the `-s` param:
|
||||
```
|
||||
totp generate <secret in BASE32> -s
|
||||
```
|
||||
|
||||
|
||||
25
build.clj
Normal file
25
build.clj
Normal file
@@ -0,0 +1,25 @@
|
||||
(ns build
|
||||
(:require [clojure.tools.build.api :as b]))
|
||||
|
||||
(def lib 'es.rcorral/clj-topt)
|
||||
(def version (format "1.0.%s" (b/git-count-revs nil)))
|
||||
(def class-dir "target/classes")
|
||||
(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 uber [_]
|
||||
(clean nil)
|
||||
(b/copy-dir {:src-dirs ["src" "resources"]
|
||||
:target-dir class-dir})
|
||||
(b/compile-clj {:basis @basis
|
||||
:ns-compile '[totp.app]
|
||||
:class-dir class-dir})
|
||||
(b/uber {:class-dir class-dir
|
||||
:uber-file uber-file
|
||||
:basis @basis
|
||||
:main 'totp.app}))
|
||||
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>
|
||||
1
collect-deps.sh
Executable file
1
collect-deps.sh
Executable file
@@ -0,0 +1 @@
|
||||
~/.sdkman/candidates/java/21.0.2-graalce/bin/java -agentlib:native-image-agent=config-output-dir=META-INF/native-image -jar target/clj-topt-1.0.32-standalone.jar g TUGOBTEHPSCMUCYAT6UPELNWGE -c
|
||||
22
deps.edn
22
deps.edn
@@ -1,11 +1,19 @@
|
||||
{:paths ["src"]
|
||||
:deps {clojure.java-time/clojure.java-time {:mvn/version "1.4.3"}
|
||||
mvxcvi/alphabase {:mvn/version "3.0.185"}}
|
||||
:deps {org.clojure/clojure {:mvn/version "1.12.1"}
|
||||
io.github.clojure/tools.build {:mvn/version "0.10.10"}
|
||||
mvxcvi/alphabase {:mvn/version "3.0.185"} ;; https://github.com/greglook/alphabase
|
||||
cli-matic/cli-matic {:mvn/version "0.5.4"} ;; https://github.com/l3nz/cli-matic
|
||||
;; 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/
|
||||
|
||||
:aliases {:test {:extra-paths ["test"] ;; https://cljdoc.org/d/uberdeps/uberdeps/1.4.0/doc/readme
|
||||
: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"] ;; https://cljdoc.org/d/uberdeps/uberdeps/1.4.0/doc/readme
|
||||
:extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}}
|
||||
:main-opts ["-m" "kaocha.runner"]}
|
||||
:uberdeps {
|
||||
:replace-deps {uberdeps/uberdeps {:mvn/version "1.4.0"}}
|
||||
:replace-paths []
|
||||
:main-opts ["-m" "uberdeps.uberjar"]}}}
|
||||
|
||||
;; Run with clj -T:build function-in-build
|
||||
:build {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
|
||||
:ns-default build}}}
|
||||
|
||||
34
doc/db.plantuml
Normal file
34
doc/db.plantuml
Normal file
@@ -0,0 +1,34 @@
|
||||
@startuml
|
||||
' configuration
|
||||
skinparam linetype ortho
|
||||
|
||||
entity "user" as user {
|
||||
id: number
|
||||
--
|
||||
login: varchar(64)
|
||||
passw: varchar(512)
|
||||
active: shortint
|
||||
desc: varchar(512)
|
||||
config: varchar(512)
|
||||
}
|
||||
|
||||
entity "app" as app {
|
||||
id: number
|
||||
--
|
||||
name: varchar(32)
|
||||
desc: varchar(512)
|
||||
secret: varchar(512)
|
||||
period: int
|
||||
config: varchar(512)
|
||||
}
|
||||
|
||||
entity "user_app" as user_app {
|
||||
user_id: number
|
||||
app_id: number
|
||||
--
|
||||
}
|
||||
|
||||
user ||--o{ user_app
|
||||
app ||--o{ user_app
|
||||
|
||||
@enduml
|
||||
BIN
doc/db.png
Normal file
BIN
doc/db.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.9 KiB |
14
native.sh
Executable file
14
native.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
NATIVE=~/.sdkman/candidates/java/21.0.2-graalce/bin/native-image
|
||||
UBERJAR=clj-topt-1.0.32-standalone.jar
|
||||
BIN_FILE=totp
|
||||
|
||||
echo "Creating uberjar"
|
||||
clojure -T:build uber
|
||||
|
||||
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
|
||||
|
||||
echo "Executable created on target/$BIN_FILE"
|
||||
52
reflect_config.json
Normal file
52
reflect_config.json
Normal file
@@ -0,0 +1,52 @@
|
||||
[
|
||||
{
|
||||
"name": "com.sun.crypto.provider.HmacSHA1",
|
||||
"methods": [
|
||||
{
|
||||
"name": "<init>",
|
||||
"parameterTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "java.lang.reflect.Method",
|
||||
"methods": [
|
||||
{
|
||||
"name": "canAccess",
|
||||
"parameterTypes": [
|
||||
"java.lang.Object"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "java.util.Arrays",
|
||||
"allDeclaredClasses": true,
|
||||
"allPublicClasses": true,
|
||||
"queryAllPublicMethods": true,
|
||||
"methods": [
|
||||
{
|
||||
"name": "copyOfRange",
|
||||
"parameterTypes": [
|
||||
"byte[]",
|
||||
"int",
|
||||
"int"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "java.util.Timer",
|
||||
"queryAllPublicMethods": true,
|
||||
"methods": [
|
||||
{
|
||||
"name": "scheduleAtFixedRate",
|
||||
"parameterTypes": [
|
||||
"java.util.TimerTask",
|
||||
"long",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -1,3 +1,64 @@
|
||||
(ns totp.app
|
||||
( :require [totp.core :refer :all]))
|
||||
(:require [totp.core :refer :all]
|
||||
[cli-matic.core :refer [run-cmd]]
|
||||
[cli-matic.utils :as U]
|
||||
[clojure.pprint :as pp])
|
||||
(:import [java.util TimerTask Timer])
|
||||
(:gen-class))
|
||||
|
||||
|
||||
(defn- print-confinuous
|
||||
([secret] (print-confinuous secret 30))
|
||||
([secret step]
|
||||
(let [step-millis (* 1000 step)
|
||||
now (System/currentTimeMillis)
|
||||
delay (int (- step-millis (rem now step-millis)))
|
||||
fn-show (fn [s] (println (System/currentTimeMillis) "-> "(get-otp s)))
|
||||
task (proxy [TimerTask] []
|
||||
(run [] (fn-show secret)))]
|
||||
(println "\n <Generating continuosly, press enter to stop>\n")
|
||||
;; (println "Now:" now ", Delay:" delay ", Next execution: " (+ now delay))
|
||||
(fn-show secret)
|
||||
(. (new Timer) (scheduleAtFixedRate task delay step-millis)))
|
||||
(read-line))) ;; Waits for a key press
|
||||
|
||||
(comment
|
||||
(print get-otp "MJXW42LBORXQ====")
|
||||
(print-confinuous "MJXW42LBORXQ====")
|
||||
)
|
||||
|
||||
(defn cmd-generate
|
||||
[& {:keys [secret continuous] :as otps}]
|
||||
;(pp/pprint otps)
|
||||
(if continuous
|
||||
(print-confinuous secret)
|
||||
(println (get-otp secret))
|
||||
))
|
||||
|
||||
|
||||
(def cli-options
|
||||
{:app {:command "totp"
|
||||
:version "1.0"
|
||||
:description ["Generate a TOTP"]}
|
||||
|
||||
:commands [{:command "generate" :short "g"
|
||||
:description "Generate one TOTP with a given secret in BASE32"
|
||||
:examples ["Generate one TOTP and exit:"
|
||||
" totp generate \"MJXW42LBORXQ====\""
|
||||
"Generate one TOTP, update each 30 seconds:"
|
||||
" totp g -c \"MJXW42LBORXQ====\""]
|
||||
:opts [{:option "secret"
|
||||
:short 0
|
||||
:as "Secret codified in BASE32"
|
||||
:type :string
|
||||
:default :present}
|
||||
{:option "continuous"
|
||||
:short "c"
|
||||
:type :with-flag
|
||||
:as "Contiuous mode"
|
||||
:default false}]
|
||||
:runs cmd-generate}]})
|
||||
|
||||
|
||||
(defn -main [& args]
|
||||
(run-cmd args cli-options))
|
||||
|
||||
@@ -5,19 +5,20 @@
|
||||
(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
|
||||
(quot (/ time 1000) step-size)))
|
||||
(int (quot time (* 1000 step-size)))))
|
||||
|
||||
|
||||
(defn bytes-array?
|
||||
"Return true if x is a byte[]"
|
||||
[x]
|
||||
(= byte/1 (type x)))
|
||||
(= byte-array-type (type x)))
|
||||
|
||||
|
||||
(defmulti hmac-sha1
|
||||
@@ -25,7 +26,7 @@
|
||||
(fn [key message]
|
||||
(cond
|
||||
(and (string? key) (string? message)) :string
|
||||
(and (= byte/1 (type key)) (= byte/1 (type message))) :byte
|
||||
(and (bytes-array? key) (bytes-array? message)) :byte
|
||||
:else :nil)))
|
||||
|
||||
;; By default
|
||||
|
||||
106
src/totp/data.clj
Normal file
106
src/totp/data.clj
Normal file
@@ -0,0 +1,106 @@
|
||||
(ns totp.data
|
||||
(:require [clojure.edn :as e]
|
||||
[clojure.string :as str]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.pprint :as pp]))
|
||||
|
||||
(defn join-path
|
||||
"Joins several subpaths using system's path separator (/ un *NIX and \\ in windows)"
|
||||
[& col]
|
||||
(str/join java.io.File/separator col))
|
||||
|
||||
|
||||
(def cfg-path (join-path (System/getProperty "user.home") ".config" "totp"))
|
||||
|
||||
(def cfg-file (join-path cfg-path "apps.edn"))
|
||||
|
||||
(def cfg-header ";; clj-totp configuration file
|
||||
;; This file contents a list of maps with :name and :secret entries
|
||||
;; Secrets must be encoded in BASE32
|
||||
|
||||
")
|
||||
|
||||
|
||||
(defn exists-config
|
||||
"Checks if the config file exists"
|
||||
[]
|
||||
(.exists (io/file cfg-file)))
|
||||
|
||||
|
||||
(defn create-cfg-file
|
||||
"Creates the config file"
|
||||
[]
|
||||
(println "Creating " cfg-file)
|
||||
(io/delete-file cfg-file true)
|
||||
(io/make-parents cfg-file)
|
||||
(spit cfg-file cfg-header)
|
||||
true)
|
||||
|
||||
|
||||
(defn create-cfg?
|
||||
"Create configuration file if not exists. Overridable with allways = true"
|
||||
([] (create-cfg? false))
|
||||
([allways]
|
||||
(if (or allways (not (exists-config)))
|
||||
(create-cfg-file)
|
||||
false)))
|
||||
|
||||
(comment
|
||||
(exists-config)
|
||||
(create-cfg?)
|
||||
)
|
||||
|
||||
|
||||
(defn load-config
|
||||
"Loads configuration from file"
|
||||
[]
|
||||
(e/read-string (slurp cfg-file)))
|
||||
|
||||
|
||||
(defn store-config
|
||||
"Store configuration to file"
|
||||
[cfg]
|
||||
(when cfg
|
||||
(spit cfg-file (str cfg-header (with-out-str
|
||||
(binding [pp/*print-right-margin* 50]
|
||||
(pp/pprint cfg)))))))
|
||||
|
||||
|
||||
(defn delete-app
|
||||
[cfg name]
|
||||
(filter #(not= name (:name %)) cfg))
|
||||
|
||||
|
||||
(defn add-app
|
||||
[cfg name secret]
|
||||
(conj (delete-app cfg name) {:name name :secret secret}))
|
||||
|
||||
|
||||
(defn list-apps
|
||||
[cfg]
|
||||
(map :name cfg))
|
||||
|
||||
|
||||
(defn get-app
|
||||
[cfg name]
|
||||
(first (filter #(= name (:name %)) cfg)))
|
||||
|
||||
|
||||
(comment
|
||||
(exists-config)
|
||||
(create-cfg?)
|
||||
(load-config)
|
||||
|
||||
(with-out-str
|
||||
(binding [pp/*print-right-margin* 50]
|
||||
(pp/pprint [{:name "abc" :secret "def"} {:name "my-app" :secret "abc123"}])))
|
||||
|
||||
(store-config [{:name "abc" :secret "def"} {:name "my-app" :secret "abc123"}])
|
||||
|
||||
(-> nil
|
||||
(add-app "app1" "abc123abc123")
|
||||
(add-app "app2" "abc123abc123")
|
||||
(add-app "app1" "123456789012")
|
||||
(store-config))
|
||||
|
||||
)
|
||||
Reference in New Issue
Block a user