diff --git a/.gitignore b/.gitignore index d186e5b..07c8651 100644 --- a/.gitignore +++ b/.gitignore @@ -32,5 +32,6 @@ npm-debug.log # we ignore priv/static. You may want to comment # this depending on your deployment strategy. /priv/static/ +/priv/cert/ dev.secret.exs \ No newline at end of file diff --git a/README.md b/README.md index 5af4e0c..b99d5ef 100644 --- a/README.md +++ b/README.md @@ -5,16 +5,29 @@ To start your Phoenix server: * Install dependencies with `mix deps.get` * Create and migrate your database with `mix ecto.setup` * Install Node.js dependencies with `npm install` inside the `assets` directory + * Run `mix phx.gen.cert` to use HTTPS during development, required for OAuth * Start Phoenix endpoint with `mix phx.server` Now you can visit [`localhost:4000`](http://localhost:4000) from your browser. Ready to run in production? Please [check our deployment guides](https://hexdocs.pm/phoenix/deployment.html). -## Learn more +## Setting up OAuth - * Official website: https://www.phoenixframework.org/ - * Guides: https://hexdocs.pm/phoenix/overview.html - * Docs: https://hexdocs.pm/phoenix - * Forum: https://elixirforum.com/c/phoenix-forum - * Source: https://github.com/phoenixframework/phoenix +Add the OAuth providers you'll be using to the providers array. + +``` +use Mix.Config +config :ueberauth, Ueberauth, + providers: [ + github: {Ueberauth.Strategy.Github, []} + ] +``` + +You'll need to visit each provider's site and set up OAuth. This usually entails creating an OAuth App to generate a client_id, and generating a client_secret. Then create a `dev.secret.exs` file in your config folder and add your client_id & secret to your provider's ueberauth config. + +``` +config :ueberauth, Ueberauth.Strategy.Github.OAuth, + client_id: "some_client_id", + client_secret: "some_secret_key" +``` diff --git a/config/config.exs b/config/config.exs index c69b935..dc21086 100644 --- a/config/config.exs +++ b/config/config.exs @@ -26,6 +26,11 @@ config :logger, :console, # Use Jason for JSON parsing in Phoenix config :phoenix, :json_library, Jason +config :ueberauth, Ueberauth, + providers: [ + github: {Ueberauth.Strategy.Github, [default_scope: "user:email", allow_private_emails: true]} + ] + # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. import_config "#{Mix.env()}.exs" diff --git a/config/dev.exs b/config/dev.exs index 32f7656..82dcb83 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -17,6 +17,12 @@ config :entendu, Entendu.Repo, # with webpack to recompile .js and .css sources. config :entendu, EntenduWeb.Endpoint, http: [port: System.get_env("PORT", "4000")], + https: [ + port: 4001, + cipher_suite: :strong, + certfile: "priv/cert/selfsigned.pem", + keyfile: "priv/cert/selfsigned_key.pem" + ], debug_errors: true, code_reloader: true, check_origin: false, diff --git a/lib/entendu/application.ex b/lib/entendu/application.ex index 6236043..0f4c3fc 100644 --- a/lib/entendu/application.ex +++ b/lib/entendu/application.ex @@ -6,12 +6,6 @@ defmodule Entendu.Application do use Application def start(_type, _args) do - # topologies = [ - # chat: [ - # strategy: Cluster.Strategy.Gossip - # ] - # ] - topologies = [ k8s_entendu: [ strategy: Elixir.Cluster.Strategy.Kubernetes.DNS, diff --git a/lib/entendu/user_from_auth.ex b/lib/entendu/user_from_auth.ex index e69de29..ac67147 100644 --- a/lib/entendu/user_from_auth.ex +++ b/lib/entendu/user_from_auth.ex @@ -0,0 +1,47 @@ +defmodule Entendu.UserFromAuth do + @moduledoc """ + Retrieve the user information from an auth request + """ + require Logger + require Jason + + alias Ueberauth.Auth + + def find_or_create(%Auth{} = auth) do + {:ok, basic_info(auth)} + end + + # github does it this way + defp avatar_from_auth(%{info: %{urls: %{avatar_url: image}}}), do: image + + # facebook does it this way + defp avatar_from_auth(%{info: %{image: image}}), do: image + + # default case if nothing matches + defp avatar_from_auth(auth) do + Logger.warn("#{auth.provider} needs to find an avatar URL!") + Logger.debug(Jason.encode!(auth)) + nil + end + + defp basic_info(auth) do + IO.inspect(auth) + %{id: auth.uid, name: name_from_auth(auth), avatar: avatar_from_auth(auth)} + end + + defp name_from_auth(auth) do + if auth.info.name do + auth.info.name + else + name = + [auth.info.first_name, auth.info.last_name] + |> Enum.filter(&(&1 != nil and &1 != "")) + + if Enum.empty?(name) do + auth.info.nickname + else + Enum.join(name, " ") + end + end + end +end diff --git a/lib/entendu_web/controllers/auth_controller.ex b/lib/entendu_web/controllers/auth_controller.ex new file mode 100644 index 0000000..a92017b --- /dev/null +++ b/lib/entendu_web/controllers/auth_controller.ex @@ -0,0 +1,41 @@ +defmodule EntenduWeb.AuthController do + @moduledoc """ + Auth controller responsible for handling Ueberauth responses + """ + + use EntenduWeb, :controller + + plug Ueberauth + + alias Ueberauth.Strategy.Helpers + alias Entendu.UserFromAuth + + def delete(conn, _params) do + conn + |> put_flash(:info, "You have been logged out!") + |> clear_session() + |> redirect(to: "/") + end + + def callback(%{assigns: %{ueberauth_failure: _fails}} = conn, _params) do + conn + |> put_flash(:error, "Failed to authenticate.") + |> redirect(to: "/") + end + + def callback(%{assigns: %{ueberauth_auth: auth}} = conn, _params) do + case UserFromAuth.find_or_create(auth) do + {:ok, user} -> + conn + |> put_flash(:info, "Successfully authenticated.") + |> put_session(:current_user, user) + |> configure_session(renew: true) + |> redirect(to: "/") + + {:error, reason} -> + conn + |> put_flash(:error, reason) + |> redirect(to: "/") + end + end +end diff --git a/lib/entendu_web/controllers/link_controller.ex b/lib/entendu_web/controllers/link_controller.ex new file mode 100644 index 0000000..7803b49 --- /dev/null +++ b/lib/entendu_web/controllers/link_controller.ex @@ -0,0 +1,11 @@ +defmodule EntenduWeb.LinkController do + @moduledoc """ + Controller responsible for managing links responses + """ + + use EntenduWeb, :controller + + def just(conn, _params) do + render(conn, "just.html") + end +end diff --git a/lib/entendu_web/controllers/page_controller.ex b/lib/entendu_web/controllers/page_controller.ex new file mode 100644 index 0000000..796e15d --- /dev/null +++ b/lib/entendu_web/controllers/page_controller.ex @@ -0,0 +1,11 @@ +defmodule EntenduWeb.PageController do + @moduledoc """ + Static page controller + """ + + use EntenduWeb, :controller + + def index(conn, _params) do + render(conn, "index.html", current_user: get_session(conn, :current_user)) + end +end diff --git a/lib/entendu_web/live/link_live/for.ex b/lib/entendu_web/live/link_live/for.ex deleted file mode 100644 index 8ab29b3..0000000 --- a/lib/entendu_web/live/link_live/for.ex +++ /dev/null @@ -1,13 +0,0 @@ -defmodule EntenduWeb.LinkLive.For do - use EntenduWeb, :live_view - - @impl true - def mount(_params, _session, socket) do - {:ok, socket |> assign(:step, 1)} - end - - def handle_event("next_step", _, %{ assigns: %{ step: step } } = socket) do - socket = socket |> assign(:step, step + 1) - {:noreply, socket} - end -end diff --git a/lib/entendu_web/live/link_live/for.html.leex b/lib/entendu_web/live/link_live/for.html.leex deleted file mode 100644 index 41c7e79..0000000 --- a/lib/entendu_web/live/link_live/for.html.leex +++ /dev/null @@ -1,4 +0,0 @@ -

