Skip to content

Commit 2d63a5b

Browse files
committed
finish cleaning up Cache.Hash
1 parent 2f6df23 commit 2d63a5b

File tree

3 files changed

+160
-110
lines changed

3 files changed

+160
-110
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* Add Graph.modify/3 with a finder function
1414
* Rename Cache.request_notification/1 -> Cache.subscribe/1
1515
* Rename Cache.stop_notification/1 -> Cache.unsubscribe/1
16-
16+
* General cleanup of Scenic.Cache.Hash. Some functions removed. Some function signatures changed.
1717

1818
## 0.8.0
1919

lib/scenic/cache/hash.ex

Lines changed: 101 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,33 @@
55

66
defmodule Scenic.Cache.Hash do
77
@moduledoc """
8-
Ssimple functions to load a file, following the hashing rules
8+
Helper functions to work with hash signatures.
9+
10+
Both the [`Cache.File`](Scenic.Cache.File.html) and [`Cache.Term`](Scenic.Cache.Term.html)
11+
modules use cryptographic hash signatures to verify that files are valid before using
12+
the data they contain.
13+
14+
This modules provides a collection of helper functions that make it easy to use, generate
15+
and validate these hashes.
16+
17+
Any time one of these functions asks for a type of hash, the supported types are:
18+
`:sha`, `:sha224`, `:sha256`, `:sha384`, `:sha512`, and `:ripemd160`
919
"""
10-
# import IEx
1120

1221
@hash_types [:sha, :sha224, :sha256, :sha384, :sha512, :ripemd160]
1322
@default_hash :sha
1423

24+
@type hash_type ::
25+
:sha
26+
| :sha224
27+
| :sha256
28+
| :sha384
29+
| :sha512
30+
| :ripemd160
31+
32+
@type type_error :: {:error, :invalid_hash_type}
33+
@type hash_error :: {:error, :hash_failure}
34+
1535
# ===========================================================================
1636
defmodule Error do
1737
@moduledoc false
@@ -20,40 +40,56 @@ defmodule Scenic.Cache.Hash do
2040
end
2141

2242
# --------------------------------------------------------
43+
@doc false
44+
@deprecated "Cache.valid_hash_types/0 will be removed in 0.10.0"
2345
@spec valid_hash_types() :: [:ripemd160 | :sha | :sha224 | :sha256 | :sha384 | :sha512, ...]
2446
def valid_hash_types(), do: @hash_types
47+
2548
# --------------------------------------------------------
26-
@spec valid_hash_type?(any()) :: boolean()
27-
def valid_hash_type?(hash_type), do: Enum.member?(@hash_types, hash_type)
49+
@spec valid_hash_type?(type :: hash_type) :: boolean()
50+
defp valid_hash_type?(type), do: Enum.member?(@hash_types, type)
51+
2852
# --------------------------------------------------------
29-
@spec valid_hash_type!(any()) :: any() | no_return
30-
def valid_hash_type!(hash_type) do
31-
case Enum.member?(@hash_types, hash_type) do
53+
@spec valid_hash_type!(type :: hash_type) :: hash_type | no_return
54+
defp valid_hash_type!(type) do
55+
case Enum.member?(@hash_types, type) do
3256
true ->
33-
hash_type
57+
type
3458

3559
false ->
36-
msg = "Invalid hash type: #{hash_type}\r\n" <> "Must be one of: #{inspect(@hash_types)}"
60+
msg = "Invalid hash type: #{type}\r\n" <> "Must be one of: #{inspect(@hash_types)}"
3761
raise Error, message: msg
3862
end
3963
end
4064

4165
# --------------------------------------------------------
42-
@spec binary(any(), any()) :: {:error, :invalid_hash_type} | {:ok, binary()}
43-
def binary(data, hash_type) do
44-
case valid_hash_type?(hash_type) do
45-
true -> {:ok, hash_type |> :crypto.hash(data) |> Base.url_encode64(padding: false)}
66+
@doc """
67+
Calculate the hash of binary data
68+
69+
Returns the hash wrapped in a `{:ok, hash}` tuple.
70+
"""
71+
@spec binary(data :: binary, type :: hash_type) :: {:ok, bitstring()} | type_error
72+
def binary(data, type) do
73+
case valid_hash_type?(type) do
74+
true -> {:ok, type |> :crypto.hash(data) |> Base.url_encode64(padding: false)}
4675
false -> {:error, :invalid_hash_type}
4776
end
4877
end
4978

50-
def binary!(data, hash_type) do
51-
valid_hash_type!(hash_type)
79+
@doc """
80+
Calculate the hash of binary data
81+
82+
Returns the hash directly.
83+
"""
84+
@spec binary!(data :: binary, type :: hash_type) :: bitstring()
85+
def binary!(data, type) do
86+
valid_hash_type!(type)
5287
|> :crypto.hash(data)
5388
|> Base.url_encode64(padding: false)
5489
end
5590

5691
# --------------------------------------------------------
92+
@spec file(path :: bitstring, type :: hash_type) :: {:ok, bitstring()} | type_error
5793
def file(path, hash_type) do
5894
do_compute_file(
5995
path,
@@ -62,6 +98,7 @@ defmodule Scenic.Cache.Hash do
6298
)
6399
end
64100

