diff --git a/lib/matrix_server/account.ex b/lib/matrix_server/account.ex index b5a505e..9be08cb 100644 --- a/lib/matrix_server/account.ex +++ b/lib/matrix_server/account.ex @@ -47,12 +47,11 @@ defmodule MatrixServer.Account do |> Multi.run(:device_with_access_token, &Device.insert_new_access_token/2) end - def get_by_access_token(access_token) do - from(a in Account, - join: d in assoc(a, :devices), - where: d.access_token == ^access_token, - preload: [devices: d] - ) + def by_access_token(access_token) do + Device + |> where([d], d.access_token == ^access_token) + |> join(:inner, [d], a in assoc(d, :account)) + |> select([d, a], {a, d}) |> Repo.one() end diff --git a/lib/matrix_server/device.ex b/lib/matrix_server/device.ex index 867f717..dcbc8d4 100644 --- a/lib/matrix_server/device.ex +++ b/lib/matrix_server/device.ex @@ -1,7 +1,9 @@ defmodule MatrixServer.Device do use Ecto.Schema - import Ecto.Changeset - alias MatrixServer.{Account, Device} + + import Ecto.{Changeset, Query} + + alias MatrixServer.{Account, Device, Repo} @primary_key false schema "devices" do @@ -45,4 +47,23 @@ defmodule MatrixServer.Device do "#{localpart}_#{time_string}" end + + def login(account, device_id, access_token, params) do + update_query = + from(d in Device) + |> update(set: [access_token: ^access_token, device_id: ^device_id]) + + update_query = + if params[:display_name] != nil do + update(update_query, set: [display_name: ^params.display_name]) + else + update_query + end + + Ecto.build_assoc(account, :devices) + |> Map.put(:device_id, device_id) + |> Map.put(:access_token, access_token) + |> Device.changeset(params) + |> Repo.insert(on_conflict: update_query, conflict_target: [:localpart, :device_id]) + end end diff --git a/lib/matrix_server_web/controllers/account_controller.ex b/lib/matrix_server_web/controllers/account_controller.ex index d50e4a2..5525593 100644 --- a/lib/matrix_server_web/controllers/account_controller.ex +++ b/lib/matrix_server_web/controllers/account_controller.ex @@ -4,7 +4,7 @@ defmodule MatrixServerWeb.AccountController do import MatrixServer import MatrixServerWeb.Plug.Error - alias MatrixServer.Account + alias MatrixServer.{Account, Repo} alias Plug.Conn def available(conn, params) do @@ -28,4 +28,24 @@ defmodule MatrixServerWeb.AccountController do |> put_status(200) |> json(data) end + + def logout(%Conn{assigns: %{device: device}} = conn, _params) do + case Repo.delete(device) do + {:ok, _} -> + conn + |> put_status(200) + |> json(%{}) + + {:error, _} -> + put_error(conn, :unknown) + end + end + + def logout_all(%Conn{assigns: %{account: account}} = conn, _params) do + Repo.delete_all(Ecto.assoc(account, :devices)) + + conn + |> put_status(200) + |> json(%{}) + end end diff --git a/lib/matrix_server_web/controllers/auth_controller.ex b/lib/matrix_server_web/controllers/auth_controller.ex index da5b73f..292664c 100644 --- a/lib/matrix_server_web/controllers/auth_controller.ex +++ b/lib/matrix_server_web/controllers/auth_controller.ex @@ -130,30 +130,9 @@ defmodule MatrixServerWeb.AuthController do device_id = Map.get(params, :device_id, Device.generate_device_id(localpart)) access_token = Device.generate_access_token(localpart, device_id) - update_query = - from(d in Device) - |> update(set: [access_token: ^access_token, device_id: ^device_id]) - - update_query = - if params[:display_name] != nil do - update(update_query, set: [display_name: ^params.display_name]) - else - update_query - end - - result = - Ecto.build_assoc(account, :devices) - |> Map.put(:device_id, device_id) - |> Map.put(:access_token, access_token) - |> Device.changeset(params) - |> repo.insert(on_conflict: update_query, conflict_target: [:localpart, :device_id]) - - case result do - {:ok, device} -> - device - - {:error, _cs} -> - repo.rollback(:forbidden) + case Device.login(account, device_id, access_token, params) do + {:ok, device} -> device + {:error, _cs} -> repo.rollback(:forbidden) end else repo.rollback(:forbidden) diff --git a/lib/matrix_server_web/plug/authenticate.ex b/lib/matrix_server_web/plug/authenticate.ex index 7879912..ad2c7d4 100644 --- a/lib/matrix_server_web/plug/authenticate.ex +++ b/lib/matrix_server_web/plug/authenticate.ex @@ -22,8 +22,8 @@ defmodule MatrixServerWeb.Plug.Authenticate do end defp authenticate(conn, access_token) do - case Account.get_by_access_token(access_token) do - %Account{devices: [device]} = account -> + case Account.by_access_token(access_token) do + {account, device} -> conn |> assign(:account, account) |> assign(:device, device) diff --git a/lib/matrix_server_web/router.ex b/lib/matrix_server_web/router.ex index 086b016..b26711f 100644 --- a/lib/matrix_server_web/router.ex +++ b/lib/matrix_server_web/router.ex @@ -17,9 +17,9 @@ defmodule MatrixServerWeb.Router do scope "/client/r0", as: :client do post "/register", AuthController, :register + get "/register/available", AccountController, :available get "/login", AuthController, :login_types post "/login", AuthController, :login - get "/register/available", AccountController, :available end get "/client/versions", InfoController, :versions @@ -30,6 +30,8 @@ defmodule MatrixServerWeb.Router do scope "/client/r0", as: :client do get "/account/whoami", AccountController, :whoami + post "/logout", AccountController, :logout + post "/logout/all", AccountController, :logout_all end end