From 089816845e9532f562d83f89cc30ef8374b1cd93 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 22 Apr 2024 18:45:42 -0400 Subject: [PATCH 1/4] Silence any lint on window.location mock --- assets/js/__tests__/ujs.spec.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/assets/js/__tests__/ujs.spec.ts b/assets/js/__tests__/ujs.spec.ts index 7f87b766..cef79c14 100644 --- a/assets/js/__tests__/ujs.spec.ts +++ b/assets/js/__tests__/ujs.spec.ts @@ -117,6 +117,7 @@ describe('Remote utilities', () => { // https://www.benmvp.com/blog/mocking-window-location-methods-jest-jsdom/ let oldWindowLocation: Location; + /* eslint-disable @typescript-eslint/no-explicit-any */ beforeAll(() => { oldWindowLocation = window.location; delete (window as any).location; @@ -136,6 +137,7 @@ describe('Remote utilities', () => { beforeEach(() => { (window.location.reload as any).mockReset(); }); + /* eslint-enable @typescript-eslint/no-explicit-any */ afterAll(() => { // restore window.location to the jsdom Location object From f1a75e87f235ded1770518b9919139188b6510b4 Mon Sep 17 00:00:00 2001 From: Liam Date: Sat, 27 Apr 2024 01:54:40 -0400 Subject: [PATCH 2/4] Fix escaping error --- lib/philomena_web/templates/channel/index.html.slime | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/philomena_web/templates/channel/index.html.slime b/lib/philomena_web/templates/channel/index.html.slime index 7cd341cb..7fd24c1c 100644 --- a/lib/philomena_web/templates/channel/index.html.slime +++ b/lib/philomena_web/templates/channel/index.html.slime @@ -37,6 +37,6 @@ p strong> Q: Do you host streams? | A: No, we cheat and just link to streams on Picarto since that's where (almost) everyone is already. This is simply a nice way to track streaming artists. p - strong> Q: How do I get my stream/a friend's stream/'s stream here? + strong> Q: How do I get my stream/a friend's stream/<artist>'s stream here? ' A: Send a private message to a site administrator ' with a link to the stream and the artist tag if applicable. From eb79ee45d2d6c76992d6c190ed4ce0b2e38a39e1 Mon Sep 17 00:00:00 2001 From: liamwhite Date: Sat, 27 Apr 2024 14:00:54 -0400 Subject: [PATCH 3/4] Tag change search (#234) * profile/tag_change: add search box to show only a single tag * Minor fixup --------- Co-authored-by: prg --- .../profile/tag_change_controller.ex | 23 ++++++++++++++++++- .../profile/tag_change/index.html.slime | 14 +++++------ 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/lib/philomena_web/controllers/profile/tag_change_controller.ex b/lib/philomena_web/controllers/profile/tag_change_controller.ex index 358990e6..21524d4b 100644 --- a/lib/philomena_web/controllers/profile/tag_change_controller.ex +++ b/lib/philomena_web/controllers/profile/tag_change_controller.ex @@ -3,6 +3,7 @@ defmodule PhilomenaWeb.Profile.TagChangeController do alias Philomena.Users.User alias Philomena.Images.Image + alias Philomena.Tags.Tag alias Philomena.TagChanges.TagChange alias Philomena.Repo import Ecto.Query @@ -16,19 +17,27 @@ defmodule PhilomenaWeb.Profile.TagChangeController do tag_changes = TagChange |> join(:inner, [tc], i in Image, on: tc.image_id == i.id) + |> only_tag_join(params) |> where( [tc, i], tc.user_id == ^user.id and not (i.user_id == ^user.id and i.anonymous == true) ) |> added_filter(params) + |> only_tag_filter(params) |> preload([:tag, :user, image: [:user, :sources, tags: :aliases]]) |> order_by(desc: :id) |> Repo.paginate(conn.assigns.scrivener) + # params.permit(:added, :only_tag) ... + pagination_params = + [added: conn.params["added"], only_tag: conn.params["only_tag"]] + |> Keyword.filter(fn {k, _v} -> Map.has_key?(conn.params, "#{k}") end) + render(conn, "index.html", title: "Tag Changes for User `#{user.name}'", user: user, - tag_changes: tag_changes + tag_changes: tag_changes, + pagination_params: pagination_params ) end @@ -40,4 +49,16 @@ defmodule PhilomenaWeb.Profile.TagChangeController do defp added_filter(query, _params), do: query + + defp only_tag_join(query, %{"only_tag" => only_tag}) when only_tag != "", + do: join(query, :inner, [tc], t in Tag, on: tc.tag_id == t.id) + + defp only_tag_join(query, _params), + do: query + + defp only_tag_filter(query, %{"only_tag" => only_tag}) when only_tag != "", + do: where(query, [_, _, t], t.name == ^only_tag) + + defp only_tag_filter(query, _params), + do: query end diff --git a/lib/philomena_web/templates/profile/tag_change/index.html.slime b/lib/philomena_web/templates/profile/tag_change/index.html.slime index 8fe9a9a4..563a7fc3 100644 --- a/lib/philomena_web/templates/profile/tag_change/index.html.slime +++ b/lib/philomena_web/templates/profile/tag_change/index.html.slime @@ -4,16 +4,16 @@ h1 = @user.name - route = fn p -> Routes.profile_tag_change_path(@conn, :index, @user, p) end -- params = if @conn.params["added"], do: [added: @conn.params["added"]] -- pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @tag_changes, route: route, conn: @conn, params: params +- pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @tag_changes, route: route, conn: @conn, params: @pagination_params .block .block__header - span.block__header__title - | Display only: + = form_for @conn, Routes.profile_tag_change_path(@conn, :index, @user), [method: "get", enforce_utf8: false], fn f -> + = text_input f, :only_tag, class: "input", placeholder: "Tag", title: "Only show this tag", autocapitalize: "none" + = submit "Search", class: "button", title: "Search" - = link "Removed", to: Routes.profile_tag_change_path(@conn, :index, @user, added: 0) - = link "Added", to: Routes.profile_tag_change_path(@conn, :index, @user, added: 1) - = link "All", to: Routes.profile_tag_change_path(@conn, :index, @user) + = link "Removed", to: Routes.profile_tag_change_path(@conn, :index, @user, Keyword.merge(@pagination_params, added: 0)) + = link "Added", to: Routes.profile_tag_change_path(@conn, :index, @user, Keyword.merge(@pagination_params, added: 1)) + = link "All", to: Routes.profile_tag_change_path(@conn, :index, @user, Keyword.delete(@pagination_params, :added)) = render PhilomenaWeb.TagChangeView, "index.html", conn: @conn, tag_changes: @tag_changes, pagination: pagination From 101aec001b8b5d854e629e2350eac4bbf92d8e69 Mon Sep 17 00:00:00 2001 From: liamwhite Date: Sat, 27 Apr 2024 14:01:02 -0400 Subject: [PATCH 4/4] Use modern Phoenix HTML escaping (#236) --- lib/philomena_web/markdown_renderer.ex | 13 ++++++------- lib/philomena_web/stats_updater.ex | 4 +++- lib/philomena_web/views/tag_view.ex | 4 ++++ 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/philomena_web/markdown_renderer.ex b/lib/philomena_web/markdown_renderer.ex index a37b1a42..508a960f 100644 --- a/lib/philomena_web/markdown_renderer.ex +++ b/lib/philomena_web/markdown_renderer.ex @@ -3,7 +3,6 @@ defmodule PhilomenaWeb.MarkdownRenderer do alias Philomena.Images.Image alias Philomena.Repo alias PhilomenaWeb.ImageView - import Phoenix.HTML import Phoenix.HTML.Link import Ecto.Query @@ -84,7 +83,6 @@ defmodule PhilomenaWeb.MarkdownRenderer do size: ImageView.select_version(img, :medium), conn: conn ) - |> safe_to_string() [_id, "t"] when not img.hidden_from_users and img.approved -> Phoenix.View.render(ImageView, "_image_target.html", @@ -93,7 +91,6 @@ defmodule PhilomenaWeb.MarkdownRenderer do size: ImageView.select_version(img, :small), conn: conn ) - |> safe_to_string() [_id, "s"] when not img.hidden_from_users and img.approved -> Phoenix.View.render(ImageView, "_image_target.html", @@ -102,18 +99,15 @@ defmodule PhilomenaWeb.MarkdownRenderer do size: ImageView.select_version(img, :thumb_small), conn: conn ) - |> safe_to_string() [_id, suffix] when not img.approved -> ">>#{img.id}#{suffix}#{link_suffix(img)}" [_id, ""] -> link(">>#{img.id}#{link_suffix(img)}", to: "/images/#{img.id}") - |> safe_to_string() [_id, suffix] when suffix in ["t", "s", "p"] -> link(">>#{img.id}#{suffix}#{link_suffix(img)}", to: "/images/#{img.id}") - |> safe_to_string() # This condition should never trigger, but let's leave it here just in case. [id, suffix] -> @@ -124,7 +118,12 @@ defmodule PhilomenaWeb.MarkdownRenderer do ">>#{text}" end - [text, rendered] + string_contents = + rendered + |> Phoenix.HTML.Safe.to_iodata() + |> IO.iodata_to_binary() + + [text, string_contents] end) |> Map.new(fn [id, html] -> {id, html} end) end diff --git a/lib/philomena_web/stats_updater.ex b/lib/philomena_web/stats_updater.ex index caecc6b6..dc53324d 100644 --- a/lib/philomena_web/stats_updater.ex +++ b/lib/philomena_web/stats_updater.ex @@ -45,13 +45,15 @@ defmodule PhilomenaWeb.StatsUpdater do distinct_creators: distinct_creators, images_in_galleries: images_in_galleries ) + |> Phoenix.HTML.Safe.to_iodata() + |> IO.iodata_to_binary() now = DateTime.utc_now() |> DateTime.truncate(:second) static_page = %{ title: "Statistics", slug: "stats", - body: Phoenix.HTML.safe_to_string(result), + body: result, created_at: now, updated_at: now } diff --git a/lib/philomena_web/views/tag_view.ex b/lib/philomena_web/views/tag_view.ex index ada8ffdd..bcbc1e22 100644 --- a/lib/philomena_web/views/tag_view.ex +++ b/lib/philomena_web/views/tag_view.ex @@ -103,6 +103,8 @@ defmodule PhilomenaWeb.TagView do {tags, shipping, data} end + # This is a rendered template, so raw/1 has no effect on safety + # sobelow_skip ["XSS.Raw"] defp render_quick_tags({tags, shipping, data}, conn) do render(PhilomenaWeb.TagView, "_quick_tag_table.html", tags: tags, @@ -110,6 +112,8 @@ defmodule PhilomenaWeb.TagView do data: data, conn: conn ) + |> Phoenix.HTML.Safe.to_iodata() + |> Phoenix.HTML.raw() end defp names_in_tab("default", data) do