Compare commits
5 Commits
6c017b3262
...
v1.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 386d4f7434 | |||
| 82b1407489 | |||
| 5651cc1ab2 | |||
| 96ed6ae1e9 | |||
| d8c3f5ee67 |
@@ -2,7 +2,7 @@
|
|||||||
(:require [clojure.tools.build.api :as b]))
|
(:require [clojure.tools.build.api :as b]))
|
||||||
|
|
||||||
(def lib 'es.rcorral/clj-totp)
|
(def lib 'es.rcorral/clj-totp)
|
||||||
(def version (format "1.2.%s" (b/git-count-revs nil)))
|
(def version (format "1.1.%s" (b/git-count-revs nil)))
|
||||||
(def target-dir "target")
|
(def target-dir "target")
|
||||||
(def class-dir (str target-dir "/classes"))
|
(def class-dir (str target-dir "/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))
|
||||||
|
|||||||
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>
|
|
||||||
10
deps.edn
10
deps.edn
@@ -3,18 +3,10 @@
|
|||||||
io.github.clojure/tools.build {:mvn/version "0.10.10"}
|
io.github.clojure/tools.build {:mvn/version "0.10.10"}
|
||||||
mvxcvi/alphabase {:mvn/version "3.0.185"} ;; https://github.com/greglook/alphabase
|
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
|
cli-matic/cli-matic {:mvn/version "0.5.4"} ;; https://github.com/l3nz/cli-matic
|
||||||
;; For SQLite
|
|
||||||
com.github.seancorfield/next.jdbc {:mvn/version "1.3.1048"}
|
|
||||||
org.xerial/sqlite-jdbc {:mvn/version "3.50.3.0"}
|
|
||||||
;; For Datomic local
|
|
||||||
com.datomic/local {:mvn/version "1.0.291"};; https://docs.datomic.com/datomic-local.html
|
|
||||||
;; Native image (GraalVM)
|
;; 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/
|
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
|
;; Protobuf for java
|
||||||
com.google.protobuf/protobuf-java {:mvn/version "3.25.8"}
|
com.google.protobuf/protobuf-java {:mvn/version "3.25.8"}}
|
||||||
;; Progress bar
|
|
||||||
com.github.pmonks/spinner {:mvn/version "2.0.284"}
|
|
||||||
}
|
|
||||||
|
|
||||||
:aliases {;; Execute the app
|
:aliases {;; Execute the app
|
||||||
:run {:main-opts ["-m" "totp.app"]}
|
:run {:main-opts ["-m" "totp.app"]}
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
@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
BIN
doc/db.png
Binary file not shown.
|
Before Width: | Height: | Size: 7.9 KiB |
33
native.cmd
33
native.cmd
@@ -1,33 +0,0 @@
|
|||||||
|
|
||||||
@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
|
|
||||||
|
|
||||||
|
|
||||||
echo Executable created: target\%BIN_FILE%.exe
|
|
||||||
|
|
||||||
copy target\%BIN_FILE%.exe %DEST_DIR%
|
|
||||||
echo Native image copied to %DEST_DIR%\%BIN_FILE%.exe
|
|
||||||
@@ -4,62 +4,33 @@
|
|||||||
[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))
|
||||||
|
|
||||||
|
|
||||||
(defn print-timer
|
|
||||||
([] (print-timer 1 30))
|
|
||||||
([start] (print-timer start 30))
|
|
||||||
([start period]
|
|
||||||
(let [a (atom start)]
|
|
||||||
(pd/animate! a :opts {:total period
|
|
||||||
;:line 1
|
|
||||||
:label "Next TOTP: "
|
|
||||||
;:redraw-rate 60 ;; updates per second
|
|
||||||
:style (:coloured-ascii-boxes pd/styles)}
|
|
||||||
;(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 true))
|
([secret] (print-confinuous secret "sha1" 6 30))
|
||||||
([secret algorithm digits period bar]
|
([secret algorithm digits period]
|
||||||
(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] (println (format "[%d] %s" (System/currentTimeMillis) (get-otp s algorithm digits period))))
|
||||||
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 [] (println) (fn-show secret)))
|
(run [] (fn-show secret)))]
|
||||||
task-bar (proxy [TimerTask] []
|
|
||||||
(run [] (print-timer)))
|
|
||||||
task-init (proxy [TimerTask] []
|
|
||||||
(run [] (print-timer (- period delay-sec) period)))]
|
|
||||||
(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" delay-sec "seconds")
|
(println "Refresing in" (int (/ delay 1000)) "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)))
|
||||||
;; Waits for a key press
|
(read-line))) ;; Waits for a key press
|
||||||
(read-line)))
|
|
||||||
|
|
||||||
|
|
||||||
(defn cmd-generate
|
(defn cmd-generate
|
||||||
[& {:keys [secret continuous algorithm digits period bar]}]
|
[& {:keys [secret continuous algorithm digits period]}]
|
||||||
;;(pp/pprint opts)
|
;;(pp/pprint opts)
|
||||||
(if continuous
|
(if continuous
|
||||||
(print-confinuous secret algorithm digits period bar)
|
(print-confinuous secret algorithm digits period)
|
||||||
(println (get-otp secret algorithm digits period))))
|
(println (get-otp secret algorithm digits period))))
|
||||||
|
|
||||||
|
|
||||||
@@ -78,45 +49,28 @@
|
|||||||
(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" delay-sec "seconds")
|
(println "Refresing in" (int (/ delay 1000)) "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)))
|
||||||
)) ;; Waits for a key press
|
(read-line))) ;; Waits for a key press
|
||||||
|
|
||||||
|
|
||||||
(defn cmd-get-multi
|
(defn cmd-get-multi
|
||||||
[& {:keys [continuous bar _arguments]}]
|
[& {:keys [continuous _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
|
||||||
(let [period 30
|
(print-app-continuous 30 apps)
|
||||||
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)))
|
|
||||||
task-init (proxy [TimerTask] []
|
|
||||||
(run [] (print-timer (- period delay-sec) period)))]
|
|
||||||
(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))))))
|
||||||
|
|
||||||
|
|
||||||
@@ -199,7 +153,7 @@
|
|||||||
|
|
||||||
(def cli-options
|
(def cli-options
|
||||||
{:app {:command "totp"
|
{:app {:command "totp"
|
||||||
:version "1.2"
|
:version "1.1"
|
||||||
:description ["Generate a TOTP"]}
|
:description ["Generate a TOTP"]}
|
||||||
|
|
||||||
:commands [;; Generate a TOTP with given params
|
:commands [;; Generate a TOTP with given params
|
||||||
@@ -228,11 +182,7 @@
|
|||||||
{: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}]
|
|
||||||
: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"
|
||||||
@@ -248,11 +198,7 @@
|
|||||||
{: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}]
|
|
||||||
: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,68 +0,0 @@
|
|||||||
(ns totp.db.datomic
|
|
||||||
(:require [totp.data :as data]
|
|
||||||
[datomic.client.api :as d]))
|
|
||||||
|
|
||||||
|
|
||||||
(def cfg-path (data/join-path (System/getProperty "user.home") ".config" "totp"))
|
|
||||||
(def db-path (str cfg-path java.io.File/separator "data"))
|
|
||||||
|
|
||||||
(def cfg {:server-type :datomic-local
|
|
||||||
:system "local-data"
|
|
||||||
:storage-dir db-path})
|
|
||||||
|
|
||||||
(def client (d/client cfg))
|
|
||||||
|
|
||||||
;; Schema for our database
|
|
||||||
|
|
||||||
(def totp-schema [{:db/ident :app/name
|
|
||||||
:db/valueType :db.type/string
|
|
||||||
:db/cardinality :db.cardinality/one
|
|
||||||
:db/unique :db.unique/identity
|
|
||||||
:db/doc "Unique name of the application. Between 2 and 32 chars"
|
|
||||||
:db.attr/preds (fn [s] (<= 3 (count s) 15))}
|
|
||||||
{:db/ident :app/desc
|
|
||||||
:db/valueType :db.type/string
|
|
||||||
:db/cardinality :db.cardinality/one
|
|
||||||
:db/doc "(optional) Description of the application"}
|
|
||||||
{:db/ident :app/secret
|
|
||||||
:db/valueType :db.type/string
|
|
||||||
:db/cardinality :db.cardinality/one
|
|
||||||
:db/doc "Secret BASE32"}
|
|
||||||
{:db/ident :app/period
|
|
||||||
:db/valueType :db.type/long
|
|
||||||
:db/cardinality :db.cardinality/one
|
|
||||||
:db/doc "Time slice in seconds (30 by default)"}
|
|
||||||
{:db/ident :app/config
|
|
||||||
:db/valueType :db.type/string
|
|
||||||
:db/cardinality :db.cardinality/one
|
|
||||||
:db/doc "(Optional) Extra config"}
|
|
||||||
|
|
||||||
{:db/ident :user/login
|
|
||||||
:db/valueType :db.type/string
|
|
||||||
:db/cardinality :db.cardinality/one
|
|
||||||
:db/unique :db.unique/identity
|
|
||||||
:db/doc "Identifier for the user"}
|
|
||||||
{:db/ident :user/passwd
|
|
||||||
:db/valueType :db.type/string
|
|
||||||
:db/cardinality :db.cardinality/one
|
|
||||||
:db/doc "Password"}
|
|
||||||
{:db/ident :user/active
|
|
||||||
:db/valueType :db.type/boolean
|
|
||||||
:db/cardinality :db.cardinality/one
|
|
||||||
:db/doc "Is the user active?"}
|
|
||||||
{:db/ident :user/desc
|
|
||||||
:db/valueType :db.type/string
|
|
||||||
:db/cardinality :db.cardinality/one
|
|
||||||
:db/doc "(Optional) Description of the user"}
|
|
||||||
{:db/ident :user/config
|
|
||||||
:db/valueType :db.type/string
|
|
||||||
:db/cardinality :db.cardinality/one
|
|
||||||
:db/doc "(Optional) Extra config"}
|
|
||||||
{:db/ident :user/apps
|
|
||||||
:db/valueType :db.type/ref
|
|
||||||
:db/cardinality :db.cardinality/many
|
|
||||||
:db/doc "Applications for this user"}])
|
|
||||||
|
|
||||||
(defn init-db
|
|
||||||
[client]
|
|
||||||
(d/create-database client {:db-name "totp"}))
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
(ns totp.db.sqlite
|
|
||||||
(:require [next.jdbc :as jdbc]))
|
|
||||||
|
|
||||||
;; DB configuration
|
|
||||||
(def db {:dbname "totp-data.sqlite"
|
|
||||||
:dbtype "sqlite"})
|
|
||||||
|
|
||||||
;; DB parsed config
|
|
||||||
(def data-source (jdbc/get-datasource db))
|
|
||||||
|
|
||||||
(defn init-db
|
|
||||||
"Create an empty DB"
|
|
||||||
[]
|
|
||||||
(jdbc/execute! data-source ["
|
|
||||||
create table apps (
|
|
||||||
id int auto_increment primary key,
|
|
||||||
name varchar(32),
|
|
||||||
desc varchar(255)
|
|
||||||
)"]))
|
|
||||||
|
|
||||||
(comment
|
|
||||||
(init-db)
|
|
||||||
)
|
|
||||||
BIN
totp-data.sqlite
BIN
totp-data.sqlite
Binary file not shown.
Reference in New Issue
Block a user