Create Link

- -<%= live_component @socket, EntenduWeb.LinkLive.For.Step1Component, id: "step1", test: "test" %> -On Step: <%= @step %> diff --git a/lib/entendu_web/live/link_live/index.ex b/lib/entendu_web/live/link_live/index.ex deleted file mode 100644 index 62df978..0000000 --- a/lib/entendu_web/live/link_live/index.ex +++ /dev/null @@ -1,46 +0,0 @@ -defmodule EntenduWeb.LinkLive.Index do - use EntenduWeb, :live_view - - alias Entendu.Links - alias Entendu.Links.Link - - @impl true - def mount(_params, _session, socket) do - {:ok, assign(socket, :links, list_links())} - end - - @impl true - def handle_params(params, _url, socket) do - {:noreply, apply_action(socket, socket.assigns.live_action, params)} - end - - defp apply_action(socket, :edit, %{"id" => id}) do - socket - |> assign(:page_title, "Edit Link") - |> assign(:link, Links.get_link!(id)) - end - - defp apply_action(socket, :new, _params) do - socket - |> assign(:page_title, "New Link") - |> assign(:link, %Link{}) - end - - defp apply_action(socket, :index, _params) do - socket - |> assign(:page_title, "Listing Links") - |> assign(:link, nil) - end - - @impl true - def handle_event("delete", %{"id" => id}, socket) do - link = Links.get_link!(id) - {:ok, _} = Links.delete_link(link) - - {:noreply, assign(socket, :links, list_links())} - end - - defp list_links do - Links.list_links() - end -end diff --git a/lib/entendu_web/live/link_live/index.html.leex b/lib/entendu_web/live/link_live/index.html.leex deleted file mode 100644 index 39a842f..0000000 --- a/lib/entendu_web/live/link_live/index.html.leex +++ /dev/null @@ -1,37 +0,0 @@ -

