@@ -282,7 +282,9 @@ defmodule PlausibleWeb.StatsController do
282282 )
283283
284284 if shared_link do
285- new_link_format = Routes . stats_path ( conn , :shared_link , shared_link . site . domain , auth: slug )
285+ new_link_format =
286+ Routes . stats_path ( conn , :shared_link , shared_link . site . domain , [ ] , auth: slug )
287+
286288 redirect ( conn , to: new_link_format )
287289 else
288290 render_error ( conn , 404 )
@@ -306,6 +308,15 @@ defmodule PlausibleWeb.StatsController do
306308 defp render_password_protected_shared_link ( conn , shared_link ) do
307309 conn = Plug.Conn . fetch_cookies ( conn )
308310
311+ star_path = conn . path_params [ "path" ]
312+
313+ star_path_fragment = serialize_star_path_as_query_string_fragment ( star_path )
314+
315+ query_string =
316+ [ conn . query_string , star_path_fragment ]
317+ |> Enum . filter ( fn v -> is_binary ( v ) and String . length ( v ) > 0 end )
318+ |> Enum . join ( "&" )
319+
309320 case validate_shared_link_password ( conn , shared_link ) do
310321 { :ok , shared_link } ->
311322 render_shared_link ( conn , shared_link )
@@ -314,7 +325,7 @@ defmodule PlausibleWeb.StatsController do
314325 conn
315326 |> render ( "shared_link_password.html" ,
316327 link: shared_link ,
317- query_string: conn . query_string ,
328+ query_string: query_string ,
318329 dogfood_page_path: "/share/:dashboard"
319330 )
320331 end
@@ -349,12 +360,23 @@ defmodule PlausibleWeb.StatsController do
349360 if Plausible.Auth.Password . match? ( password , shared_link . password_hash ) do
350361 token = Plausible.Auth.Token . sign_shared_link ( slug )
351362
363+ star_path = parse_star_path ( conn )
364+
365+ query_string_fragment =
366+ get_rest_of_query_string ( conn ) |> omit_from_query_string ( "return_to" )
367+
352368 conn
353369 |> put_resp_cookie ( shared_link_cookie_name ( slug ) , token )
354370 |> redirect (
355371 to:
356- Routes . stats_path ( conn , :shared_link , shared_link . site . domain , auth: slug ) <>
357- qs_appendix ( conn )
372+ Routes . stats_path (
373+ conn ,
374+ :shared_link ,
375+ shared_link . site . domain ,
376+ star_path ,
377+ auth: slug
378+ ) <>
379+ query_string_fragment
358380 )
359381 else
360382 conn
@@ -370,12 +392,47 @@ defmodule PlausibleWeb.StatsController do
370392 end
371393 end
372394
373- def qs_appendix ( conn )
374- when is_nil ( conn . query_string ) or
375- ( is_binary ( conn . query_string ) and byte_size ( conn . query_string ) ) == 0 ,
376- do: ""
395+ defp serialize_star_path_as_query_string_fragment ( star_path ) do
396+ if length ( star_path ) > 0 do
397+ # make the path start with a /
398+ # to be able to reject values that don't start with a /
399+ serialized_value =
400+ "/#{ Enum . join ( star_path , "/" ) } "
401+ |> PlausibleWeb.URIEncoding . uri_encode_permissive ( )
377402
378- def qs_appendix ( conn ) , do: "&#{ conn . query_string } "
403+ "return_to=#{ serialized_value } "
404+ else
405+ nil
406+ end
407+ end
408+
409+ defp parse_star_path ( conn ) do
410+ return_to_value = conn . query_params [ "return_to" ]
411+
412+ if not is_nil ( return_to_value ) and String . starts_with? ( return_to_value , "/" ) do
413+ # get rid of the / character that we added
414+ "/" <> trimmed_return_to_value = return_to_value
415+ String . split ( trimmed_return_to_value , "/" )
416+ else
417+ [ ]
418+ end
419+ end
420+
421+ defp get_rest_of_query_string ( conn )
422+ when is_nil ( conn . query_string ) or
423+ ( is_binary ( conn . query_string ) and byte_size ( conn . query_string ) ) == 0 ,
424+ do: ""
425+
426+ defp get_rest_of_query_string ( conn ) , do: "&#{ conn . query_string } "
427+
428+ defp omit_from_query_string ( query_string , key ) do
429+ query_string
430+ |> String . split ( "&" )
431+ |> Enum . reject ( fn key_and_value ->
432+ key_and_value == key || String . starts_with? ( key_and_value , key )
433+ end )
434+ |> Enum . join ( "&" )
435+ end
379436
380437 defp render_shared_link ( conn , shared_link ) do
381438 shared_links_feature_access? =
0 commit comments