add waffle library, handle file upload, authenticate user with oauth and see if they have the link's email associated to their account

This commit is contained in:
2022-02-13 00:20:21 -05:00
parent 5de53e23ea
commit cac3757723
20 changed files with 305 additions and 94 deletions

View File

@@ -1,5 +1,7 @@
defmodule Entendu.Links.Link do
use Ecto.Schema
use Waffle.Ecto.Schema
alias Entendu.EncryptedLink
import Ecto.Changeset
@primary_key {:id, Ecto.UUID, autogenerate: true}
@@ -9,8 +11,8 @@ defmodule Entendu.Links.Link do
field :expires, :utc_datetime
field :filename, :string
field :filetype, :string
field :text_content, :string
field :file_content, :string
field :text_content, EncryptedLink.Type
field :file_content, EncryptedLink.Type
field :recipient, :string
field :service, :string
@@ -25,10 +27,10 @@ defmodule Entendu.Links.Link do
:burn_after_reading,
:filename,
:filetype,
:text_content,
:file_content,
:recipient,
:service
])
|> cast_attachments(attrs, [:text_content, :file_content])
end
end

View File

@@ -6,6 +6,7 @@ defmodule Entendu.UserFromAuth do
require Jason
alias Ueberauth.Auth
alias Entendu.Links.Link
def find_or_create(%Auth{} = auth) do
{:ok, basic_info(auth)}
@@ -24,9 +25,15 @@ defmodule Entendu.UserFromAuth do
nil
end
defp emails_from_auth(%Auth{ extra: %Auth.Extra{ raw_info: %{ user: %{ "emails" => emails}}}}), do: emails
defp emails_from_auth(%Auth{ info: %{ email: email }}), do: [email]
defp emails_from_auth(_auth), do: []
defp basic_info(auth) do
IO.inspect(auth)
%{id: auth.uid, name: name_from_auth(auth), avatar: avatar_from_auth(auth)}
%{id: auth.uid, name: name_from_auth(auth), avatar: avatar_from_auth(auth), emails: emails_from_auth(auth)}
end
defp name_from_auth(auth) do
@@ -44,4 +51,9 @@ defmodule Entendu.UserFromAuth do
end
end
end
def can_access?(recipient, emails) do
emails
|> Enum.any?(&( &1["verified"] == true and &1["email"] == recipient))
end
end

View File

@@ -23,18 +23,27 @@ defmodule EntenduWeb.AuthController do
end
def callback(%{assigns: %{ueberauth_auth: auth}} = conn, _params) do
case UserFromAuth.find_or_create(auth) do
{:ok, user} ->
# TODO: turn this into plug that only proceeds if current_link session var exists
%{ id: link_id, recipient: recipient } = get_session(conn, :current_link)
with {:ok, user} <- UserFromAuth.find_or_create(auth),
true <- UserFromAuth.can_access?(recipient, user.emails) do
# TODO: send over encrypted data that the frontend can decrypt
conn
|> put_flash(:info, "Successfully authenticated.")
|> put_session(:current_user, user)
|> configure_session(renew: true)
|> redirect(to: "/")
|> redirect(to: "/just/for/you/#{link_id}")
else
false ->
conn
|> put_flash(:error, "#{recipient} was not found in your list of verified emails")
|> redirect(to: "/just/for/you/#{link_id}")
{:error, reason} ->
conn
|> put_flash(:error, reason)
|> redirect(to: "/")
|> redirect(to: "/just/for/you/#{link_id}")
end
end
end

View File

