Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .clj-kondo/config.edn
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
{:lint-as {devcards.core/defcard clojure.core/def
devcards.core/defcard-rg clojure.core/def}}
{:hooks {:analyze-call {portfolio.react-18/defscene hooks.portfolio.react-18/defscene-hook}}
:lint-as {devcards.core/defcard clojure.core/def
devcards.core/defcard-rg clojure.core/def
portfolio.reagent/defscene clojure.core/defn}}
24 changes: 24 additions & 0 deletions .clj-kondo/hooks/portfolio/react_18.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
(ns hooks.portfolio.react-18
(:require
[clj-kondo.hooks-api :as api]))

(defn defscene-hook
[{:keys [node]}]
(let [[_defscene name & more] (:children node)
forms more
first-form (first forms)]
(cond
(and (api/string-node? first-form) (api/keyword-node? (second forms)))
(let [[docstring _params _params-value fn-params & body] forms
body-node (api/list-node (cons (api/token-node 'do) body))
def-node (api/list-node [(api/token-node 'defn) name docstring fn-params body-node])]
{:node def-node})
(api/string-node? first-form)
(let [[docstring & body] forms
body-node (api/list-node (cons (api/token-node 'do) body))
def-node (api/list-node [(api/token-node 'def) name docstring body-node])]
{:node def-node})
:else (let [body-node (api/list-node (cons (api/token-node 'do) forms))
def-node (api/list-node [(api/token-node 'def) name body-node])]
{:node def-node}))))

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
**/.clever.json
**/tmp
**/target
**/public/js

### Intellij
.idea/
Expand Down
10 changes: 10 additions & 0 deletions auto_web_clj/deps.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{:deps {amalloy/ring-gzip-middleware {:mvn/version "0.1.4"}
clj-http/clj-http {:mvn/version "3.13.1"}
http-kit/http-kit {:mvn/version "2.8.1"}
mount/mount {:mvn/version "0.1.23"}
ring-cors/ring-cors {:mvn/version "0.1.13"}
ring/ring {:mvn/version "1.15.2"}
ring/ring-anti-forgery {:mvn/version "1.4.0"}
ring/ring-headers {:mvn/version "0.4.0"}
ring/ring-ssl {:mvn/version "0.4.0"}}
:paths ["src" "resources"]}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

body, h1, h2, h3, h4, h5, h6, p {
font-family: ui-sans-serif, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;
}

h1,h2,h3,h4,h5,h6,p,div,li,ul{
user-select: none;
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
138 changes: 138 additions & 0 deletions auto_web_clj/src/auto_web/middleware/rate_limit.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
(ns auto-web.middleware.rate-limit
"Rate limit middleware to prevent attacks."
(:import [java.time Instant Duration]
[java.util.concurrent Executors TimeUnit])
(:require
[auto-core.uuid :refer [unguessable]]
[clojure.string :as str]
[ring.util.response :as response]))

(defn make-rate-limiter
"Returns a newly created limiter, a map with:
- `middleware-fn` function wrapping the handler to add this behavior, add it early in the chain so unncessary computation.
- `executor` the single thread scheduled excecutor that is used to track limiter and update it.
- `id` an id generated for each instance.
- `stop` function to call with parameter `rate-limiter` to stop.

Options are `:limit`, `:window-ms`"
[{:keys [limit window-ms cleanup-interval-ms name]
:as pars}]
(let [state (atom {})
executor (Executors/newSingleThreadScheduledExecutor)
id (unguessable)
out *out*
err *err*]
;; Async cleanup thread
(.scheduleAtFixedRate
executor
(fn []
(binding [*out* out
*err* err]
(when (pos? (count @state))
(println (format "Rate limiter cleanup thread: `%s-%s` (%d IPs): %s"
name
id
(count @state)
(str/join ", " (keys @state)))))
(let [now (Instant/now)]
(swap! state (fn [m]
(->> m
(remove (fn [[_ {:keys [start]}]]
(> (.toMillis (Duration/between start now)) window-ms)))
(into {}))))
(flush))))
cleanup-interval-ms
cleanup-interval-ms
TimeUnit/MILLISECONDS)
(println (format "`%s-%s` is a new rate limiter. (%d queries in %d ms, cleanup every %d)"
name
id
limit
window-ms
cleanup-interval-ms))
(flush)
{:middleware-fn
(fn [handler]
(fn [req]
(let [{:keys [remote-addr]} req
ip remote-addr
now (Instant/now)
{:keys [count start]
:or {count 0
start now}}
(get @state ip)
elapsed (.toMillis (Duration/between start now))
header (format "Middleware `%s-%s`, request (ip %s) at time %s" name id ip now)]
(if (< elapsed window-ms)
(if (< count limit)
(do (println (format "%s, request accepted in window [%s, +%d], [%d < %d]"
header
start
window-ms
count
limit))
(swap! state update
ip
#(-> %
(update :count (fnil inc 0))
(assoc :start start)))
(handler req))
(do (println (format "%s, request refused in window [%s, +%d], [%d >= %d]"
header
start
window-ms
count
limit))
(-> (response/response "Too many requests")
(response/status 429))))
(do (println (format "%s, is beyond window [%s, +%d]" header start window-ms))
(swap! state assoc
ip
{:count 1
:start now})
(handler req))))))
:executor executor
:state state
:pars (assoc pars :id id)
:stop (fn [{:keys [executor id]
:as _rate-limiter}]
(println (format "Stopping rate limit middleware `%s-%s`:" name id))
(flush)
(.shutdownNow executor))
:id id}))

(defn stop-rate-limit [rate-limiter] (let [{:keys [stop]} rate-limiter] (stop rate-limiter)))

(comment
(def limiter
(make-rate-limiter {:limit 2
:window-ms 10000}))
(defn handler-test [_] {:response :hey})
((-> handler-test
limiter)
{:remote-addr "192.168.1.1"})
;;
;
)


(defn rate-limiter-desc
[rate-limiter]
(let [{:keys [limit id window-ms name cleanup-interval-ms]} (:pars rate-limiter)]
(format "Endpoint `%s-%s`authorizes %d queries every %d. Cleaned every `%d` ms.\n%s"
name
id
limit
window-ms
cleanup-interval-ms
(pr-str (:pars rate-limiter)))))

(comment
(-> {:limit 3
:window-ms 7000
:name "test"
:cleanup-interval-ms 5000}
make-rate-limiter
rate-limiter-desc)
;;
)
10 changes: 10 additions & 0 deletions auto_web_cljc/deps.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{:deps {com.github.hephaistox/auto-core
{:git/sha "e72b9a127cd0d7a2665be1db69673babed722ee5",
:git/url "https://github.com/hephaistox/auto-core",
:hephaistox/dir "../../auto_core",
:hephaistox/url "https://github.com/hephaistox/auto-core"},
com.taoensso/sente {:mvn/version "1.20.0"},
hiccup/hiccup {:mvn/version "2.0.0"},
metosin/muuntaja {:mvn/version "0.6.11"},
metosin/reitit {:mvn/version "0.9.1"}},
:paths ["src"]}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@

(defn- on-close-modal
[modal-kw]
#?(:cljs (fn [_] (set! (.-style.display (.getElementById js/document (name modal-kw))) "none"))
:clj (str "document.getElementById(\"" (name modal-kw) "\").style.display = \"none\";")))
#?(:cljs (fn [_] (set! (.-style.display (.getElementById js/document modal-kw)) "none"))
:clj (str "document.getElementById(\"" modal-kw "\").style.display = \"none\";")))

(defn- on-open-modal
[modal-kw]
#?(:cljs (fn [_] (set! (.-style.display (.getElementById js/document (name modal-kw))) "block"))
:clj (str "document.getElementById(\"" (name modal-kw) "\").style.display = \"block\";")))
#?(:cljs (fn [_] (set! (.-style.display (.getElementById js/document modal-kw)) "block"))
:clj (str "document.getElementById(\"" modal-kw "\").style.display = \"block\";")))

(defn cpeople-modal*
"What is displayed when the modal opens"
Expand Down Expand Up @@ -40,10 +40,10 @@
[:div.w3-round-xxlarge.w3-col.m4.w3-card
opts
[:div.w3-modal {:id modal-kw
:onclick (on-close-modal modal-kw)}
:on-click (on-close-modal modal-kw)}
[:div.w3-modal-content.w3-animate-top.w3-round-xxlarge {:style {:z-index "-9999!important"}}
modal-content]]
[:div.w3-padding-24.w3-row {:onclick (on-open-modal modal-kw)}
[:div.w3-padding-24.w3-row {:on-click (on-open-modal modal-kw)}
[:div.w3-center.w3-row (cimg {:class "w3-circle w3-center w3-margin"} :xsmall img)]
[:div.w3-row.w3-center
[:div.w3-large.w3-bold people-name]
Expand Down
31 changes: 31 additions & 0 deletions auto_web_cljc/src/auto_web/components/button.cljc
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
(ns auto-web.components.button
"Buttons"
(:require
[auto-web.components.link :refer [link-opts]]))

(defn- clink-button*
[opts link text]
[:a
(-> opts
(update :class #(str "w3-button w3-ripple " %))
(merge (link-opts link)))
text])

(defn clink-button
"A link visually like a button"
[opts link text]
(if (map? opts) (clink-button* opts link text) (clink-button* {} opts link)))


(defn- cbutton*
[opts link text]
[:a
(-> opts
(update :class #(str "w3-button w3-ripple " %))
(merge (link-opts link)))
text])

(defn cbutton
"A link visually like a button"
[opts link text]
(if (map? opts) (cbutton* opts link text) (cbutton* {} opts link)))
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@
"Metadata of an img html element."
[img]
(let [{:keys [url target alt img-id]
:or {url "images/logos/not_def.png"}}
:or {url (-> images
:not-def
:url)}}
img]
{:src url
:target target
Expand Down
14 changes: 14 additions & 0 deletions auto_web_cljc/src/auto_web/components/link.cljc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
(ns auto-web.components.link
"A link is made of
* `url` where the link lead into
* `target` as defined in the html `:a` target
* `link-id` the internal name of it")

(defn link-opts
"Returns link options for a link"
[link]
(let [{:keys [url target link-id]} link]
{:href url
:target target
"data-link-name" (some-> link-id
name)}))
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
(:require
[auto-core.uuid :refer [unguessable]]
[auto-web.components.img :refer [cicon cicon-img]]
[auto-web.components.link :refer [clink]]
[auto-web.components.link :refer [link-opts]]
[clojure.string :refer [blank?]]))

(defn cbullet
Expand All @@ -30,8 +30,8 @@
[:i.fa {:class (str fa-icon " w3-center")
:style {:width "1em"}}]
(if-not (blank? label)
[:b.w3-margin-right.w3-button.w3-hover-opacity
(clink {} link (str label ":"))]
[:b.w3-margin.w3-button.w3-hover-opacity
[:a (link-opts link) (str label ":")]]
[:b.w3-margin-right])
(when tooltip
[:span.w3-text.w3-tag {:style {:position "absolute"
Expand All @@ -52,15 +52,15 @@
item*]
[:div.w3-tooltip
(assoc-in opts* [:style :overflow] "visible")
(clink {}
link
[:i.fa.w3-btn.w3-center {:class fa-icon
:style {:overflow "visible"}}]
(when tooltip
[:span.w3-text.w3-tag {:style {:position "absolute"
:left "0"
:bottom "2.5em"}}
tooltip]))]))
[:a
(link-opts link)
[:i.fa.w3-btn.w3-center {:class fa-icon
:style {:overflow "visible"}}]]
(when tooltip
[:span.w3-text.w3-tag {:style {:position "absolute"
:left "0"
:bottom "2.5em"}}
tooltip])]))

(defn cbar
"Display as a bar of icons"
Expand All @@ -86,14 +86,12 @@
^{:key react-key}
[:div.w3-tooltip
(assoc-in opts [:style :overflow] "visible")
(clink {}
link
[:i.fa.w3-btn.w3-center (cicon-img {} img)]
(when tooltip
[:span.w3-text.w3-tag {:style {:position "absolute"
:left "0"
:bottom "2em"}}
tooltip]))])
[:a (link-opts link) [:i.fa.w3-btn.w3-center (cicon-img {} img)]]
(when tooltip
[:span.w3-text.w3-tag {:style {:position "absolute"
:left "0"
:bottom "2em"}}
tooltip])])

(defn csmall-imgs
"List `items` to display as small buttons all on the same row."
Expand All @@ -104,15 +102,15 @@
(let [{:keys [fa-icon link label]} item]
(conj hiccup
(when (seq item)
(clink {}
link
[:div.w3-tooltip.w3-button {:style {:overflow "visible"}}
[:div.w3-hover-opacity (cicon {} fa-icon)]
(when label
[:div.w3-text.w3-tag {:style {:bottom "-2em"
:left "0em"
:position "absolute"}}
label])])))))
[:a
(link-opts link)
[:div.w3-tooltip.w3-button {:style {:overflow "visible"}}
[:div.w3-hover-opacity (cicon {} fa-icon)]
(when label
[:div.w3-text.w3-tag {:style {:bottom "-2em"
:left "0em"
:position "absolute"}}
label])]]))))
[:div.w3-container.w3-content.w3-flex
(assoc-in opts [:style :justify-content] "center")]
items)))
Loading
Loading