@@ -29,7 +29,8 @@ See the [Documentation][docs] on HexDocs.
2929## Installation
3030
3131To 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:
3334
3435``` elixir
3536def deps do
@@ -40,6 +41,8 @@ def deps do
4041end
4142```
4243
44+ To use SafeURL with your favorite HTTP Client, see the [ HTTP Clients] [ readme-http ] section.
45+
4346<br >
4447
4548
5154CIDR ranges to the blocklist, or alternatively allow specific CIDR ranges to which the
5255application is allowed to make requests.
5356
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.
5860
59- ### Examples
6061
6162``` elixir
6263iex> SafeURL .allowed? (" https://includesecurity.com" )
@@ -80,8 +81,12 @@ iex> SafeURL.get("https://google.com/")
8081{:ok , %HTTPoison .Response {.. .}}
8182```
8283
84+ <br >
85+
8386
84- ### Configuration
87+
88+
89+ ## Configuration
8590
8691` SafeURL ` can be configured to customize and override validation behaviour by passing the
8792following options:
@@ -96,7 +101,8 @@ following options:
96101
97102 * ` :schemes ` - List of allowed URL schemes. Defaults to ` ["http, "https"] ` .
98103
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.
100106
101107These options can be passed to the function directly or set globally in your ` config.exs `
102108file:
@@ -105,15 +111,121 @@ file:
105111config :safeurl ,
106112 block_reserved: true ,
107113 blocklist: ~w[ 100.0.0.0/16] ,
108- schemes: ~w[ https]
114+ schemes: ~w[ https] ,
115+ dns_module: MyCustomDNSResolver
109116```
110117
111118Find detailed documentation on [ HexDocs] [ docs ] .
112119
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.
117229
118230<br >
119231
@@ -149,9 +261,14 @@ This package is available as open source under the terms of the [MIT License][gi
149261[ hexpm ] : https://hex.pm/packages/safeurl
150262[ github-license ] : https://github.com/slab/safeurl-elixir/blob/master/LICENSE
151263[ github-fork ] : https://github.com/slab/safeurl-elixir/fork
152-
153- [ docs ] : https://hexdocs.pm/safeurl
154264[ slab ] : https://slab.com/
155265[ includesecurity ] : https://github.com/IncludeSecurity
266+ [ readme-http ] : #http-clients
156267
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
157271
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