Skip to content

Commit 070965a

Browse files
committed
Provide a timestamp and ASVS version upon updates
Also added an option to set recurring tasks.
1 parent 75af9ba commit 070965a

6 files changed

Lines changed: 131 additions & 24 deletions

File tree

resources/public/css/main.css

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,18 @@ header a:hover {
591591
}
592592
}
593593
}
594+
menu {
595+
display: flex;
596+
padding: 0;
597+
flex-direction: row;
598+
gap: 1em;
599+
div {
600+
display: flex;
601+
}
602+
.Recurrence-input {
603+
transform: translateY(-0.4em);
604+
}
605+
}
594606
}
595607
.Assessment .item {
596608
display: flex;
@@ -682,3 +694,21 @@ button.primary {
682694
strong {
683695
font-weight: 600;
684696
}
697+
698+
.Recurrence-input {
699+
display: flex;
700+
flex-direction: row;
701+
opacity: 1;
702+
transition: .2s ease;
703+
label {
704+
opacity: 0.5;
705+
font-size: 0.6em;
706+
}
707+
div {
708+
display: flex;
709+
flex-direction: column;
710+
}
711+
&.hide {
712+
opacity: 0;
713+
}
714+
}

src/asva/assessments.cljs

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
(ns asva.assessments
22
(:require
3-
[asva.components :refer [highlight progress-indicator]]
3+
[asva.components :refer [highlight progress-indicator recurrence-input]]
44
[asva.i18n :refer [t]]
55
[asva.icons :as icons]
6-
[asva.utils :refer [<> <sub dispatch>e e> parse-int slug slug-key]]
6+
[asva.utils :refer [<> <sub dispatch>e e> parse-int slug slug-key now]]
77
[clojure.edn :as edn]
88
[clojure.string :as str]
99
[clojure.walk :refer [postwalk]]
@@ -75,22 +75,52 @@
7575
(re-frame/reg-event-fx
7676
::notes
7777
(fn [{:keys [db]} [_ shortcode notes]]
78-
(let [updated-db (assoc-in db [::assessments (slug-key shortcode) :notes] notes)]
78+
(let [last-modified (now)
79+
updated-db (update-in db [::assessments (slug-key shortcode)]
80+
(fn [assessment]
81+
(merge assessment
82+
{:asvs-version (-> db ::asvs :version)
83+
:notes notes
84+
:last-modified last-modified})))]
7985
{:db updated-db
8086
:local-storage [::assessments (get updated-db ::assessments)]})))
8187

8288
(re-frame/reg-event-fx
8389
::progress
8490
(fn [{:keys [db]} [_ shortcode progress]]
8591
(let [progress (max 0 (min 100 progress))
86-
updated-db (assoc-in db [::assessments (slug-key shortcode) :progress] progress)]
92+
last-modified (now)
93+
updated-db (update-in db [::assessments (slug-key shortcode)]
94+
(fn [assessment]
95+
(merge assessment
96+
{:asvs-version (-> db ::asvs :version)
97+
:progress progress
98+
:last-modified last-modified})))]
8799
{:db updated-db
88100
:local-storage [::assessments (get updated-db ::assessments)]})))
89101

90102
(re-frame/reg-event-fx
91103
::not-applicable
92104
(fn [{:keys [db]} [_ shortcode not-applicable]]
93-
(let [updated-db (assoc-in db [::assessments (slug-key shortcode) :not-applicable] not-applicable)]
105+
(let [last-modified (now)
106+
updated-db (update-in db [::assessments (slug-key shortcode)]
107+
(fn [assessment]
108+
(merge assessment
109+
{:asvs-version (-> db ::asvs :version)
110+
:not-applicable not-applicable
111+
:last-modified last-modified})))]
112+
{:db updated-db
113+
:local-storage [::assessments (get updated-db ::assessments)]})))
114+
115+
(re-frame/reg-event-fx
116+
::recurrence
117+
(fn [{:keys [db]} [_ shortcode recurrence]]
118+
(let [updated-db (update-in db [::assessments (slug-key shortcode)]
119+
(fn [assessment]
120+
(merge assessment
121+
{:asvs-version (-> db ::asvs :version)
122+
:last-modified (now)
123+
:recurring recurrence})))]
94124
{:db updated-db
95125
:local-storage [::assessments (get updated-db ::assessments)]})))
96126

@@ -184,11 +214,12 @@
184214
(group-by :chapter))]
185215
(sort-by key items))))
186216

