@@ -29,7 +29,8 @@ See the [Documentation][docs] on HexDocs.
29
29
## Installation
30
30
31
31
To get started, add ` safeurl ` to your project dependencies in ` mix.exs ` . Optionally, you may
32
- also add ` HTTPoison ` to your dependencies for making requests directly through SafeURL:
32
+ also add [ ` HTTPoison ` ] [ lib-httpoison ] to your dependencies for making requests directly
33
+ through SafeURL:
33
34
34
35
``` elixir
35
36
def deps do
@@ -40,6 +41,8 @@ def deps do
40
41
end
41
42
```
42
43
44
+ To use SafeURL with your favorite HTTP Client, see the [ HTTP Clients] [ readme-http ] section.
45
+
43
46
<br >
44
47
45
48
51
54
CIDR ranges to the blocklist, or alternatively allow specific CIDR ranges to which the
52
55
application is allowed to make requests.
53
56
54
- You can use ` allowed?/2 ` or ` validate/2 ` to check if a URL is safe to call, or if you have
55
- the ` HTTPoison ` application available, just call it directly via ` get/4 ` which will validate
56
- it automatically before calling, and return an error if it is not.
57
-
57
+ You can use ` allowed?/2 ` or ` validate/2 ` to check if a URL is safe to call. If you have the
58
+ [ ` HTTPoison ` ] [ lib-httpoison ] application available, you can also call ` get/4 ` which will
59
+ validate the host automatically before making a web request, and return an error otherwise.
58
60
59
- ### Examples
60
61
61
62
``` elixir
62
63
iex> SafeURL .allowed? (" https://includesecurity.com" )
@@ -80,8 +81,12 @@ iex> SafeURL.get("https://google.com/")
80
81
{:ok , %HTTPoison .Response {.. .}}
81
82
```
82
83
84
+ <br >
85
+
83
86
84
- ### Configuration
87
+
88
+
89
+ ## Configuration
85
90
86
91
` SafeURL ` can be configured to customize and override validation behaviour by passing the
87
92
following options:
@@ -96,7 +101,8 @@ following options:
96
101
97
102
* ` :schemes ` - List of allowed URL schemes. Defaults to ` ["http, "https"] ` .
98
103
99
- * ` :dns_module ` - Any module that implements DNSResolver. Defaults to DNS from the ` dns ` package.
104
+ * ` :dns_module ` - Any module that implements the ` SafeURL.DNSResolver ` behaviour.
105
+ Defaults to ` DNS ` from the [ ` :dns ` ] [ lib-dns ] package.
100
106
101
107
These options can be passed to the function directly or set globally in your ` config.exs `
102
108
file:
@@ -105,15 +111,121 @@ file:
105
111
config :safeurl ,
106
112
block_reserved: true ,
107
113
blocklist: ~w[ 100.0.0.0/16] ,
108
- schemes: ~w[ https]
114
+ schemes: ~w[ https] ,
115
+ dns_module: MyCustomDNSResolver
109
116
```
110
117
111
118
Find detailed documentation on [ HexDocs] [ docs ] .
112
119
113
- <!--
114
- TODO: Add section explaining how to use SafeURL with various HTTP libraries
115
- such as HTTPoison, Tesla, etc. once we remove HTTPoison as a dependency.
116
- -->
120
+ <br >
121
+
122
+
123
+
124
+
125
+ ## HTTP Clients
126
+
127
+ While SafeURL already provides a convenient [ ` get/4 ` ] [ docs-get ] method to validate hosts
128
+ before making GET HTTP requests, you can also write your own wrappers, helpers or
129
+ middleware to work with the HTTP Client of your choice.
130
+
131
+
132
+ ### HTTPoison
133
+
134
+ For [ HTTPoison] [ lib-httpoison ] , you can create a wrapper module that validates hosts
135
+ before making HTTP requests:
136
+
137
+ ``` elixir
138
+ defmodule CustomClient do
139
+ def request (method, url, body, headers \\ [], opts \\ []) do
140
+ {safeurl_opts, opts} = Keyword .pop (opts, :safeurl , [])
141
+
142
+ with :ok <- SafeURL .validate (url, safeurl_opts) do
143
+ HTTPoison .request (method, url, body, headers, opts)
144
+ end
145
+ end
146
+
147
+ def get (url, headers \\ [], opts \\ []), do: request (:get , url, " " , headers, opts)
148
+ def post (url, body, headers \\ [], opts \\ []), do: request (:post , url, body, headers, opts)
149
+ # ...
150
+ end
151
+ ```
152
+
153
+ And you can use it as:
154
+
155
+ ``` elixir
156
+ iex> CustomClient .get (" http://230.10.10.10/data.json" , [], safeurl: [block_reserved: false ], recv_timeout: 500 )
157
+ {:ok , %HTTPoison .Response {.. .}}
158
+ ```
159
+
160
+
161
+ ### Tesla
162
+
163
+ For [ Tesla] [ lib-tesla ] , you can write a custom middleware to halt requests that are not
164
+ allowed:
165
+
166
+ ``` elixir
167
+ defmodule MyApp .Middleware .SafeURL do
168
+ @behaviour Tesla .Middleware
169
+
170
+ @impl true
171
+ def call (env, next, opts) do
172
+ with :ok <- SafeURL .validate (env.url, opts), do: Tesla .run (next)
173
+ end
174
+ end
175
+ ```
176
+
177
+ And you can plug it in anywhere you're using Tesla:
178
+
179
+ ``` elixir
180
+ defmodule DocumentService do
181
+ use Tesla
182
+
183
+ plug Tesla .Middleware .BaseUrl , " https://document-service/"
184
+ plug Tesla .Middleware .JSON
185
+ plug MyApp .Middleware .SafeURL , schemes: ~w[ https] , allowlist: [" 10.0.0.0/24" ]
186
+
187
+ def fetch (id) do
188
+ get (" /documents/#{ id } " )
189
+ end
190
+ end
191
+ ```
192
+
193
+ <br >
194
+
195
+
196
+
197
+
198
+ ## Custom DNS Resolver
199
+
200
+ In some cases you might want to use a custom strategy for DNS resolution. You can do so by
201
+ passing your own implementation of [ ` SafeURL.DNSResolver ` ] [ docs-dns ] in the global or local
202
+ config.
203
+
204
+ Example use-cases of this are:
205
+
206
+ - Using a specific DNS server
207
+ - Avoiding network access in specific environments
208
+ - Mocking DNS resolution in tests
209
+
210
+ You can do so by implementing ` DNSResolver ` :
211
+
212
+
213
+ ``` elixir
214
+ defmodule TestDNSResolver do
215
+ @behaviour SafeURL .DNSResolver
216
+
217
+ @impl true
218
+ def resolve (" google.com" ), do: {:ok , [{192 , 168 , 1 , 10 }]}
219
+ def resolve (" github.com" ), do: {:ok , [{192 , 168 , 1 , 20 }]}
220
+ def resolve (_domain ), do: {:ok , [{192 , 168 , 1 , 99 }]}
221
+ end
222
+ ```
223
+
224
+ ``` elixir
225
+ config :safeurl , dns_module: TestDNSResolver
226
+ ```
227
+
228
+ For more examples, see [ ` SafeURL.DNSResolver ` ] [ docs-dns ] docs.
117
229
118
230
<br >
119
231
@@ -149,9 +261,14 @@ This package is available as open source under the terms of the [MIT License][gi
149
261
[ hexpm ] : https://hex.pm/packages/safeurl
150
262
[ github-license ] : https://github.com/slab/safeurl-elixir/blob/master/LICENSE
151
263
[ github-fork ] : https://github.com/slab/safeurl-elixir/fork
152
-
153
- [ docs ] : https://hexdocs.pm/safeurl
154
264
[ slab ] : https://slab.com/
155
265
[ includesecurity ] : https://github.com/IncludeSecurity
266
+ [ readme-http ] : #http-clients
156
267
268
+ [ docs ] : https://hexdocs.pm/safeurl
269
+ [ docs-get ] : https://hexdocs.pm/safeurl/SafeURL.html#get/4
270
+ [ docs-dns ] : https://hexdocs.pm/safeurl/SafeURL.DNSResolver.html
157
271
272
+ [ lib-dns ] : https://github.com/tungd/elixir-dns
273
+ [ lib-tesla ] : https://github.com/elixir-tesla/tesla
274
+ [ lib-httpoison ] : https://github.com/edgurgel/httpoison
0 commit comments