Listing Links

- -<%= if @live_action in [:new, :edit] do %> - <%= live_modal @socket, EntenduWeb.LinkLive.FormComponent, - id: @link.id || :new, - title: @page_title, - action: @live_action, - link: @link, - return_to: Routes.link_index_path(@socket, :index) %> -<% end %> - - - - - - - - - - - - <%= for link <- @links do %> - - - - - - - <% end %> - -
ExpiresBurn after reading
- -<%= live_patch "New Link", to: Routes.link_index_path(@socket, :new) %> diff --git a/lib/entendu_web/live/link_live/steps/step1_component.ex b/lib/entendu_web/live/link_live/steps/step1_component.ex deleted file mode 100644 index 8bd000f..0000000 --- a/lib/entendu_web/live/link_live/steps/step1_component.ex +++ /dev/null @@ -1,4 +0,0 @@ -defmodule EntenduWeb.LinkLive.For.Step1Component do - use EntenduWeb, :live_component - -end diff --git a/lib/entendu_web/live/link_live/steps/step1_component.html.leex b/lib/entendu_web/live/link_live/steps/step1_component.html.leex deleted file mode 100644 index 36dc1be..0000000 --- a/lib/entendu_web/live/link_live/steps/step1_component.html.leex +++ /dev/null @@ -1,3 +0,0 @@ -This is step 1. <%= @test %> - - diff --git a/lib/entendu_web/live/page_live.ex b/lib/entendu_web/live/page_live.ex deleted file mode 100644 index 5d7d02d..0000000 --- a/lib/entendu_web/live/page_live.ex +++ /dev/null @@ -1,39 +0,0 @@ -defmodule EntenduWeb.PageLive do - use EntenduWeb, :live_view - - @impl true - def mount(_params, _session, socket) do - {:ok, assign(socket, query: "", results: %{})} - end - - @impl true - def handle_event("suggest", %{"q" => query}, socket) do - {:noreply, assign(socket, results: search(query), query: query)} - end - - @impl true - def handle_event("search", %{"q" => query}, socket) do - case search(query) do - %{^query => vsn} -> - {:noreply, redirect(socket, external: "https://hexdocs.pm/#{query}/#{vsn}")} - - _ -> - {:noreply, - socket - |> put_flash(:error, "No dependencies found matching \"#{query}\"") - |> assign(results: %{}, query: query)} - end - end - - defp search(query) do - if not EntenduWeb.Endpoint.config(:code_reloader) do - raise "action disabled when not in development" - end - - for {app, desc, vsn} <- Application.started_applications(), - app = to_string(app), - String.starts_with?(app, query) and not List.starts_with?(desc, ~c"ERTS"), - into: %{}, - do: {app, vsn} - end -end diff --git a/lib/entendu_web/live/page_live.html.leex b/lib/entendu_web/live/page_live.html.leex deleted file mode 100644 index ee59e54..0000000 --- a/lib/entendu_web/live/page_live.html.leex +++ /dev/null @@ -1,18 +0,0 @@ -
-

<%= gettext "Welcome to %{name}!", name: "Phoenix" %>

-

Peace of mind from prototype to production