187-
(defn assessment [{:keys [shortcode description progress not-applicable notes cwe nist last-updated]}]
217+
(defn assessment [{:keys [shortcode description progress not-applicable notes cwe nist last-modified asvs-version]}]
188218
(let [query (re-frame/subscribe [::query])
219+
recurrence-input? (reagent/atom false)
189220
editing? (reagent/atom false)
190221
note (reagent/atom notes)]
191-
(fn [{:keys [shortcode description progress not-applicable notes cwe nist last-updated] :as tmp}]
222+
(fn [{:keys [shortcode description progress not-applicable notes cwe nist last-modified asvs-version]}]
192223
(let [not-applicable (boolean not-applicable)
193224
url (str (-> js/location .-host) "/#" shortcode)
194225
cwe-url (fn [n] (str "https://cwe.mitre.org/data/definitions/" n ".html"))
@@ -209,21 +240,27 @@
209240
:title (t :not-applicable)
210241
:on-change (dispatch>e [::not-applicable shortcode (not not-applicable)])}]
211242
[:label {:for (str shortcode "-na")} "n/a"]]]
212-
(when last-updated [:small.last-updated.badge (t :last-updated last-updated)])
243+
(when last-modified
244+
[:small.last-modified.badge {:title (t :registered-version asvs-version (js/Date. last-modified))}
245+
(t :last-modified (js/Date. last-modified))])
213246
[:p.description (highlight description @query)]
214247
[:div.horizontal
215248
(when (some? cwe) [:a.badge.warning {:target :_blank :title :cwe :rel :noopener :href (cwe-url cwe)} cwe])
216249
(when (some? nist) [:a.badge {:target :_blank :title :nist :rel :noopener :href (nist-url nist)} nist])]
250+
[:menu
251+
(when-not @editing?
252+
[:button {:title (t :assessment-notes) :on-click (e> (reset! editing? true))} [icons/note]])
253+
[:div
254+
[:button {:title (t :recurring) :on-click #(swap! recurrence-input? not)} [icons/recurring]]]
255+
[recurrence-input {:class [(when-not @recurrence-input? :hide)] :on-change #(re-frame/dispatch [::recurrence shortcode %])}]]
217256
[:div.Markdown
218257
(if @editing?
219258
[:<>
220259
[:textarea {:auto-focus true :placeholder (t :assessment-notes) :value @note :on-change (e> (reset! note value))}]
221260
[:a {:href "https://www.markdownguide.org/basic-syntax/" :target :_blank :rel :noopener}
222-
[icons/markdown {:title (t :markdown-support)}]]]
261+
[icons/markdown {:title (t :markdown-support)}]]
262+
[:button.primary {:on-click (dispatch>e (do (reset! editing? false) [::notes shortcode @note]))} "Save"]]
223263
[markdown->hiccup notes])]
224-
(if @editing?
225-
[:button.primary {:on-click (dispatch>e (do (reset! editing? false) [::notes shortcode @note]))} "Save"]
226-
[:button {:title (t :assessment-notes) :on-click (e> (reset! editing? true))} [icons/note]])
227264
[progress-indicator {:width 40
228265
:on-progress (fn [prog] (re-frame/dispatch [::progress shortcode prog]))} progress]]))))
229266

src/asva/components.cljs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
[asva.icons :as icons]
55
[asva.utils :refer [->params e>]]
66
[clojure.string :as str]
7-
[reagent.core :as reagent]))
7+
[reagent.core :as reagent]
8+
[reagent.core :as r]))
89

