2021-06-25 15:43:12 +00:00
|
|
|
defmodule MatrixServer.Device do
|
|
|
|
use Ecto.Schema
|
2021-06-27 20:24:54 +00:00
|
|
|
|
|
|
|
import Ecto.{Changeset, Query}
|
|
|
|
|
|
|
|
alias MatrixServer.{Account, Device, Repo}
|
2021-08-14 13:20:42 +00:00
|
|
|
alias MatrixServerWeb.Client.Request.Login
|
2021-06-25 15:43:12 +00:00
|
|
|
|
2021-08-26 09:01:19 +00:00
|
|
|
@type t :: %__MODULE__{
|
|
|
|
device_id: String.t(),
|
|
|
|
access_token: String.t(),
|
|
|
|
display_name: String.t(),
|
|
|
|
localpart: String.t()
|
|
|
|
}
|
|
|
|
|
2021-06-25 15:43:12 +00:00
|
|
|
@primary_key false
|
|
|
|
schema "devices" do
|
|
|
|
field :device_id, :string, primary_key: true
|
2021-07-10 21:16:00 +00:00
|
|
|
field :access_token, :string, redact: true
|
2021-06-25 15:43:12 +00:00
|
|
|
field :display_name, :string
|
|
|
|
|
|
|
|
belongs_to :account, Account,
|
|
|
|
foreign_key: :localpart,
|
|
|
|
references: :localpart,
|
|
|
|
type: :string,
|
|
|
|
primary_key: true
|
|
|
|
end
|
|
|
|
|
|
|
|
def changeset(device, params \\ %{}) do
|
|
|
|
device
|
2021-06-27 15:28:28 +00:00
|
|
|
|> cast(params, [:display_name, :device_id])
|
2021-06-25 15:43:12 +00:00
|
|
|
|> validate_required([:localpart, :device_id])
|
|
|
|
|> unique_constraint([:localpart, :device_id], name: :devices_pkey)
|
|
|
|
end
|
|
|
|
|
2021-06-27 15:28:28 +00:00
|
|
|
def insert_new_access_token(repo, %{
|
2021-06-25 22:29:33 +00:00
|
|
|
device: %Device{localpart: localpart, device_id: device_id} = device
|
|
|
|
}) do
|
2021-06-27 15:28:28 +00:00
|
|
|
access_token = generate_access_token(localpart, device_id)
|
2021-06-25 22:29:33 +00:00
|
|
|
|
2021-06-25 15:43:12 +00:00
|
|
|
device
|
|
|
|
|> change(%{access_token: access_token})
|
|
|
|
|> repo.update()
|
|
|
|
end
|
2021-06-26 20:02:18 +00:00
|
|
|
|
2021-06-27 15:28:28 +00:00
|
|
|
def generate_access_token(localpart, device_id) do
|
|
|
|
Phoenix.Token.encrypt(MatrixServerWeb.Endpoint, "access_token", {localpart, device_id})
|
|
|
|
end
|
|
|
|
|
|
|
|
def generate_device_id(localpart) do
|
2021-07-13 15:08:07 +00:00
|
|
|
# TODO: use random string instead
|
2021-08-12 22:45:07 +00:00
|
|
|
"#{localpart}_#{System.os_time(:millisecond)}"
|
2021-06-26 20:02:18 +00:00
|
|
|
end
|
2021-06-27 20:24:54 +00:00
|
|
|
|
2021-07-17 15:38:20 +00:00
|
|
|
def login(%Login{} = input, account) do
|
|
|
|
device_id = input.device_id || generate_device_id(account.localpart)
|
2021-07-13 21:16:56 +00:00
|
|
|
access_token = generate_access_token(account.localpart, device_id)
|
|
|
|
|
2021-06-27 20:24:54 +00:00
|
|
|
update_query =
|
|
|
|
from(d in Device)
|
|
|
|
|> update(set: [access_token: ^access_token, device_id: ^device_id])
|
2021-07-13 21:16:56 +00:00
|
|
|
|> then(fn q ->
|
2021-07-17 15:38:20 +00:00
|
|
|
if input.initial_device_display_name do
|
|
|
|
update(q, set: [display_name: ^input.initial_device_display_name])
|
2021-07-13 21:16:56 +00:00
|
|
|
else
|
|
|
|
q
|
|
|
|
end
|
|
|
|
end)
|
2021-06-27 20:24:54 +00:00
|
|
|
|
2021-07-13 21:16:56 +00:00
|
|
|
device_params = %{
|
|
|
|
device_id: device_id,
|
2021-07-17 15:38:20 +00:00
|
|
|
display_name: input.initial_device_display_name
|
2021-07-13 21:16:56 +00:00
|
|
|
}
|
2021-06-27 20:24:54 +00:00
|
|
|
|
|
|
|
Ecto.build_assoc(account, :devices)
|
2021-07-13 21:16:56 +00:00
|
|
|
|> Device.changeset(device_params)
|
|
|
|
|> put_change(:access_token, access_token)
|
2021-06-27 20:24:54 +00:00
|
|
|
|> Repo.insert(on_conflict: update_query, conflict_target: [:localpart, :device_id])
|
|
|
|
end
|
2021-06-25 15:43:12 +00:00
|
|
|
end
|