- -
- - - <%= for {app, _vsn} <- @results do %> - - <% end %> - - -
-
- -
- Links -
diff --git a/lib/entendu_web/router.ex b/lib/entendu_web/router.ex index 8855bcd..db5f4ba 100644 --- a/lib/entendu_web/router.ex +++ b/lib/entendu_web/router.ex @@ -17,8 +17,16 @@ defmodule EntenduWeb.Router do scope "/", EntenduWeb do pipe_through :browser - live "/", PageLive, :index - live "/for", LinkLive.For + get "/", PageController, :index + get "/just", LinkController, :just + end + + scope "/auth", EntenduWeb do + pipe_through :browser + + get "/:provider", AuthController, :request + get "/:provider/callback", AuthController, :callback + delete "/logout", AuthController, :delete end # Other scopes may use custom stacks. diff --git a/lib/entendu_web/templates/link/just.html.eex b/lib/entendu_web/templates/link/just.html.eex new file mode 100644 index 0000000..0489925 --- /dev/null +++ b/lib/entendu_web/templates/link/just.html.eex @@ -0,0 +1,6 @@ +
+

Create a secret!

+

There will be a form here

+

And a file input here

+

Then a next button

+
diff --git a/lib/entendu_web/templates/page/index.html.eex b/lib/entendu_web/templates/page/index.html.eex new file mode 100644 index 0000000..66d392e --- /dev/null +++ b/lib/entendu_web/templates/page/index.html.eex @@ -0,0 +1,49 @@ +
+

Überauth + Phoenix Example

+

+ This is an application to show an example of how to wire up + Überauth with + Phoenix. +

+ <%= if @current_user do %> +

Welcome, <%= @current_user.name %>!