910
(defn progress-indicator [& args]
1011
(let [[{:keys [on-progress width]
@@ -128,3 +129,32 @@
128129
[:div.Upload-message
129130
[:h1 (t :drop-to-upload)]])]
130131
body)))
132+
133+
(defn recurrence-input [{:keys [value on-change] :as params}]
134+
(let [{:keys [every unit]
135+
:or {every 0 unit :month}} value
136+
local-state (r/atom {:every every :unit unit})]
137+
(fn [{:keys [on-change] :as params}]
138+
(let [params (dissoc params :on-change :value)]
139+
[:div.Recurrence-input params
140+
[:div
141+
[:label (t :every)]
142+
[:input {:type :number
143+
:min 0
144+
:size 3
145+
:value (:every @local-state)
146+
:on-change (fn [e]
147+
(let [v (js/parseInt (.. e -target -value))]
148+
(swap! local-state assoc :every v)
149+
(on-change (assoc @local-state :every v))))}]]
150+
[:div
151+
[:label (t :time-span)]
152+
[:select {:value (name (:unit @local-state))
153+
:on-change (fn [e]
154+
(let [v (keyword (.. e -target -value))]
155+
(swap! local-state assoc :unit v)
156+
(on-change (assoc @local-state :unit v))))}
157+
[:option {:value :day} "Day"]
158+
[:option {:value :week} "Week"]
159+
[:option {:value :month} "Month"]
160+
[:option {:value :year} "Year"]]]]))))

src/asva/i18n.cljs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@
9090
:12-hour (tongue/inst-formatter "{hour12}" inst-strings-en)
9191
:two-decimals (fn [num] (format-number-en (round-to-decimals num 2)))
9292
:percent (fn [num] (str (format-number-en (round-to-decimals num 2)) "%"))
93-
:last-updated (fn [d] (str "Last updated " ((tongue/inst-formatter "{month-long} {day}, {year}" inst-strings-en) d)))
93+
:last-modified (fn [d] (str "Last modified " ((tongue/inst-formatter "{month-long} {day}, {year}" inst-strings-en) d)))
94+
:registered-version "Registered with ASVS v.{1} at {2}"
95+
:recurring "Recurring"
9496

9597
:main-title "Welcome to Our ASVA Assessment Page"
9698
:preface-1 "Our mission is to integrate robust security practices into our services. This assessment, aligned with "
@@ -115,6 +117,8 @@
115117
:file-upload-help "Don't have a file yet?"
116118
:file-upload-download "Download the latest ASVS from OWASP"
117119

120+
:every "Every"
121+
:time-span "Time span"
118122
:search "Search..."
119123
:copy-location "Copy location of anchor to your clipboard"
120124
:level "Level {1}"
@@ -140,7 +144,7 @@
140144
:failed-reading "Error reading the ASVS file. Check if the file exists, is accessible, and is in JSON format."}
141145

