From 5f593dfaf2b39c7949f2b0d69fd656b9331d44ec Mon Sep 17 00:00:00 2001 From: Chris McCord Date: Fri, 5 Nov 2021 23:02:31 -0400 Subject: [PATCH] Lock files behind temporary token --- .gitignore | 2 +- assets/js/app.js | 9 +++++---- config/dev.exs | 6 ++++++ lib/live_beats/media_library.ex | 4 ++++ lib/live_beats/media_library/song.ex | 13 ++++++++++--- lib/live_beats_web/controllers/file_controller.ex | 13 +++++++++++++ lib/live_beats_web/live/player_live.ex | 4 +++- lib/live_beats_web/router.ex | 2 ++ .../repo/migrations/20211027201102_create_songs.exs | 3 ++- 9 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 lib/live_beats_web/controllers/file_controller.ex diff --git a/.gitignore b/.gitignore index 830a9fa..996b81b 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,4 @@ live_beats-*.tar npm-debug.log /assets/node_modules/ -/priv/static/uploads +/priv/uploads diff --git a/assets/js/app.js b/assets/js/app.js index c7ab771..4b098f3 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -38,12 +38,13 @@ Hooks.AudioPlayer = { this.play() } }) - this.handleEvent("play", ({url, elapsed}) => { + this.handleEvent("play", ({url, token, elapsed}) => { this.playbackBeganAt = nowSeconds() - elapsed - if(this.player.src === url && this.player.paused){ + let currentSrc = this.player.src.split("?")[0] + if(currentSrc === url && this.player.paused){ this.play({sync: true}) - } else if(this.player.src !== url) { - this.player.src = url + } else if(currentSrc !== url) { + this.player.src = `${url}?token=${token}` this.play({sync: true}) } }) diff --git a/config/dev.exs b/config/dev.exs index 6dbbf40..5b22073 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -1,5 +1,11 @@ import Config +config :live_beats, :file_host, %{ + scheme: "http", + host: "localhost", + port: 4000 +} + config :live_beats, :github, %{ client_id: "83806139172df82d4ccc", client_secret: System.fetch_env!("LIVE_BEATS_GITHUB_CLIENT_SECRET"), diff --git a/lib/live_beats/media_library.ex b/lib/live_beats/media_library.ex index aba6671..8cfbf8e 100644 --- a/lib/live_beats/media_library.ex +++ b/lib/live_beats/media_library.ex @@ -19,6 +19,10 @@ defmodule LiveBeats.MediaLibrary do Phoenix.PubSub.subscribe(@pubsub, topic(user.id)) end + def local_filepath(filename_uuid) when is_binary(filename_uuid) do + Path.join("priv/uploads/songs", filename_uuid) + end + def play_song(%Song{id: id}), do: play_song(id) def play_song(id) do diff --git a/lib/live_beats/media_library/song.ex b/lib/live_beats/media_library/song.ex index 3859d4c..206940b 100644 --- a/lib/live_beats/media_library/song.ex +++ b/lib/live_beats/media_library/song.ex @@ -15,8 +15,9 @@ defmodule LiveBeats.MediaLibrary.Song do field :duration, :integer field :status, Ecto.Enum, values: [stopped: 1, playing: 2, paused: 3] field :title, :string - field :mp3_path, :string + field :mp3_url, :string field :mp3_filepath, :string + field :mp3_filename, :string belongs_to :user, Accounts.User belongs_to :genre, LiveBeats.MediaLibrary.Genre @@ -42,13 +43,19 @@ defmodule LiveBeats.MediaLibrary.Song do def put_mp3_path(%Ecto.Changeset{} = changeset) do if changeset.valid? do filename = Ecto.UUID.generate() <> ".mp3" - filepath = Path.join("priv/static/uploads/songs", filename) + filepath = LiveBeats.MediaLibrary.local_filepath(filename) changeset + |> Ecto.Changeset.put_change(:mp3_filename, filename) |> Ecto.Changeset.put_change(:mp3_filepath, filepath) - |> Ecto.Changeset.put_change(:mp3_path, Path.join("uploads/songs", filename)) + |> Ecto.Changeset.put_change(:mp3_url, mp3_url(filename)) else changeset end end + + defp mp3_url(filename) do + %{scheme: scheme, host: host, port: port} = Application.fetch_env!(:live_beats, :file_host) + URI.to_string(%URI{scheme: scheme, host: host, port: port, path: "/files/#{filename}"}) + end end diff --git a/lib/live_beats_web/controllers/file_controller.ex b/lib/live_beats_web/controllers/file_controller.ex new file mode 100644 index 0000000..1db590b --- /dev/null +++ b/lib/live_beats_web/controllers/file_controller.ex @@ -0,0 +1,13 @@ +defmodule LiveBeatsWeb.FileController do + use LiveBeatsWeb, :controller + + alias LiveBeats.MediaLibrary + + def show(conn, %{"id" => filename_uuid, "token" => token}) do + case Phoenix.Token.verify(conn, "file", token, max_age: :timer.minutes(10)) do + {:ok, ^filename_uuid} -> send_file(conn, 200, MediaLibrary.local_filepath(filename_uuid)) + {:ok, _} -> send_resp(conn, :unauthorized, "") + {:error, _} -> send_resp(conn, :unauthorized, "") + end + end +end diff --git a/lib/live_beats_web/live/player_live.ex b/lib/live_beats_web/live/player_live.ex index b8e03d9..09dbfd9 100644 --- a/lib/live_beats_web/live/player_live.ex +++ b/lib/live_beats_web/live/player_live.ex @@ -192,10 +192,12 @@ defmodule LiveBeatsWeb.PlayerLive do end defp push_play(socket, %Song{} = song, elapsed) do + token = Phoenix.Token.sign(socket.endpoint, "file", song.mp3_filename) push_event(socket, "play", %{ paused: Song.paused?(song), elapsed: elapsed, - url: Path.join(LiveBeatsWeb.Endpoint.url(), song.mp3_path) + token: token, + url: song.mp3_url }) end end diff --git a/lib/live_beats_web/router.ex b/lib/live_beats_web/router.ex index 1c440b2..1039ad9 100644 --- a/lib/live_beats_web/router.ex +++ b/lib/live_beats_web/router.ex @@ -19,6 +19,8 @@ defmodule LiveBeatsWeb.Router do scope "/", LiveBeatsWeb do pipe_through :browser + get "/files/:id", FileController, :show + delete "/signout", OAuthCallbackController, :sign_out live_session :default, on_mount: [{LiveBeatsWeb.UserAuth, :current_user}, LiveBeatsWeb.Nav] do diff --git a/priv/repo/migrations/20211027201102_create_songs.exs b/priv/repo/migrations/20211027201102_create_songs.exs index 54a2a19..3da4df1 100644 --- a/priv/repo/migrations/20211027201102_create_songs.exs +++ b/priv/repo/migrations/20211027201102_create_songs.exs @@ -10,7 +10,8 @@ defmodule LiveBeats.Repo.Migrations.CreateSongs do add :played_at, :utc_datetime add :paused_at, :utc_datetime add :title, :string, null: false - add :mp3_path, :string, null: false + add :mp3_url, :string, null: false + add :mp3_filename, :string, null: false add :mp3_filepath, :string, null: false add :date_recorded, :naive_datetime add :date_released, :naive_datetime