+
+ +
+ <%= link "Logout", to: Routes.auth_path(@conn, :delete), method: "delete", class: "button" %> +
+ <% else %> + + <% end %> +
diff --git a/lib/entendu_web/views/link_view.ex b/lib/entendu_web/views/link_view.ex new file mode 100644 index 0000000..e0a7af1 --- /dev/null +++ b/lib/entendu_web/views/link_view.ex @@ -0,0 +1,3 @@ +defmodule EntenduWeb.LinkView do + use EntenduWeb, :view +end diff --git a/lib/entendu_web/views/page_view.ex b/lib/entendu_web/views/page_view.ex new file mode 100644 index 0000000..636bf57 --- /dev/null +++ b/lib/entendu_web/views/page_view.ex @@ -0,0 +1,3 @@ +defmodule EntenduWeb.PageView do + use EntenduWeb, :view +end diff --git a/mix.exs b/mix.exs index 5696c69..c8d07ef 100644 --- a/mix.exs +++ b/mix.exs @@ -48,7 +48,8 @@ defmodule Entendu.MixProject do {:jason, "~> 1.0"}, {:plug_cowboy, "~> 2.0"}, {:libcluster, "~> 3.2"}, - {:ueberauth, "~> 0.6.3"} + {:ueberauth, "~> 0.7.0"}, + {:ueberauth_github, "~> 0.8.1"} ] end diff --git a/mix.lock b/mix.lock index ed168fb..4ea7ce5 100644 --- a/mix.lock +++ b/mix.lock @@ -1,4 +1,5 @@ %{ + "certifi": {:hex, :certifi, "2.8.0", "d4fb0a6bb20b7c9c3643e22507e42f356ac090a1dcea9ab99e27e0376d695eba", [:rebar3], [], "hexpm", "6ac7efc1c6f8600b08d625292d4bbf584e14847ce1b6b5c44d983d273e1097ea"}, "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"}, "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.1", "ebd1a1d7aff97f27c66654e78ece187abdc646992714164380d8a041eda16754", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a6efd3366130eab84ca372cbd4a7d3c3a97bdfcfb4911233b035d117063f0af"}, @@ -10,10 +11,16 @@ "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, "floki": {:hex, :floki, "0.31.0", "f05ee8a8e6a3ced4e62beeb2c79a63bc8e12ab98fbaaf6e6a3d9b76b1278e23f", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "b05afa372f5c345a5bf240ac25ea1f0f3d5fcfd7490ac0beeb4a203f9444891e"}, "gettext": {:hex, :gettext, "0.18.2", "7df3ea191bb56c0309c00a783334b288d08a879f53a7014341284635850a6e55", [:mix], [], "hexpm", "f9f537b13d4fdd30f3039d33cb80144c3aa1f8d9698e47d7bcbcc8df93b1f5c5"}, + "hackney": {:hex, :hackney, "1.18.0", "c4443d960bb9fba6d01161d01cd81173089686717d9490e5d3606644c48d121f", [:rebar3], [{:certifi, "~>2.8.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "9afcda620704d720db8c6a3123e9848d09c87586dc1c10479c42627b905b5c5e"}, "html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"}, + "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"}, "libcluster": {:hex, :libcluster, "3.3.0", "f7d45ff56d88e9fb4c30aee662480cbab69ebc0e7f7da4ad8d01b1e4f7492da8", [:mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "ecdcdc88334ec8eb18b10a13a1d5f22a3319a970b5b1e66cfe71c7719a4ab6cc"}, - "mime": {:hex, :mime, "2.0.1", "0de4c81303fe07806ebc2494d5321ce8fb4df106e34dd5f9d787b637ebadc256", [:mix], [], "hexpm", "7a86b920d2aedce5fb6280ac8261ac1a739ae6c1a1ad38f5eadf910063008942"}, + "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, + "mime": {:hex, :mime, "2.0.2", "0b9e1a4c840eafb68d820b0e2158ef5c49385d17fb36855ac6e7e087d4b1dcc5", [:mix], [], "hexpm", "e6a3f76b4c277739e36c2e21a2c640778ba4c3846189d5ab19f97f126df5f9b7"}, + "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, + "oauth2": {:hex, :oauth2, "2.0.0", "338382079fe16c514420fa218b0903f8ad2d4bfc0ad0c9f988867dfa246731b0", [:mix], [{:hackney, "~> 1.13", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "881b8364ac7385f9fddc7949379cbe3f7081da37233a1aa7aab844670a91e7e7"}, + "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, "phoenix": {:hex, :phoenix, "1.5.10", "3ee7d5c17ff9626d72d374d8fc8909bf00f4323fd15549fbe3abbbd38b5299c8", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f9c2eaa5a8fe5a412610c6aa84ccdb6f3e92f333d4df7fbaeb0d5a157dbfb48d"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.3.0", "2c69a452c2e0ee8c93345ae1cdc1696ef4877ff9cbb15c305def41960c3c4ebf", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "0ac491924217550c8f42c81c1f390b5d81517d12ceaf9abf3e701156760a848e"}, "phoenix_html": {:hex, :phoenix_html, "2.14.3", "51f720d0d543e4e157ff06b65de38e13303d5778a7919bcc696599e5934271b8", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "efd697a7fff35a13eeeb6b43db884705cba353a1a41d127d118fda5f90c8e80f"}, @@ -26,8 +33,11 @@ "plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"}, "postgrex": {:hex, :postgrex, "0.15.10", "2809dee1b1d76f7cbabe570b2a9285c2e7b41be60cf792f5f2804a54b838a067", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "1560ca427542f6b213f8e281633ae1a3b31cdbcd84ebd7f50628765b8f6132be"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, + "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, "telemetry": {:hex, :telemetry, "0.4.3", "a06428a514bdbc63293cd9a6263aad00ddeb66f608163bdec7c8995784080818", [:rebar3], [], "hexpm", "eb72b8365ffda5bed68a620d1da88525e326cb82a75ee61354fc24b844768041"}, "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"}, "telemetry_poller": {:hex, :telemetry_poller, "0.5.1", "21071cc2e536810bac5628b935521ff3e28f0303e770951158c73eaaa01e962a", [:rebar3], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4cab72069210bc6e7a080cec9afffad1b33370149ed5d379b81c7c5f0c663fd4"}, - "ueberauth": {:hex, :ueberauth, "0.6.3", "d42ace28b870e8072cf30e32e385579c57b9cc96ec74fa1f30f30da9c14f3cc0", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "afc293d8a1140d6591b53e3eaf415ca92842cb1d32fad3c450c6f045f7f91b60"}, + "ueberauth": {:hex, :ueberauth, "0.7.0", "9c44f41798b5fa27f872561b6f7d2bb0f10f03fdd22b90f454232d7b087f4b75", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "2efad9022e949834f16cc52cd935165049d81fa9e925690f91035c2e4b58d905"}, + "ueberauth_github": {:hex, :ueberauth_github, "0.8.1", "0be487b5afc29bc805fa5e31636f37c8f09d5159ef73fc08c4c7a98c9cfe2c18", [:mix], [{:oauth2, "~> 1.0 or ~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.7.0", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "143d6130b945ea9bdbd0ef94987f40788f1d7e8090decbfc0722773155e7a74a"}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, }