101+
@spec file!(path :: bitstring, type :: hash_type) :: bitstring()
65102
def file!(path, hash_type) do
66103
# start the hash context
67104
hash_context =
@@ -103,6 +140,13 @@ defmodule Scenic.Cache.Hash do
103140
end
104141

105142
# --------------------------------------------------------
143+
@doc """
144+
Verify that the given data conforms to the given hash.
145+
146+
If the verification passes, returns `{:ok, data}`
147+
If it fails, returns `{:error, :hash_failure}`
148+
"""
149+
@spec verify(data :: binary, hash :: bitstring, type :: hash_type) :: {:ok, binary} | hash_error
106150
def verify(data, hash, hash_type) do
107151
case binary(data, hash_type) do
108152
{:ok, ^hash} -> {:ok, data}
@@ -111,6 +155,13 @@ defmodule Scenic.Cache.Hash do
111155
end
112156

113157
# --------------------------------------------------------
158+
@doc """
159+
Verify that the given data conforms to the given hash.
160+
161+
If the verification passes, returns the data unchanged.
162+
If it fails, raises an error
163+
"""
164+
@spec verify!(data :: binary, hash :: bitstring, type :: hash_type) :: binary | no_return
114165
def verify!(data, hash, hash_type) do
115166
case binary!(data, hash_type) == hash do
116167
true -> data
@@ -119,9 +170,13 @@ defmodule Scenic.Cache.Hash do
119170
end
120171

121172
# --------------------------------------------------------
122-
def verify_file(path_data), do: path_params(path_data) |> do_verify_file()
173+
@doc """
174+
Verify that the data in a file conforms to the given hash.
123175
124-
defp do_verify_file({path, hash, hash_type}) do
176+
If the verification passes, returns `{:ok, hash}`
177+
If it fails, returns `{:error, :hash_failure}`
178+
"""
179+
def verify_file(path, hash, hash_type) do
125180
case file(path, hash_type) do
126181
{:ok, computed_hash} ->
127182
case computed_hash == hash do
@@ -135,42 +190,46 @@ defmodule Scenic.Cache.Hash do
135190
end
136191

137192
# --------------------------------------------------------
138-
def verify_file!(path_data), do: path_params(path_data) |> do_verify_file!()
193+
@doc """
194+
Verify that the data in a file conforms to the given hash.
139195
140-
defp do_verify_file!({path, hash, hash_type}) do
196+
If the verification passes, returns the hash unchanged.
197+
If it fails, raises an error
198+
"""
199+
def verify_file!(path, hash, hash_type) do
141200
case file!(path, hash_type) == hash do
142201
true -> hash
143202
false -> raise Error
144203
end
145204
end
146205

147-
# --------------------------------------------------------
148-
def from_path(path) do
149-
path
150-
|> String.split(".")
151-
|> List.last()
152-
end
206+
# # --------------------------------------------------------
207+
# defp from_path(path) do
208+
# path
209+
# |> String.split(".")
210+
# |> List.last()
211+
# end
153212

154-
# --------------------------------------------------------
155-
def path_params(path)
213+
# # --------------------------------------------------------
214+
# defp path_params(path)
156215

157-
def path_params(path) when is_bitstring(path) do
158-
hash = from_path(path)
159-
path_params({path, hash, @default_hash})
160-
end
216+
# defp path_params(path) when is_bitstring(path) do
217+
# hash = from_path(path)
218+
# path_params({path, hash, @default_hash})
219+
# end
161220

162-
def path_params({path, hash_type}) when is_atom(hash_type) do
163-
hash = from_path(path)
164-
path_params({path, hash, hash_type})
165-
end
221+
# defp path_params({path, hash_type}) when is_atom(hash_type) do
222+
# hash = from_path(path)
223+
# path_params({path, hash, hash_type})
224+
# end
166225

167-
def path_params({path_or_data, hash}), do: path_params({path_or_data, hash, @default_hash})
226+
# defp path_params({path_or_data, hash}), do: path_params({path_or_data, hash, @default_hash})
168227

169-
def path_params({path_or_data, hash, hash_type})
170-
when is_binary(path_or_data) and is_bitstring(hash) and is_atom(hash_type) do
171-
{path_or_data, hash, valid_hash_type!(hash_type)}
172-
end
228+
# defp path_params({path_or_data, hash, hash_type})
229+
# when is_binary(path_or_data) and is_bitstring(hash) and is_atom(hash_type) do
230+
# {path_or_data, hash, valid_hash_type!(hash_type)}
231+
# end
173232

174-
def path_params(path_or_data, hash_or_type), do: path_params({path_or_data, hash_or_type})
175-
def path_params(path_or_data, hash, hash_type), do: path_params({path_or_data, hash, hash_type})
233+
# defp path_params(path_or_data, hash_or_type), do: path_params({path_or_data, hash_or_type})
234+
# defp path_params(path_or_data, hash, hash_type), do: path_params({path_or_data, hash, hash_type})
176235
end

0 commit comments

Comments
 (0)