-
Notifications
You must be signed in to change notification settings - Fork 1
/
check.clj
77 lines (68 loc) · 3.01 KB
/
check.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
(ns com.eldrix.trud.impl.check
"Check provides support for validating downloaded TRUD files.
There are three mechanisms for checking the integrity of downloaded files.
1. Checksum (hash)
2. Signature (GPG)
3. The use of https to download the files.
It appears as if checksums are generated using a Windows command line tool
called FCIV (https://docs.microsoft.com/en-us/troubleshoot/windows-server/windows-security/fciv-availability-and-description).
<?XML version=\"1.0\" encoding=\"utf-8\"?>
<FCIV>
<FILE_ENTRY>
<name>ntdll.dll</name> <MD5>bL/ZGbqnyeA8hHGuTY+LsA==</MD5>
</FILE_ENTRY>
</FCIV>
It appears that FCIV generates only MD5 and SHA1 hashes."
(:require [clojure.data.xml :as xml]
[clojure.java.io :as io]
[clojure.string :as str]
[clojure.zip :as zip]
[clojure.data.zip.xml :as zx]
[buddy.core.codecs :as codecs]
[buddy.core.hash :as hash]
[hato.client :as hc])
(:import (java.io File)))
(defn- parse-fciv-file-entry [loc]
(let [props (:content (zip/node loc))]
(apply hash-map (interleave (map :tag props) (map (comp first :content) props)))))
(defn- fetch-fciv
"Fetch and parse a FCIV XML structure from the URL specified.
Returns a map keyed by filename. Each value is itself a map with keys
as the type of hash (`:MD5` or `:SHA1` at the time of writing) and the
actual hash as the value."
[url]
(let [fciv (-> (hc/get url {:http-client {:redirect-policy :normal}})
:body
xml/parse-str
zip/xml-zip
(zx/xml-> :FCIV :FILE_ENTRY parse-fciv-file-entry))]
(apply hash-map (mapcat #(vector (:name %) (dissoc % :name)) fciv))))
(defn valid-checksum?
"Determines whether the file specified has a valid checksum.
Note: if we do not support a checksum type, then we return `true` with a
warning."
[{:keys [checksumFileUrl archiveFileName] :as _release} ^File downloaded-file]
(let [fciv (fetch-fciv checksumFileUrl)
filename archiveFileName]
(loop [props (get fciv filename)]
(if-not props
(do (println "Warning: unable to validate checksum: no supported checksum available.\nPublished checksums:" fciv)
true)
(let [[k v] (first props)
engine (hash/resolve-digest-engine (keyword (str/lower-case (name k))))]
(if engine
(let [calc (-> downloaded-file
io/input-stream
(hash/-digest engine)
codecs/bytes->b64
codecs/bytes->str)]
(= v calc))
(recur (next props))))))))
(comment
(def api-key (slurp "api-key.txt"))
(require '[com.eldrix.trud.impl.release :as release])
(release/get-releases api-key 341)
(def release (release/get-latest api-key 341))
release
(fetch-fciv (:checksumFileUrl release))
(valid-checksum? release (File. "/tmp/trud/341--2021-01-29--hscorgrefdataxml_data_1.0.0_20210129000001.zip")))