@@ -66,6 +66,11 @@ defmodule Phoenix.HTML.Link do
66
66
config :phoenix_html, csrf_token_generator: {MyGenerator, :get_token, []}
67
67
68
68
"""
69
+ @ valid_uri_schemes [ "http:" , "https:" , "ftp:" , "ftps:" , "mailto:" ,
70
+ "news:" , "irc:" , "gopher:" , "nntp:" , "feed:" ,
71
+ "telnet:" , "mms:" , "rtsp:" , "svn:" , "tel:" , "fax:" ,
72
+ "xmpp:" ]
73
+
69
74
def link ( text , opts )
70
75
71
76
def link ( opts , do: contents ) when is_list ( opts ) do
@@ -78,6 +83,9 @@ defmodule Phoenix.HTML.Link do
78
83
79
84
def link ( text , opts ) do
80
85
{ to , opts } = pop_required_option! ( opts , :to , "expected non-nil value for :to in link/2" )
86
+
87
+ to = valid_destination! ( to , "link/2" )
88
+
81
89
{ method , opts } = Keyword . pop ( opts , :method , :get )
82
90
83
91
if method == :get do
@@ -129,6 +137,8 @@ defmodule Phoenix.HTML.Link do
129
137
{ to , opts } = pop_required_option! ( opts , :to , "option :to is required in button/2" )
130
138
{ method , opts } = Keyword . pop ( opts , :method , :post )
131
139
140
+ to = valid_destination! ( to , "button/2" )
141
+
132
142
if method == :get do
133
143
opts = skip_csrf ( opts )
134
144
content_tag ( :button , text , [ data: [ method: method , to: to ] ] ++ opts )
@@ -165,4 +175,33 @@ defmodule Phoenix.HTML.Link do
165
175
166
176
{ value , opts }
167
177
end
178
+
179
+ defp valid_destination! ( to , calling_func ) do
180
+ if invalid_destination? ( to ) do
181
+ raise ArgumentError , """
182
+ unsupported scheme given to #{ calling_func } . In case you want to link to an
183
+ unknown or unsafe scheme, such as javascript, use a tuple: {:javascript, rest}
184
+ """
185
+ end
186
+
187
+ valid_destination! ( to )
188
+ end
189
+ defp valid_destination! ( { :safe , to } ) do
190
+ { :safe , valid_destination! ( to ) }
191
+ end
192
+ defp valid_destination! ( { other , to } ) when is_atom ( other ) do
193
+ [ Atom . to_string ( other ) , ?: , to ]
194
+ end
195
+ defp valid_destination! ( to ) , do: to
196
+
197
+ for scheme <- @ valid_uri_schemes do
198
+ defp invalid_destination? ( unquote ( scheme ) <> _ ) , do: false
199
+ end
200
+ defp invalid_destination? ( { scheme , _ } ) when is_atom ( scheme ) do
201
+ false
202
+ end
203
+ defp invalid_destination? ( to ) when is_binary ( to ) do
204
+ String . contains? ( to , ":" )
205
+ end
206
+ defp invalid_destination? ( _ ) , do: true
168
207
end
0 commit comments