@@ -8,7 +8,6 @@ defmodule EntenduWeb.LinkController do
alias Entendu.Links
alias Links.Link
alias Ecto.Changeset
alias EntenduWeb.FallbackController
action_fallback(FallbackController)
@@ -17,23 +16,13 @@ defmodule EntenduWeb.LinkController do
render(conn, "just.html")
end
defparams(
first_step(%{
burn_after_reading: [field: :boolean, default: false],
expires: :utc_datetime,
filename: :string,
filetype: :string,
text_content: :string,
file_content: :string
})
)
def just(conn, params) do
with %Changeset{valid?: true} = changeset <- first_step(params),
link_params <- Params.to_map(changeset),
{:ok, %Link{} = link} <- Links.create_link(link_params) do
with {:ok, %Link{} = link} <- Links.create_link(params) do
conn
|> render("show_authorized.json", %{link: link})
else
test ->
IO.inspect(test)
end
end
@@ -41,18 +30,9 @@ defmodule EntenduWeb.LinkController do
render(conn, "for.html")
end
defparams(
second_step(%{
service: :string,
recipient: :string
})
)
def for(conn, %{link_id: link_id} = params) do
with %Changeset{valid?: true} = changeset <- first_step(params),
link_params <- Params.to_map(changeset),
%Link{} = link <- Links.get_link(link_id),
Links.update_link(link, link_params) do
def for(conn, %{"link_id" => link_id, "recipient" => recipient, "service" => service}) do
with %Link{} = link <- Links.get_link(link_id),
Links.update_link(link, %{ recipient: recipient, service: service}) do
conn
|> render("show_authorized.json", %{link: link})
end
@@ -61,4 +41,12 @@ defmodule EntenduWeb.LinkController do
def you_page(conn, _params) do
render(conn, "you.html")
end
def auth_page(conn, %{ "id" => link_id}) do
with %Link{service: service, recipient: recipient} = link <- Links.get_link(link_id) do
conn
|> put_session(:current_link, link)
|> render("auth.html", %{ service: service, recipient: recipient })
end
end
end

View File

@@ -23,6 +23,7 @@ defmodule EntenduWeb.Router do
get "/just/for", LinkController, :for_page
post "/just/for", LinkController, :for
get "/just/for/you", LinkController, :you_page
get "/just/for/you/:id", LinkController, :auth_page
end
scope "/auth", EntenduWeb do

View File

@@ -0,0 +1 @@
<%= react_component("Components.AuthPage", %{ csrf: Plug.CSRFProtection.get_csrf_token(), service: @service, recipient: @recipient, user: @current_user }) %>

View File

@@ -1 +1 @@
<%= react_component("Components.ForPage") %>
<%= react_component("Components.ForPage", %{ csrf: Plug.CSRFProtection.get_csrf_token() }) %>

View File

@@ -0,0 +1,56 @@
defmodule Entendu.EncryptedLink do
use Waffle.Definition
use Waffle.Ecto.Definition
# Include ecto support (requires package waffle_ecto installed):
# use Waffle.Ecto.Definition
@versions [:original]
# To add a thumbnail version:
# @versions [:original, :thumb]
# Override the bucket on a per definition basis:
# def bucket do
# :custom_bucket_name
# end
# Whitelist file extensions:
# def validate({file, _}) do
# file_extension = file.file_name |> Path.extname() |> String.downcase()
#
# case Enum.member?(~w(.jpg .jpeg .gif .png), file_extension) do
# true -> :ok
# false -> {:error, "invalid file type"}
# end
# end
# Define a thumbnail transformation:
# def transform(:thumb, _) do
# {:convert, "-strip -thumbnail 250x250^ -gravity center -extent 250x250 -format png", :png}
# end
# Override the persisted filenames:
# def filename(version, _) do
# version
# end
# Override the storage directory:
# def storage_dir(version, {file, scope}) do
# "uploads/user/avatars/#{scope.id}"
# end
# Provide a default URL if there hasn't been a file uploaded
# def default_url(version, scope) do
# "/images/avatars/default_#{version}.png"
# end
# Specify custom headers for s3 objects
# Available options are [:cache_control, :content_disposition,
# :content_encoding, :content_length, :content_type,
# :expect, :expires, :storage_class, :website_redirect_location]
#
# def s3_object_headers(version, {file, scope}) do
# [content_type: MIME.from_path(file.file_name)]
# end
end