142146
:nb
143-
{:last-updated (fn [d] (str "Sist oppdatert " ((tongue/inst-formatter "{day}. {month-long} {year}" inst-strings-no) d)))
147+
{:last-modified (fn [d] (str "Sist oppdatert " ((tongue/inst-formatter "{day}. {month-long} {year}" inst-strings-no) d)))
144148
:main-title "Velkommen til vår ASVA-vurderingsside"
145149
:preface-1 "Vår misjon er å integrere robuste sikkerhetspraksiser i våre tjenester. Denne vurderingen, i tråd med "
146150
:preface-link-1 "OWASPs ASVA-retningslinjer"
@@ -189,7 +193,7 @@
189193

190194

191195
:nl
192-
{:last-updated (fn [d] (str "Laatst bijgewerkt " ((tongue/inst-formatter "{day} {month-long} {year}" inst-strings-nl) d)))
196+
{:last-modified (fn [d] (str "Laatst bijgewerkt " ((tongue/inst-formatter "{day} {month-long} {year}" inst-strings-nl) d)))
193197
:main-title "Welkom op onze ASVA-beoordelingspagina"
194198
:preface-1 "Onze missie is om robuuste beveiligingspraktijken te integreren in onze services. Deze beoordeling, in lijn met "
195199
:preface-link-1 "OWASP's ASVA-richtlijnen"
@@ -227,7 +231,7 @@
227231
:config "Configuratie"}
228232

229233
:pt
230-
{:last-updated (fn [d] (str "Última atualização " ((tongue/inst-formatter "{day} de {month-long} de {year}" inst-strings-pt) d)))
234+
{:last-modified (fn [d] (str "Última atualização " ((tongue/inst-formatter "{day} de {month-long} de {year}" inst-strings-pt) d)))
231235
:main-title "Bem-vindo à nossa Página de Avaliação ASVA"
232236
:preface-1 "Nossa missão é integrar práticas de segurança robustas aos nossos serviços. Esta avaliação, alinhada com "
233237
:preface-link-1 "as diretrizes da ASVA da OWASP"
@@ -265,7 +269,7 @@
265269
:config "Configuração"}
266270

267271
:es
268-
{:last-updated (fn [d] (str "Última actualización " ((tongue/inst-formatter "{day} de {month-long} de {year}" inst-strings-es) d)))
272+
{:last-modified (fn [d] (str "Última actualización " ((tongue/inst-formatter "{day} de {month-long} de {year}" inst-strings-es) d)))
269273
:main-title "Bienvenido a nuestra página de evaluación ASVA"
270274
:preface-1 "Nuestra misión es integrar prácticas de seguridad robustas en nuestros servicios. Esta evaluación, alineada con "
271275
:preface-link-1 "las pautas de ASVA de OWASP"
@@ -303,7 +307,7 @@
303307
:config "Configuración"}
304308

305309
:ko
306-
{:last-updated (fn [d] (str "마지막 업데이트 " ((tongue/inst-formatter "{year}년 {month-long} {day}일" inst-strings-ko) d)))
310+
{:last-modified (fn [d] (str "마지막 업데이트 " ((tongue/inst-formatter "{year}년 {month-long} {day}일" inst-strings-ko) d)))
307311
:main-title "우리 ASVA 평가 페이지에 오신 것을 환영합니다"
308312
:preface-1 "우리의 사명은 우리 서비스에 강력한 보안 관행을 통합하는 것입니다. 이 평가는"
309313
:preface-link-1 "OWASP의 ASVA 가이드라인"

src/asva/icons.cljs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,7 @@
7070
[:path {:d "M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2z"}]
7171
[:path {:d "M12 11v6"}]
7272
[:path {:d "M9.5 13.5l2.5 -2.5l2.5 2.5"}]]))
73+
74+
(defn recurring [params]
75+
(into [svg (merge-with into {:class [:recurring]} params)]
76+
[[:path {:stroke-linecap "round" :stroke-linejoin "round" :d "M19.5 12c0-1.232-.046-2.453-.138-3.662a4.006 4.006 0 0 0-3.7-3.7 48.678 48.678 0 0 0-7.324 0 4.006 4.006 0 0 0-3.7 3.7c-.017.22-.032.441-.046.662M19.5 12l3-3m-3 3-3-3m-12 3c0 1.232.046 2.453.138 3.662a4.006 4.006 0 0 0 3.7 3.7 48.656 48.656 0 0 0 7.324 0 4.006 4.006 0 0 0 3.7-3.7c.017-.22.032-.441.046-.662M4.5 12l3 3m-3-3-3 3"}]]))

src/asva/utils.cljc

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@
88

99
(defn assoc-event-db
1010
"Associates a value into the given re-frame app-db at a specified path.
11-
11+
1212
Takes a re-frame `db` and `args`, where the last element of `args`
1313
is the value to associate, and the remaining elements define the
1414
nested keys at which to place that value.
15-
15+
1616
Usage:
1717
(re-frame/reg-event-db ::some-event assoc-event-db)
18-
18+
1919
Example:
20-
If `db` is {:a {:b {:c 0}}}, and `args` is [:a :b :c 1],
20+
If `db` is {:a {:b {:c 0}}}, and `args` is [:a :b :c 1],
2121
the resulting db will be {:a {:b {:c 1}}}."
2222
[db args] (assoc-in db (pop args) (peek args)))
2323

@@ -93,7 +93,7 @@
9393
~'inner-html (.-innerHTML ~'target)]
9494
~@body)))))
9595

96-
;; REVIEW I’m reconsidering the utility of `dispatch>e`.
96+
;; REVIEW I’m reconsidering the utility of `dispatch>e`.
9797
;; | While `e>` is beneficial for general event-handler scenarios, `dispatch>e` is
9898
;; | limited to situations where a re-frame event is dispatched. This could be
9999
;; | efficiently handled with `(e> (dispatch [:key]))`, provided we adhere to the
@@ -133,5 +133,7 @@
133133
(defn key->prop [key]
134134
(kebab-to-pascal (name key)))
135135

136+
#?(:cljs (defn now [] (.toISOString (js/Date.))))
137+
136138
#?(:cljs (defn ->clj [x] (bean/->clj x :prop->key prop->key :key->prop key->prop)))
137139
#?(:cljs (defn ->js [x] (bean/->js x :prop->key prop->key :key->prop key->prop)))

0 commit comments

Comments
 (0)