From 7b3824456863efd21644cdb7423d84051676f9da Mon Sep 17 00:00:00 2001 From: trueChazza Date: Tue, 27 Jun 2023 21:21:20 +1200 Subject: [PATCH 01/14] build: add oauth2 --- mix.exs | 3 ++- mix.lock | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index 27e7d798..fe8493c1 100644 --- a/mix.exs +++ b/mix.exs @@ -59,7 +59,8 @@ defmodule MediaServer.MixProject do {:cors_plug, "~> 3.0"}, {:scrivener, "~> 2.0"}, {:extitles, "~> 0.1.0"}, - {:exstream, "~> 0.20.0"} + {:exstream, "~> 0.20.0"}, + {:oauth2, "~> 2.0"} ] end diff --git a/mix.lock b/mix.lock index aae3beef..1393f9a3 100644 --- a/mix.lock +++ b/mix.lock @@ -31,9 +31,12 @@ "httpoison": {:hex, :httpoison, "2.1.0", "655fd9a7b0b95ee3e9a3b535cf7ac8e08ef5229bab187fa86ac4208b122d934b", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "fc455cb4306b43827def4f57299b2d5ac8ac331cb23f517e734a4b78210a160c"}, "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.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"}, + "jose": {:hex, :jose, "1.11.5", "3bc2d75ffa5e2c941ca93e5696b54978323191988eb8d225c2e663ddfefd515e", [:mix, :rebar3], [], "hexpm", "dcd3b215bafe02ea7c5b23dafd3eb8062a5cd8f2d904fd9caa323d37034ab384"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, + "oauth2": {:hex, :oauth2, "2.1.0", "beb657f393814a3a7a8a15bd5e5776ecae341fd344df425342a3b6f1904c2989", [:mix], [{:tesla, "~> 1.5", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "8ac07f85b3307dd1acfeb0ec852f64161b22f57d0ce0c15e616a1dfc8ebe2b41"}, + "openid_connect": {:hex, :openid_connect, "0.2.2", "c05055363330deab39ffd89e609db6b37752f255a93802006d83b45596189c0b", [:mix], [{:httpoison, "~> 1.2", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: false]}, {:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "735769b6d592124b58edd0582554ce638524c0214cd783d8903d33357d74cc13"}, "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, "phoenix": {:hex, :phoenix, "1.7.6", "61f0625af7c1d1923d582470446de29b008c0e07ae33d7a3859ede247ddaf59a", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "f6b4be7780402bb060cbc6e83f1b6d3f5673b674ba73cc4a7dd47db0322dfb88"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.2", "b21bd01fdeffcfe2fab49e4942aa938b6d3e89e93a480d4aee58085560a0bc0d", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "70242edd4601d50b69273b057ecf7b684644c19ee750989fd555625ae4ce8f5d"}, @@ -58,6 +61,7 @@ "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, "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, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"}, + "tesla": {:hex, :tesla, "1.7.0", "a62dda2f80d4f8a925eb7b8c5b78c461e0eb996672719fe1a63b26321a5f8b4e", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "2e64f01ebfdb026209b47bc651a0e65203fcff4ae79c11efb73c4852b00dc313"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, "websock": {:hex, :websock, "0.5.2", "b3c08511d8d79ed2c2f589ff430bd1fe799bb389686dafce86d28801783d8351", [:mix], [], "hexpm", "925f5de22fca6813dfa980fb62fd542ec43a2d1a1f83d2caec907483fe66ff05"}, "websock_adapter": {:hex, :websock_adapter, "0.5.3", "4908718e42e4a548fc20e00e70848620a92f11f7a6add8cf0886c4232267498d", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "cbe5b814c1f86b6ea002b52dd99f345aeecf1a1a6964e209d208fb404d930d3d"}, From 60df3cd0366c11973e70a65282fe7e939bf48399 Mon Sep 17 00:00:00 2001 From: trueChazza Date: Tue, 27 Jun 2023 21:22:05 +1200 Subject: [PATCH 02/14] feat: add initial flow --- config/dev.exs | 5 ++ .../controllers/auth_controller.ex | 64 +++++++++++++++++++ lib/media_server_web/oauth/github.ex | 45 +++++++++++++ lib/media_server_web/router.ex | 8 +++ 4 files changed, 122 insertions(+) create mode 100644 lib/media_server_web/controllers/auth_controller.ex create mode 100644 lib/media_server_web/oauth/github.ex diff --git a/config/dev.exs b/config/dev.exs index e02d6d44..e3173fc4 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -69,3 +69,8 @@ config :phoenix, :stacktrace_depth, 20 # Initialize plugs at runtime for faster development compilation config :phoenix, :plug_init_mode, :runtime + +config :media_server, GitHub, + client_id: System.get_env("GITHUB_CLIENT_ID"), + client_secret: System.get_env("GITHUB_CLIENT_SECRET"), + redirect_uri: System.get_env("GITHUB_REDIRECT_URI") \ No newline at end of file diff --git a/lib/media_server_web/controllers/auth_controller.ex b/lib/media_server_web/controllers/auth_controller.ex new file mode 100644 index 00000000..dc3fb153 --- /dev/null +++ b/lib/media_server_web/controllers/auth_controller.ex @@ -0,0 +1,64 @@ +defmodule MediaServerWeb.AuthController do + use MediaServerWeb, :controller + + @doc """ + This action is reached via `/auth/:provider` and redirects to the OAuth2 provider + based on the chosen strategy. + """ + def index(conn, %{"provider" => provider}) do + redirect conn, external: authorize_url!(provider) + end + + def delete(conn, _params) do + conn + |> put_flash(:info, "You have been logged out!") + |> configure_session(drop: true) + |> redirect(to: "/") + end + + @doc """ + This action is reached via `/auth/:provider/callback` is the callback URL that + the OAuth2 provider will redirect the user back to with a `code` that will + be used to request an access token. The access token will then be used to + access protected resources on behalf of the user. + """ + def callback(conn, %{"provider" => provider, "code" => code}) do + # Exchange an auth code for an access token + client = get_token!(provider, code) + + # Request the user's data with the access token + user = get_user!(provider, client) + + # Store the user in the session under `:current_user` and redirect to /. + # In most cases, we'd probably just store the user's ID that can be used + # to fetch from the database. In this case, since this example app has no + # database, I'm just storing the user map. + # + # If you need to make additional resource requests, you may want to store + # the access token as well. + conn + |> put_session(:current_user, user) + |> put_session(:access_token, client.token.access_token) + |> redirect(to: "/") + end + + defp authorize_url!("github"), do: GitHub.authorize_url! + defp authorize_url!(_), do: raise "No matching provider available" + + defp get_token!("github", code), do: GitHub.get_token!(code: code) + defp get_token!(_, _), do: raise "No matching provider available" + + defp get_user!("github", client) do + + token = Map.get(client, :token) |> Map.get(:access_token) |> Jason.decode! |> Map.get("access_token") + + %{body: user} = OAuth2.Client.get!(client, "/user", [ + {"user-agent", "midarr"}, + {"authorization", "Bearer #{ token }"} + ]) + + decoded_user = Jason.decode!(user) |> IO.inspect + + %{name: decoded_user["name"], avatar: decoded_user["avatar_url"]} + end +end \ No newline at end of file diff --git a/lib/media_server_web/oauth/github.ex b/lib/media_server_web/oauth/github.ex new file mode 100644 index 00000000..00cb9749 --- /dev/null +++ b/lib/media_server_web/oauth/github.ex @@ -0,0 +1,45 @@ +defmodule GitHub do + @moduledoc """ + An OAuth2 strategy for GitHub. + """ + use OAuth2.Strategy + + alias OAuth2.Strategy.AuthCode + + defp config do + [ + strategy: GitHub, + site: "https://api.github.com", + authorize_url: "https://github.com/login/oauth/authorize", + token_url: "https://github.com/login/oauth/access_token" + ] + end + + # Public API + + def client do + Application.get_env(:media_server, GitHub) + |> Keyword.merge(config()) + |> OAuth2.Client.new() + end + + def authorize_url!(params \\ []) do + OAuth2.Client.authorize_url!(client(), params) + end + + def get_token!(params \\ [], headers \\ []) do + OAuth2.Client.get_token!(client(), Keyword.merge(params, client_secret: client().client_secret)) + end + + # Strategy Callbacks + + def authorize_url(client, params) do + AuthCode.authorize_url(client, params) + end + + def get_token(client, params, headers) do + client + |> put_header("Accept", "application/json") + |> AuthCode.get_token(params, headers) + end +end \ No newline at end of file diff --git a/lib/media_server_web/router.ex b/lib/media_server_web/router.ex index 1ab8c34d..9d8228ef 100644 --- a/lib/media_server_web/router.ex +++ b/lib/media_server_web/router.ex @@ -26,6 +26,14 @@ defmodule MediaServerWeb.Router do post "/login", UserSessionController, :create end + scope "/auth", MediaServerWeb do + pipe_through :browser + + get "/:provider", AuthController, :index + get "/:provider/callback", AuthController, :callback + delete "/logout", AuthController, :delete + end + scope "/", MediaServerWeb do pipe_through [:browser, :require_authenticated_user] From 6e089f4d658093f920d7875093fb71eab55acb33 Mon Sep 17 00:00:00 2001 From: trueChazza Date: Wed, 28 Jun 2023 17:55:24 +1200 Subject: [PATCH 03/14] feat: add oauth authentik --- .env.example | 2 + .gitignore | 1 + config/dev.exs | 7 +- docker-compose.yml | 89 ++++++++++++++++++- .../controllers/auth_controller.ex | 27 +++--- lib/media_server_web/oauth/authentik.ex | 42 +++++++++ lib/media_server_web/oauth/github.ex | 45 ---------- 7 files changed, 144 insertions(+), 69 deletions(-) create mode 100644 .env.example create mode 100644 lib/media_server_web/oauth/authentik.ex delete mode 100644 lib/media_server_web/oauth/github.ex diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..990d571f --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +PG_PASS=password +AUTHENTIK_SECRET_KEY=password \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5e03b145..2813bfe5 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,4 @@ npm-debug.log /.idea /lib/media_server/release.ex /rel/overlays/bin/ +.env \ No newline at end of file diff --git a/config/dev.exs b/config/dev.exs index e3173fc4..7e072c5d 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -68,9 +68,4 @@ config :logger, :console, format: "[$level] $message\n" config :phoenix, :stacktrace_depth, 20 # Initialize plugs at runtime for faster development compilation -config :phoenix, :plug_init_mode, :runtime - -config :media_server, GitHub, - client_id: System.get_env("GITHUB_CLIENT_ID"), - client_secret: System.get_env("GITHUB_CLIENT_SECRET"), - redirect_uri: System.get_env("GITHUB_REDIRECT_URI") \ No newline at end of file +config :phoenix, :plug_init_mode, :runtime \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index b4649d16..e0d63769 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,3 +1,11 @@ +version: "3.4" + +volumes: + database: + driver: local + redis: + driver: local + services: midarr: @@ -21,6 +29,14 @@ services: - SETUP_ADMIN_NAME=admin - SETUP_ADMIN_PASSWORD=passwordpassword + - OAUTH_ISSUER_URL=http://localhost:9000 + - OAUTH_AUTHORIZE_URL=http://localhost:9000/application/o/authorize/ + - OAUTH_TOKEN_URL=http://server-authentik:9000/application/o/token/ + - OAUTH_CLIENT_ID=someClientId + - OAUTH_CLIENT_SECRET=someClientSecret + - OAUTH_REDIRECT_URI=http://localhost:4000/auth/authentik/callback + - OAUTH_USER_URL=http://server-authentik:9000/application/o/userinfo/ + - RADARR_BASE_URL=http://radarr:7878 - RADARR_API_KEY=d031e8c9b9df4b2fab311d1c3b3fa2c5 - SONARR_BASE_URL=http://sonarr:8989 @@ -84,4 +100,75 @@ services: - PUID=1000 - PGID=1000 healthcheck: - test: "exit 0" \ No newline at end of file + test: "exit 0" + + postgresql-authentik: + image: docker.io/library/postgres:12-alpine + healthcheck: + test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"] + start_period: 20s + interval: 30s + retries: 5 + timeout: 5s + volumes: + - database:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: ${PG_PASS:?database password required} + POSTGRES_USER: ${PG_USER:-authentik} + POSTGRES_DB: ${PG_DB:-authentik} + env_file: + - .env + + redis-authentik: + image: docker.io/library/redis:alpine + command: --save 60 1 --loglevel warning + healthcheck: + test: [ "CMD-SHELL", "redis-cli ping | grep PONG" ] + start_period: 20s + interval: 30s + retries: 5 + timeout: 3s + volumes: + - redis:/data + + server-authentik: + image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.5.3} + command: server + environment: + AUTHENTIK_REDIS__HOST: redis-authentik + AUTHENTIK_POSTGRESQL__HOST: postgresql-authentik + AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik} + AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik} + AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS} + env_file: + - .env + ports: + - "${COMPOSE_PORT_HTTP:-9000}:9000" + - "${COMPOSE_PORT_HTTPS:-9443}:9443" + depends_on: + - postgresql-authentik + - redis-authentik + + worker: + image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.5.3} + command: worker + environment: + AUTHENTIK_REDIS__HOST: redis-authentik + AUTHENTIK_POSTGRESQL__HOST: postgresql-authentik + AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik} + AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik} + AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS} + # `user: root` and the docker socket volume are optional. + # See more for the docker socket integration here: + # https://goauthentik.io/docs/outposts/integrations/docker + # Removing `user: root` also prevents the worker from fixing the permissions + # on the mounted folders, so when removing this make sure the folders have the correct UID/GID + # (1000:1000 by default) + user: root + volumes: + - /var/run/docker.sock:/var/run/docker.sock + env_file: + - .env + depends_on: + - postgresql-authentik + - redis-authentik \ No newline at end of file diff --git a/lib/media_server_web/controllers/auth_controller.ex b/lib/media_server_web/controllers/auth_controller.ex index dc3fb153..98ae2d20 100644 --- a/lib/media_server_web/controllers/auth_controller.ex +++ b/lib/media_server_web/controllers/auth_controller.ex @@ -27,38 +27,31 @@ defmodule MediaServerWeb.AuthController do client = get_token!(provider, code) # Request the user's data with the access token - user = get_user!(provider, client) + if user = MediaServer.Accounts.get_user_by_email(get_user!(provider, client).email) do + + MediaServerWeb.UserAuth.log_in_user(conn, user) + end - # Store the user in the session under `:current_user` and redirect to /. - # In most cases, we'd probably just store the user's ID that can be used - # to fetch from the database. In this case, since this example app has no - # database, I'm just storing the user map. - # - # If you need to make additional resource requests, you may want to store - # the access token as well. conn - |> put_session(:current_user, user) - |> put_session(:access_token, client.token.access_token) |> redirect(to: "/") end - defp authorize_url!("github"), do: GitHub.authorize_url! + defp authorize_url!("authentik"), do: Authentik.authorize_url! defp authorize_url!(_), do: raise "No matching provider available" - defp get_token!("github", code), do: GitHub.get_token!(code: code) + defp get_token!("authentik", code), do: Authentik.get_token!(code: code) defp get_token!(_, _), do: raise "No matching provider available" - defp get_user!("github", client) do + defp get_user!("authentik", client) do token = Map.get(client, :token) |> Map.get(:access_token) |> Jason.decode! |> Map.get("access_token") - %{body: user} = OAuth2.Client.get!(client, "/user", [ - {"user-agent", "midarr"}, + %{body: user} = OAuth2.Client.get!(client, System.get_env("OAUTH_USER_URL"), [ {"authorization", "Bearer #{ token }"} ]) - decoded_user = Jason.decode!(user) |> IO.inspect + decoded_user = Jason.decode!(user) - %{name: decoded_user["name"], avatar: decoded_user["avatar_url"]} + %{name: decoded_user["name"], email: decoded_user["email"]} end end \ No newline at end of file diff --git a/lib/media_server_web/oauth/authentik.ex b/lib/media_server_web/oauth/authentik.ex new file mode 100644 index 00000000..f7b03528 --- /dev/null +++ b/lib/media_server_web/oauth/authentik.ex @@ -0,0 +1,42 @@ +defmodule Authentik do + @moduledoc """ + An OAuth2 strategy for Authentik. + """ + use OAuth2.Strategy + + alias OAuth2.Strategy.AuthCode + + defp config do + [ + strategy: Authentik, + site: System.get_env("OAUTH_ISSUER_URL"), + authorize_url: System.get_env("OAUTH_AUTHORIZE_URL"), + token_url: System.get_env("OAUTH_TOKEN_URL"), + client_id: System.get_env("OAUTH_CLIENT_ID"), + client_secret: System.get_env("OAUTH_CLIENT_SECRET"), + redirect_uri: System.get_env("OAUTH_REDIRECT_URI") + ] + end + + def client do + OAuth2.Client.new(config()) + end + + def authorize_url!(params \\ []) do + OAuth2.Client.authorize_url!(client()) + end + + def get_token!(params \\ [], headers \\ []) do + OAuth2.Client.get_token!(client(), params) + end + + def authorize_url(client, params) do + AuthCode.authorize_url(client, params) + end + + def get_token(client, params, headers) do + client + |> put_header("Accept", "application/json") + |> AuthCode.get_token(params, headers) + end +end \ No newline at end of file diff --git a/lib/media_server_web/oauth/github.ex b/lib/media_server_web/oauth/github.ex deleted file mode 100644 index 00cb9749..00000000 --- a/lib/media_server_web/oauth/github.ex +++ /dev/null @@ -1,45 +0,0 @@ -defmodule GitHub do - @moduledoc """ - An OAuth2 strategy for GitHub. - """ - use OAuth2.Strategy - - alias OAuth2.Strategy.AuthCode - - defp config do - [ - strategy: GitHub, - site: "https://api.github.com", - authorize_url: "https://github.com/login/oauth/authorize", - token_url: "https://github.com/login/oauth/access_token" - ] - end - - # Public API - - def client do - Application.get_env(:media_server, GitHub) - |> Keyword.merge(config()) - |> OAuth2.Client.new() - end - - def authorize_url!(params \\ []) do - OAuth2.Client.authorize_url!(client(), params) - end - - def get_token!(params \\ [], headers \\ []) do - OAuth2.Client.get_token!(client(), Keyword.merge(params, client_secret: client().client_secret)) - end - - # Strategy Callbacks - - def authorize_url(client, params) do - AuthCode.authorize_url(client, params) - end - - def get_token(client, params, headers) do - client - |> put_header("Accept", "application/json") - |> AuthCode.get_token(params, headers) - end -end \ No newline at end of file From 00eba48960d8b7944d1db43183e62ee1a4fa4b8e Mon Sep 17 00:00:00 2001 From: trueChazza Date: Wed, 28 Jun 2023 18:22:01 +1200 Subject: [PATCH 04/14] refactor: footer v3.2.0-beta.2 --- lib/media_server_web/components/footer_component.html.heex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/media_server_web/components/footer_component.html.heex b/lib/media_server_web/components/footer_component.html.heex index a22577e3..0dac6ee3 100644 --- a/lib/media_server_web/components/footer_component.html.heex +++ b/lib/media_server_web/components/footer_component.html.heex @@ -24,7 +24,7 @@ ) %> - © 2023 Midarr Labs - v3.2.0-beta.1 + © 2023 Midarr Labs - v3.2.0-beta.2 From eb2a50a25e2447e1f85e404c97de00273bceeb6f Mon Sep 17 00:00:00 2001 From: trueChazza Date: Tue, 11 Jul 2023 12:38:59 +1200 Subject: [PATCH 05/14] refactor: refactor generic oauth --- .env.example | 2 - docker-compose.yml | 16 ++---- .../controllers/auth_controller.ex | 57 ------------------- .../controllers/oauth_controller.ex | 19 +++++++ .../{oauth/authentik.ex => oauth.ex} | 23 +++++--- lib/media_server_web/router.ex | 5 +- 6 files changed, 43 insertions(+), 79 deletions(-) delete mode 100644 .env.example delete mode 100644 lib/media_server_web/controllers/auth_controller.ex create mode 100644 lib/media_server_web/controllers/oauth_controller.ex rename lib/media_server_web/{oauth/authentik.ex => oauth.ex} (67%) diff --git a/.env.example b/.env.example deleted file mode 100644 index 990d571f..00000000 --- a/.env.example +++ /dev/null @@ -1,2 +0,0 @@ -PG_PASS=password -AUTHENTIK_SECRET_KEY=password \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index e0d63769..4564099e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,7 +34,7 @@ services: - OAUTH_TOKEN_URL=http://server-authentik:9000/application/o/token/ - OAUTH_CLIENT_ID=someClientId - OAUTH_CLIENT_SECRET=someClientSecret - - OAUTH_REDIRECT_URI=http://localhost:4000/auth/authentik/callback + - OAUTH_REDIRECT_URI=http://localhost:4000/auth/callback - OAUTH_USER_URL=http://server-authentik:9000/application/o/userinfo/ - RADARR_BASE_URL=http://radarr:7878 @@ -113,11 +113,9 @@ services: volumes: - database:/var/lib/postgresql/data environment: - POSTGRES_PASSWORD: ${PG_PASS:?database password required} + POSTGRES_PASSWORD: ${PG_PASS:-password} POSTGRES_USER: ${PG_USER:-authentik} POSTGRES_DB: ${PG_DB:-authentik} - env_file: - - .env redis-authentik: image: docker.io/library/redis:alpine @@ -135,13 +133,12 @@ services: image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.5.3} command: server environment: + AUTHENTIK_SECRET_KEY: password AUTHENTIK_REDIS__HOST: redis-authentik AUTHENTIK_POSTGRESQL__HOST: postgresql-authentik AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik} AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik} - AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS} - env_file: - - .env + AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS-password} ports: - "${COMPOSE_PORT_HTTP:-9000}:9000" - "${COMPOSE_PORT_HTTPS:-9443}:9443" @@ -153,11 +150,12 @@ services: image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.5.3} command: worker environment: + AUTHENTIK_SECRET_KEY: password AUTHENTIK_REDIS__HOST: redis-authentik AUTHENTIK_POSTGRESQL__HOST: postgresql-authentik AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik} AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik} - AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS} + AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS-password} # `user: root` and the docker socket volume are optional. # See more for the docker socket integration here: # https://goauthentik.io/docs/outposts/integrations/docker @@ -167,8 +165,6 @@ services: user: root volumes: - /var/run/docker.sock:/var/run/docker.sock - env_file: - - .env depends_on: - postgresql-authentik - redis-authentik \ No newline at end of file diff --git a/lib/media_server_web/controllers/auth_controller.ex b/lib/media_server_web/controllers/auth_controller.ex deleted file mode 100644 index 98ae2d20..00000000 --- a/lib/media_server_web/controllers/auth_controller.ex +++ /dev/null @@ -1,57 +0,0 @@ -defmodule MediaServerWeb.AuthController do - use MediaServerWeb, :controller - - @doc """ - This action is reached via `/auth/:provider` and redirects to the OAuth2 provider - based on the chosen strategy. - """ - def index(conn, %{"provider" => provider}) do - redirect conn, external: authorize_url!(provider) - end - - def delete(conn, _params) do - conn - |> put_flash(:info, "You have been logged out!") - |> configure_session(drop: true) - |> redirect(to: "/") - end - - @doc """ - This action is reached via `/auth/:provider/callback` is the callback URL that - the OAuth2 provider will redirect the user back to with a `code` that will - be used to request an access token. The access token will then be used to - access protected resources on behalf of the user. - """ - def callback(conn, %{"provider" => provider, "code" => code}) do - # Exchange an auth code for an access token - client = get_token!(provider, code) - - # Request the user's data with the access token - if user = MediaServer.Accounts.get_user_by_email(get_user!(provider, client).email) do - - MediaServerWeb.UserAuth.log_in_user(conn, user) - end - - conn - |> redirect(to: "/") - end - - defp authorize_url!("authentik"), do: Authentik.authorize_url! - defp authorize_url!(_), do: raise "No matching provider available" - - defp get_token!("authentik", code), do: Authentik.get_token!(code: code) - defp get_token!(_, _), do: raise "No matching provider available" - - defp get_user!("authentik", client) do - - token = Map.get(client, :token) |> Map.get(:access_token) |> Jason.decode! |> Map.get("access_token") - - %{body: user} = OAuth2.Client.get!(client, System.get_env("OAUTH_USER_URL"), [ - {"authorization", "Bearer #{ token }"} - ]) - - decoded_user = Jason.decode!(user) - - %{name: decoded_user["name"], email: decoded_user["email"]} - end -end \ No newline at end of file diff --git a/lib/media_server_web/controllers/oauth_controller.ex b/lib/media_server_web/controllers/oauth_controller.ex new file mode 100644 index 00000000..a7872cdd --- /dev/null +++ b/lib/media_server_web/controllers/oauth_controller.ex @@ -0,0 +1,19 @@ +defmodule MediaServerWeb.OAuthController do + use MediaServerWeb, :controller + + def index(conn, _params) do + redirect conn, external: MediaServerWeb.OAuth.authorize_url! + end + + def callback(conn, %{"code" => code}) do + client = MediaServerWeb.OAuth.get_token!(code: code) + + if user = MediaServer.Accounts.get_user_by_email(MediaServerWeb.OAuth.get_user!(client).email) do + + MediaServerWeb.UserAuth.log_in_user(conn, user) + end + + conn + |> redirect(to: "/") + end +end \ No newline at end of file diff --git a/lib/media_server_web/oauth/authentik.ex b/lib/media_server_web/oauth.ex similarity index 67% rename from lib/media_server_web/oauth/authentik.ex rename to lib/media_server_web/oauth.ex index f7b03528..062232a7 100644 --- a/lib/media_server_web/oauth/authentik.ex +++ b/lib/media_server_web/oauth.ex @@ -1,19 +1,16 @@ -defmodule Authentik do - @moduledoc """ - An OAuth2 strategy for Authentik. - """ +defmodule MediaServerWeb.OAuth do use OAuth2.Strategy alias OAuth2.Strategy.AuthCode defp config do [ - strategy: Authentik, + strategy: __MODULE__, + client_id: System.get_env("OAUTH_CLIENT_ID"), + client_secret: System.get_env("OAUTH_CLIENT_SECRET"), site: System.get_env("OAUTH_ISSUER_URL"), authorize_url: System.get_env("OAUTH_AUTHORIZE_URL"), token_url: System.get_env("OAUTH_TOKEN_URL"), - client_id: System.get_env("OAUTH_CLIENT_ID"), - client_secret: System.get_env("OAUTH_CLIENT_SECRET"), redirect_uri: System.get_env("OAUTH_REDIRECT_URI") ] end @@ -39,4 +36,16 @@ defmodule Authentik do |> put_header("Accept", "application/json") |> AuthCode.get_token(params, headers) end + + def get_user!(client) do + token = Map.get(client, :token) |> Map.get(:access_token) |> Jason.decode! |> Map.get("access_token") + + %{body: user} = OAuth2.Client.get!(client, System.get_env("OAUTH_USER_URL"), [ + {"authorization", "Bearer #{ token }"} + ]) + + decoded_user = Jason.decode!(user) + + %{name: decoded_user["name"], email: decoded_user["email"]} + end end \ No newline at end of file diff --git a/lib/media_server_web/router.ex b/lib/media_server_web/router.ex index 9d8228ef..244a9bf4 100644 --- a/lib/media_server_web/router.ex +++ b/lib/media_server_web/router.ex @@ -29,9 +29,8 @@ defmodule MediaServerWeb.Router do scope "/auth", MediaServerWeb do pipe_through :browser - get "/:provider", AuthController, :index - get "/:provider/callback", AuthController, :callback - delete "/logout", AuthController, :delete + get "/", OAuthController, :index + get "/callback", OAuthController, :callback end scope "/", MediaServerWeb do From 0ad0f47bd244beeacecea1eef59fcf5701d9d5a7 Mon Sep 17 00:00:00 2001 From: trueChazza Date: Tue, 11 Jul 2023 14:41:42 +1200 Subject: [PATCH 06/14] refactor: refactor --- lib/media_server_web/oauth.ex | 8 ++++---- lib/media_server_web/router.ex | 8 ++------ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/lib/media_server_web/oauth.ex b/lib/media_server_web/oauth.ex index 062232a7..e772e908 100644 --- a/lib/media_server_web/oauth.ex +++ b/lib/media_server_web/oauth.ex @@ -23,14 +23,14 @@ defmodule MediaServerWeb.OAuth do OAuth2.Client.authorize_url!(client()) end - def get_token!(params \\ [], headers \\ []) do - OAuth2.Client.get_token!(client(), params) - end - def authorize_url(client, params) do AuthCode.authorize_url(client, params) end + def get_token!(params \\ [], headers \\ []) do + OAuth2.Client.get_token!(client(), params) + end + def get_token(client, params, headers) do client |> put_header("Accept", "application/json") diff --git a/lib/media_server_web/router.ex b/lib/media_server_web/router.ex index f6a28256..312828ab 100644 --- a/lib/media_server_web/router.ex +++ b/lib/media_server_web/router.ex @@ -24,13 +24,9 @@ defmodule MediaServerWeb.Router do get "/login", UserSessionController, :new post "/login", UserSessionController, :create - end - - scope "/auth", MediaServerWeb do - pipe_through :browser - get "/", OAuthController, :index - get "/callback", OAuthController, :callback + get "/auth", OAuthController, :index + get "/auth/callback", OAuthController, :callback end scope "/", MediaServerWeb do From 5d8f0fa48953a0144e737550a8c0ca2d2a2d1a21 Mon Sep 17 00:00:00 2001 From: trueChazza Date: Wed, 12 Jul 2023 09:47:30 +1200 Subject: [PATCH 07/14] test: add mock server --- lib/media_server/application.ex | 1 + test/support/mock_server.ex | 21 +++++++++++++++++++++ test/test_helper.exs | 2 ++ 3 files changed, 24 insertions(+) create mode 100644 test/support/mock_server.ex diff --git a/lib/media_server/application.ex b/lib/media_server/application.ex index 15832d9f..28ca6260 100644 --- a/lib/media_server/application.ex +++ b/lib/media_server/application.ex @@ -19,6 +19,7 @@ defmodule MediaServer.Application do # Start a worker by calling: MediaServer.Worker.start_link(arg) # {MediaServer.Worker, arg} MediaServerWeb.Presence, + {DynamicSupervisor, name: MediaServer.DynamicSupervisor}, MediaServer.Token, MediaServer.MoviesIndex, MediaServer.MoviesWebhook, diff --git a/test/support/mock_server.ex b/test/support/mock_server.ex new file mode 100644 index 00000000..702a11d7 --- /dev/null +++ b/test/support/mock_server.ex @@ -0,0 +1,21 @@ +defmodule MediaServer.MockServer do + use Plug.Router + + plug(:match) + plug(:dispatch) + + get "/authorize" do + conn + |> Plug.Conn.send_resp(200, "ok") + end + + post "/token" do + conn + |> Plug.Conn.send_resp(200, Jason.encode!(%{access_token: "someAccessToken"})) + end + + get "/user" do + conn + |> Plug.Conn.send_resp(200, Jason.encode!(%{name: "someName", email: "someEmail"})) + end +end \ No newline at end of file diff --git a/test/test_helper.exs b/test/test_helper.exs index c3ec62db..37bbf144 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,2 +1,4 @@ ExUnit.start() Ecto.Adapters.SQL.Sandbox.mode(MediaServer.Repo, :manual) + +DynamicSupervisor.start_child(MediaServer.DynamicSupervisor, {Plug.Cowboy, scheme: :http, plug: MediaServer.MockServer, options: [port: 8081]}) From e002d39a474e466aab296932781b8bf2e8835e09 Mon Sep 17 00:00:00 2001 From: trueChazza Date: Wed, 12 Jul 2023 09:47:52 +1200 Subject: [PATCH 08/14] refactor: refactor --- lib/media_server_web/controllers/oauth_controller.ex | 3 ++- lib/media_server_web/oauth.ex | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/media_server_web/controllers/oauth_controller.ex b/lib/media_server_web/controllers/oauth_controller.ex index a7872cdd..cdb7f796 100644 --- a/lib/media_server_web/controllers/oauth_controller.ex +++ b/lib/media_server_web/controllers/oauth_controller.ex @@ -2,7 +2,8 @@ defmodule MediaServerWeb.OAuthController do use MediaServerWeb, :controller def index(conn, _params) do - redirect conn, external: MediaServerWeb.OAuth.authorize_url! + conn + |> redirect(external: MediaServerWeb.OAuth.authorize_url!) end def callback(conn, %{"code" => code}) do diff --git a/lib/media_server_web/oauth.ex b/lib/media_server_web/oauth.ex index e772e908..dbb3fff8 100644 --- a/lib/media_server_web/oauth.ex +++ b/lib/media_server_web/oauth.ex @@ -19,7 +19,7 @@ defmodule MediaServerWeb.OAuth do OAuth2.Client.new(config()) end - def authorize_url!(params \\ []) do + def authorize_url!(_params \\ []) do OAuth2.Client.authorize_url!(client()) end @@ -27,7 +27,7 @@ defmodule MediaServerWeb.OAuth do AuthCode.authorize_url(client, params) end - def get_token!(params \\ [], headers \\ []) do + def get_token!(params \\ [], _headers \\ []) do OAuth2.Client.get_token!(client(), params) end From 3ed8afa014e010b34aa6487ad863f1867a1bb819 Mon Sep 17 00:00:00 2001 From: trueChazza Date: Wed, 12 Jul 2023 09:48:22 +1200 Subject: [PATCH 09/14] test: add oauth_controller_test --- .../controllers/oauth_controller_test.exs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 test/media_server_web/controllers/oauth_controller_test.exs diff --git a/test/media_server_web/controllers/oauth_controller_test.exs b/test/media_server_web/controllers/oauth_controller_test.exs new file mode 100644 index 00000000..eeff69f1 --- /dev/null +++ b/test/media_server_web/controllers/oauth_controller_test.exs @@ -0,0 +1,26 @@ +defmodule MediaServerWeb.OauthControllerTest do + use MediaServerWeb.ConnCase + + import MediaServer.AccountsFixtures + + setup do + %{user: user_fixture()} + end + + test "it should redirect", %{conn: conn} do + conn = get(conn, Routes.o_auth_path(conn, :index)) + response = html_response(conn, 302) + + assert response =~ "You are being" + assert response =~ "redirected" + assert response =~ "authorize?client_id=" + end + + test "it should callback", %{conn: conn} do + conn = get(conn, Routes.o_auth_path(conn, :callback, code: "code")) + response = html_response(conn, 302) + + assert response =~ "You are being" + assert response =~ "redirected" + end +end From 1eef96577f03098e3d789b1ff7a91c43be51e803 Mon Sep 17 00:00:00 2001 From: trueChazza Date: Wed, 12 Jul 2023 09:49:13 +1200 Subject: [PATCH 10/14] build: remove authentik docker compose --- docker-compose.yml | 79 ++++------------------------------------------ 1 file changed, 6 insertions(+), 73 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 4564099e..46a1f5b7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,13 +29,13 @@ services: - SETUP_ADMIN_NAME=admin - SETUP_ADMIN_PASSWORD=passwordpassword - - OAUTH_ISSUER_URL=http://localhost:9000 - - OAUTH_AUTHORIZE_URL=http://localhost:9000/application/o/authorize/ - - OAUTH_TOKEN_URL=http://server-authentik:9000/application/o/token/ - OAUTH_CLIENT_ID=someClientId - OAUTH_CLIENT_SECRET=someClientSecret - - OAUTH_REDIRECT_URI=http://localhost:4000/auth/callback - - OAUTH_USER_URL=http://server-authentik:9000/application/o/userinfo/ + - OAUTH_ISSUER_URL=http://localhost:8081 + - OAUTH_AUTHORIZE_URL=http://localhost:8081/authorize + - OAUTH_TOKEN_URL=http://localhost:8081/token + - OAUTH_REDIRECT_URI=http://localhost:8081/auth/callback + - OAUTH_USER_URL=http://localhost:8081/user - RADARR_BASE_URL=http://radarr:7878 - RADARR_API_KEY=d031e8c9b9df4b2fab311d1c3b3fa2c5 @@ -100,71 +100,4 @@ services: - PUID=1000 - PGID=1000 healthcheck: - test: "exit 0" - - postgresql-authentik: - image: docker.io/library/postgres:12-alpine - healthcheck: - test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"] - start_period: 20s - interval: 30s - retries: 5 - timeout: 5s - volumes: - - database:/var/lib/postgresql/data - environment: - POSTGRES_PASSWORD: ${PG_PASS:-password} - POSTGRES_USER: ${PG_USER:-authentik} - POSTGRES_DB: ${PG_DB:-authentik} - - redis-authentik: - image: docker.io/library/redis:alpine - command: --save 60 1 --loglevel warning - healthcheck: - test: [ "CMD-SHELL", "redis-cli ping | grep PONG" ] - start_period: 20s - interval: 30s - retries: 5 - timeout: 3s - volumes: - - redis:/data - - server-authentik: - image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.5.3} - command: server - environment: - AUTHENTIK_SECRET_KEY: password - AUTHENTIK_REDIS__HOST: redis-authentik - AUTHENTIK_POSTGRESQL__HOST: postgresql-authentik - AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik} - AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik} - AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS-password} - ports: - - "${COMPOSE_PORT_HTTP:-9000}:9000" - - "${COMPOSE_PORT_HTTPS:-9443}:9443" - depends_on: - - postgresql-authentik - - redis-authentik - - worker: - image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.5.3} - command: worker - environment: - AUTHENTIK_SECRET_KEY: password - AUTHENTIK_REDIS__HOST: redis-authentik - AUTHENTIK_POSTGRESQL__HOST: postgresql-authentik - AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik} - AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik} - AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS-password} - # `user: root` and the docker socket volume are optional. - # See more for the docker socket integration here: - # https://goauthentik.io/docs/outposts/integrations/docker - # Removing `user: root` also prevents the worker from fixing the permissions - # on the mounted folders, so when removing this make sure the folders have the correct UID/GID - # (1000:1000 by default) - user: root - volumes: - - /var/run/docker.sock:/var/run/docker.sock - depends_on: - - postgresql-authentik - - redis-authentik \ No newline at end of file + test: "exit 0" \ No newline at end of file From 0397ba6bec55764997a59c044522b1e350ea6bca Mon Sep 17 00:00:00 2001 From: trueChazza Date: Wed, 12 Jul 2023 09:50:03 +1200 Subject: [PATCH 11/14] test: refactor oauth_controller_test --- test/media_server_web/controllers/oauth_controller_test.exs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/media_server_web/controllers/oauth_controller_test.exs b/test/media_server_web/controllers/oauth_controller_test.exs index eeff69f1..a55c6c2d 100644 --- a/test/media_server_web/controllers/oauth_controller_test.exs +++ b/test/media_server_web/controllers/oauth_controller_test.exs @@ -1,12 +1,6 @@ defmodule MediaServerWeb.OauthControllerTest do use MediaServerWeb.ConnCase - import MediaServer.AccountsFixtures - - setup do - %{user: user_fixture()} - end - test "it should redirect", %{conn: conn} do conn = get(conn, Routes.o_auth_path(conn, :index)) response = html_response(conn, 302) From f56b4eda3ef5c0dc88c677021200541e445f9781 Mon Sep 17 00:00:00 2001 From: trueChazza Date: Wed, 12 Jul 2023 10:02:21 +1200 Subject: [PATCH 12/14] build: remove .env gitignore --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 2813bfe5..434f97a2 100644 --- a/.gitignore +++ b/.gitignore @@ -43,5 +43,4 @@ npm-debug.log /.idea /lib/media_server/release.ex -/rel/overlays/bin/ -.env \ No newline at end of file +/rel/overlays/bin/ \ No newline at end of file From fe1c74509df64b3366f22c2e6f56a628c7b007be Mon Sep 17 00:00:00 2001 From: trueChazza Date: Wed, 12 Jul 2023 10:03:04 +1200 Subject: [PATCH 13/14] refactor: refactor --- .gitignore | 2 +- config/dev.exs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 434f97a2..5e03b145 100644 --- a/.gitignore +++ b/.gitignore @@ -43,4 +43,4 @@ npm-debug.log /.idea /lib/media_server/release.ex -/rel/overlays/bin/ \ No newline at end of file +/rel/overlays/bin/ diff --git a/config/dev.exs b/config/dev.exs index 7e072c5d..e02d6d44 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -68,4 +68,4 @@ config :logger, :console, format: "[$level] $message\n" config :phoenix, :stacktrace_depth, 20 # Initialize plugs at runtime for faster development compilation -config :phoenix, :plug_init_mode, :runtime \ No newline at end of file +config :phoenix, :plug_init_mode, :runtime From a7705d4e2a6af1fd75c0cb4d39ad54ef0243c616 Mon Sep 17 00:00:00 2001 From: trueChazza Date: Wed, 12 Jul 2023 10:18:30 +1200 Subject: [PATCH 14/14] ci: refactor workflows --- .github/workflows/beta.yml | 1 + .github/workflows/build.yml | 77 +---------------- .github/workflows/{tag.yml => release.yml} | 3 +- .github/workflows/test.yml | 96 ++++++++++++++++++++++ 4 files changed, 101 insertions(+), 76 deletions(-) rename .github/workflows/{tag.yml => release.yml} (97%) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/beta.yml b/.github/workflows/beta.yml index 125f0e02..b37f80d6 100644 --- a/.github/workflows/beta.yml +++ b/.github/workflows/beta.yml @@ -7,6 +7,7 @@ on: jobs: docker: + name: beta runs-on: ubuntu-latest steps: - name: Set env diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b3794f11..cf5f7410 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,23 +8,10 @@ on: branches: - '**' -env: - MIX_ENV: test - APP_URL: http://localhost:4000 - DB_HOSTNAME_TEST: localhost - DB_USERNAME: my_user - DB_PASSWORD: my_password - DB_DATABASE: my_database - RADARR_BASE_URL: http://localhost:7878 - RADARR_API_KEY: d031e8c9b9df4b2fab311d1c3b3fa2c5 - SONARR_BASE_URL: http://localhost:8989 - SONARR_API_KEY: 1accda4476394bfcaddefe8c4fd77d4a - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - jobs: build: + name: build runs-on: ubuntu-latest steps: - name: Checkout @@ -40,64 +27,4 @@ jobs: uses: docker/build-push-action@v4 with: context: . - platforms: linux/amd64,linux/arm64 - - test: - name: OTP ${{matrix.otp}} / Elixir ${{matrix.elixir}} - runs-on: ubuntu-latest - strategy: - matrix: - otp: [ '24' ] - elixir: [ '1.14.3' ] - - services: - postgres-test: - image: postgres - env: - POSTGRES_USER: my_user - POSTGRES_PASSWORD: my_password - POSTGRES_DB: my_database - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 5432:5432 - - steps: - - uses: actions/checkout@v2 - - uses: FedericoCarboni/setup-ffmpeg@v2 - - # Setup library - - run: sudo cp -r ${GITHUB_WORKSPACE}/dev/library /library - - # Setup Radarr - - run: chmod u+x .github/install-radarr.sh - - run: ./.github/install-radarr.sh - - run: curl --head -X GET --retry 5 --retry-connrefused --retry-delay 5 "http://localhost:7878" - - # Seed Radarr - - run: curl -d "@${GITHUB_WORKSPACE}/dev/radarr/root-folder.json" -H "Content-Type:application/json" -X POST "http://localhost:7878/api/v3/rootfolder?apiKey=d031e8c9b9df4b2fab311d1c3b3fa2c5" - - run: curl -d "@${GITHUB_WORKSPACE}/dev/radarr/movies.json" -H "Content-Type:application/json" -X POST "http://localhost:7878/api/v3/movie/import?apiKey=d031e8c9b9df4b2fab311d1c3b3fa2c5" - - # Setup Sonarr - - run: chmod u+x .github/install-sonarr.sh - - run: ./.github/install-sonarr.sh - - run: curl --head -X GET --retry 5 --retry-connrefused --retry-delay 5 "http://localhost:8989" - - # Seed Sonarr - - run: curl -d "@${GITHUB_WORKSPACE}/dev/sonarr/root-folder.json" -H "Content-Type:application/json" -X POST "http://localhost:8989/api/v3/rootfolder?apikey=1accda4476394bfcaddefe8c4fd77d4a" - - run: curl -d "@${GITHUB_WORKSPACE}/dev/sonarr/series.json" -H "Content-Type:application/json" -X POST "http://localhost:8989/api/v3/series/import?apikey=1accda4476394bfcaddefe8c4fd77d4a" - - # Run tests - - uses: erlef/setup-beam@v1 - with: - otp-version: ${{matrix.otp}} - elixir-version: ${{matrix.elixir}} - - run: mix deps.get - - run: mix ecto.migrate - - run: mix run priv/repo/seeds.exs - - run: mix test - - run: chmod u+x code-coverage.sh - - run: ./code-coverage.sh \ No newline at end of file + platforms: linux/amd64,linux/arm64 \ No newline at end of file diff --git a/.github/workflows/tag.yml b/.github/workflows/release.yml similarity index 97% rename from .github/workflows/tag.yml rename to .github/workflows/release.yml index c633c87c..eb707780 100644 --- a/.github/workflows/tag.yml +++ b/.github/workflows/release.yml @@ -1,4 +1,4 @@ -name: Tag +name: Release on: push: @@ -7,6 +7,7 @@ on: jobs: docker: + name: release runs-on: ubuntu-latest steps: - name: Set env diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..9d98778f --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,96 @@ +name: Test + +on: + push: + branches: + - master + pull_request: + branches: + - '**' + +env: + MIX_ENV: test + APP_URL: http://localhost:4000 + + DB_HOSTNAME_TEST: localhost + DB_USERNAME: my_user + DB_PASSWORD: my_password + DB_DATABASE: my_database + + OAUTH_CLIENT_ID: someClientId + OAUTH_CLIENT_SECRET: someClientSecret + OAUTH_ISSUER_URL: http://localhost:8081 + OAUTH_AUTHORIZE_URL: http://localhost:8081/authorize + OAUTH_TOKEN_URL: http://localhost:8081/token + OAUTH_REDIRECT_URI: http://localhost:8081/auth/callback + OAUTH_USER_URL: http://localhost:8081/user + + RADARR_BASE_URL: http://localhost:7878 + RADARR_API_KEY: d031e8c9b9df4b2fab311d1c3b3fa2c5 + SONARR_BASE_URL: http://localhost:8989 + SONARR_API_KEY: 1accda4476394bfcaddefe8c4fd77d4a + + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + +jobs: + + test: + name: test + runs-on: ubuntu-latest + strategy: + matrix: + otp: [ '24' ] + elixir: [ '1.14.3' ] + + services: + postgres-test: + image: postgres + env: + POSTGRES_USER: my_user + POSTGRES_PASSWORD: my_password + POSTGRES_DB: my_database + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 + + steps: + - uses: actions/checkout@v2 + - uses: FedericoCarboni/setup-ffmpeg@v2 + + # Setup library + - run: sudo cp -r ${GITHUB_WORKSPACE}/dev/library /library + + # Setup Radarr + - run: chmod u+x .github/install-radarr.sh + - run: ./.github/install-radarr.sh + - run: curl --head -X GET --retry 5 --retry-connrefused --retry-delay 5 "http://localhost:7878" + + # Seed Radarr + - run: curl -d "@${GITHUB_WORKSPACE}/dev/radarr/root-folder.json" -H "Content-Type:application/json" -X POST "http://localhost:7878/api/v3/rootfolder?apiKey=d031e8c9b9df4b2fab311d1c3b3fa2c5" + - run: curl -d "@${GITHUB_WORKSPACE}/dev/radarr/movies.json" -H "Content-Type:application/json" -X POST "http://localhost:7878/api/v3/movie/import?apiKey=d031e8c9b9df4b2fab311d1c3b3fa2c5" + + # Setup Sonarr + - run: chmod u+x .github/install-sonarr.sh + - run: ./.github/install-sonarr.sh + - run: curl --head -X GET --retry 5 --retry-connrefused --retry-delay 5 "http://localhost:8989" + + # Seed Sonarr + - run: curl -d "@${GITHUB_WORKSPACE}/dev/sonarr/root-folder.json" -H "Content-Type:application/json" -X POST "http://localhost:8989/api/v3/rootfolder?apikey=1accda4476394bfcaddefe8c4fd77d4a" + - run: curl -d "@${GITHUB_WORKSPACE}/dev/sonarr/series.json" -H "Content-Type:application/json" -X POST "http://localhost:8989/api/v3/series/import?apikey=1accda4476394bfcaddefe8c4fd77d4a" + + # Run tests + - uses: erlef/setup-beam@v1 + with: + otp-version: ${{matrix.otp}} + elixir-version: ${{matrix.elixir}} + - run: mix deps.get + - run: mix ecto.migrate + - run: mix run priv/repo/seeds.exs + - run: mix test + - run: chmod u+x code-coverage.sh + - run: ./code-coverage.sh \ No newline at end of file