Skip to content

Commit

Permalink
Add discord_user_id column
Browse files Browse the repository at this point in the history
  • Loading branch information
Doridian committed Mar 30, 2024
1 parent 8fbc1e1 commit a00bce9
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 44 deletions.
22 changes: 21 additions & 1 deletion lib/space_age_api/models/player.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ defmodule SpaceAgeApi.Models.Player do
@moduledoc false
use Ecto.Schema
import Ecto.Changeset
import Ecto.Query
alias SpaceAgeApi.Models.Player
alias SpaceAgeApi.Repo
alias SpaceAgeApi.Util

@primary_key false
Expand All @@ -20,10 +23,26 @@ defmodule SpaceAgeApi.Models.Player do
field :is_banned, :boolean, default: false
field :ban_reason, :string
field :banned_by, :string
field :discord_user_id, :string

timestamps()
end

def build_query(steamid, select) do
query = from p in Player,
where: p.steamid == ^steamid
if select do
query
|> select(^select)
else
query
end
end

def get_single(steamid, select \\ nil) do
Repo.one(build_query(steamid, select))
end

def public_fields do
[:steamid, :name, :score, :playtime, :faction_name, :is_faction_leader]
end
Expand All @@ -32,8 +51,9 @@ defmodule SpaceAgeApi.Models.Player do
def changeset(player, attrs) do
# credo:disable-for-lines:3
player
|> cast(attrs, [:name, :steamid, :credits, :score, :is_faction_leader, :faction_name, :advancement_level, :research, :playtime, :station_storage, :group, :is_banned, :ban_reason, :banned_by])
|> cast(attrs, [:name, :steamid, :credits, :score, :is_faction_leader, :faction_name, :advancement_level, :research, :playtime, :station_storage, :group, :is_banned, :ban_reason, :banned_by, :discord_user_id])
|> validate_required([:name, :steamid, :credits, :score, :is_faction_leader, :faction_name, :advancement_level, :research, :playtime, :station_storage, :group, :is_banned])
|> unique_constraint(:discord_user_id)
|> put_change(:updated_at, Util.naive_date_time())
end
end
2 changes: 1 addition & 1 deletion lib/space_age_api/plug/authenticate.ex
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ defmodule SpaceAgeApi.Plug.Authenticate do
end
defp verify_auth_header(conn, "client", token) do
{ok, claims} = SpaceAgeApi.Token.verify_and_validate(token)
if ok == :ok and claims["aud"] == "https://api.spaceage.mp/v2/clientauth" do
if ok == :ok and claims["aud"] == "https://api.spaceage.mp/v2/jwt/clientauth" do
steamid = claims["sub"]
server = claims["server"]
faction_name = claims["faction_name"]
Expand Down
3 changes: 2 additions & 1 deletion lib/space_age_api/token.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ defmodule SpaceAgeApi.Token do
def token_config do
default_claims(default_exp: @default_exp, skip: [:aud])
|> add_claim("aud", nil, &(&1 in [
"https://api.spaceage.mp/v2/clientauth"
"https://api.spaceage.mp/v2/jwt/clientauth",
"https://api.spaceage.mp/v2/jwt/discordlink"
]))
end
end
59 changes: 54 additions & 5 deletions lib/space_age_api_web/controllers/discord_controller.ex
Original file line number Diff line number Diff line change
@@ -1,39 +1,88 @@
defmodule SpaceAgeApiWeb.DiscordController do
@moduledoc false
import Ecto.Query

use SpaceAgeApiWeb, :controller
alias SpaceAgeApi.Models.Player
alias SpaceAgeApi.Plug.RawBodyReader

def handle_interaction(conn, 1, _data) do
defp handle_interaction(conn, 1, _data) do
render(conn, "discord.json", type: 1)
end

def handle_interaction(conn, 2, %{
defp handle_interaction(conn, 2, %{
"member" => %{"user" => %{"id" => user_id}},
"data" => %{
"options" => [
%{"name" => "operation", "value" => operation},
],
"name" => "sa"
"name" => "salink"
},
}) do
handle_salink_slash_command(conn, operation, "#{user_id}")
render(conn, "discord.json", type: 4, data: %{
"content" => "The operation is #{operation} and the user id is #{user_id}",
"flags" => 64
})
end

def handle_interaction(conn, 2, _data) do
defp handle_interaction(conn, 2, _data) do
conn
|> send_resp(400, "Unhandled command or invalid parameters")
|> halt
end

def handle_interaction(conn, type, _data) do
defp handle_interaction(conn, type, _data) do
conn
|> send_resp(400, "Bad type: #{type}")
|> halt
end

defp handle_salink_slash_command(conn, "unlink", user_id) do
query = from p in Player,
where: p.discord_user_id == ^user_id
player = Repo.one(query)
set_player_discord_user_id(conn, player, nil)
render(conn, "discord.json", type: 4, data: %{
"content" => "If your Discord account was linked to any Steam account, it has been unlinked.",
"flags" => 64
})
end
defp handle_salink_slash_command(conn, code, user_id) do
{ok, claims} = SpaceAgeApi.Token.verify_and_validate(code)
if ok == :ok and claims["aud"] == "https://api.spaceage.mp/v2/jwt/discordlink" do
steamid = claims["sub"]
player = Player.get_single(steamid)
player_ok = set_player_discord_user_id(conn, player, user_id)
if player_ok == :ok do
render(conn, "discord.json", type: 4, data: %{
"content" => "Your Discord account has successfully been linked to #{steamid}",
"flags" => 64
})
else
conn
|> send_resp(500, "Failed to link (not found?!)")
|> halt
end
else
render(conn, "discord.json", type: 4, data: %{
"content" => "Your linking token was invalid or expired",
"flags" => 64
})
end
end

defp set_player_discord_user_id(_conn, nil, _user_id) do
:not_found
end
defp set_player_discord_user_id(conn, player, user_id) do
changeset = Player.changeset(player, %{
discord_user_id: user_id,
})
changeset_perform_upsert_by_steamid(conn, changeset)
:ok
end

def interaction(conn, params) do
[timestamp | _] = get_req_header(conn, "x-signature-timestamp")
[signature | _] = get_req_header(conn, "x-signature-ed25519")
Expand Down
39 changes: 18 additions & 21 deletions lib/space_age_api_web/controllers/players_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ defmodule SpaceAgeApiWeb.PlayersController do

plug SpaceAgeApi.Plug.Authenticate,
[allow_server: true, allow_client: true, require_steamid: true]
when action in [:get_full]
when action in [:get_full, :make_discordlink_jwt]
plug SpaceAgeApi.Plug.Authenticate, [allow_server: true] when action in [:upsert, :ban, :make_jwt]
plug SpaceAgeApi.Plug.Cache when action in [:list, :get]
plug SpaceAgeApi.Plug.Cache, [time: 5] when action in [:list_banned]
Expand Down Expand Up @@ -38,7 +38,7 @@ defmodule SpaceAgeApiWeb.PlayersController do

def upsert(conn, params) do
steamid = params["steamid"]
player_db = get_single(steamid)
player_db = Player.get_single(steamid)
changeset = upsert_changeset(player_db, params)
changeset_perform_upsert_by_steamid(conn, changeset)
end
Expand All @@ -55,7 +55,7 @@ defmodule SpaceAgeApiWeb.PlayersController do
ban_reason = params["ban_reason"]
banned_by = params["banned_by"]

player = get_single(steamid)
player = Player.get_single(steamid)
if player do
changeset = Player.changeset(player, %{
is_banned: true,
Expand All @@ -72,7 +72,7 @@ defmodule SpaceAgeApiWeb.PlayersController do

def make_jwt(conn, params) do
steamid = params["steamid"]
player = get_single(steamid, [:steamid, :faction_name, :is_faction_leader])
player = Player.get_single(steamid, [:steamid, :faction_name, :is_faction_leader])
if player do
make_jwt_internal(conn, player)
else
Expand All @@ -84,36 +84,33 @@ defmodule SpaceAgeApiWeb.PlayersController do
end
end

defp get_single_show(conn, params, template, select \\ nil) do
def make_discordlink_jwt(conn, params) do
steamid = params["steamid"]
player = get_single(steamid, select)
single_or_404(conn, template, player)
make_jwt_internal(conn, %{
steamid: steamid,
faction_name: "",
is_faction_leader: false,
}, "https://api.spaceage.mp/v2/jwt/discordlink", 5 * 60)
end

defp build_query(steamid, select) do
query = from p in Player,
where: p.steamid == ^steamid
if select do
query
|> select(^select)
else
query
end
defp get_single_show(conn, params, template, select \\ nil) do
steamid = params["steamid"]
player = Player.get_single(steamid, select)
single_or_404(conn, template, player)
end

defp get_single(steamid, select \\ nil) do
Repo.one(build_query(steamid, select))
defp make_jwt_internal(conn, player) do
make_jwt_internal(conn, player, "https://api.spaceage.mp/v2/jwt/clientauth", SpaceAgeApi.Token.default_exp())
end

defp make_jwt_internal(conn, player) do
valid_time = SpaceAgeApi.Token.default_exp()
defp make_jwt_internal(conn, player, aud, valid_time) do
expiry = System.system_time(:second) + valid_time

server = conn.assigns[:auth_server]

jwt = SpaceAgeApi.Token.generate_and_sign!(%{
sub: player.steamid,
aud: "https://api.spaceage.mp/v2/clientauth",
aud: aud,
server: server.name,
faction_name: player.faction_name,
is_faction_leader: player.is_faction_leader,
Expand Down
1 change: 1 addition & 0 deletions lib/space_age_api_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ defmodule SpaceAgeApiWeb.Router do
get "/players/:steamid/full", PlayersController, :get_full
put "/players/:steamid", PlayersController, :upsert
post "/players/:steamid/jwt", PlayersController, :make_jwt
post "/players/:steamid/discordlink", PlayersController, :make_discordlink_jwt
post "/players/:steamid/ban", PlayersController, :ban

get "/factions", FactionsController, :list
Expand Down
1 change: 1 addition & 0 deletions lib/space_age_api_web/views/players_view.ex
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ defmodule SpaceAgeApiWeb.PlayersView do
is_banned: player.is_banned,
ban_reason: player.ban_reason,
banned_by: player.banned_by,
discord_user_id: player.discord_user_id,
}
end

Expand Down
11 changes: 11 additions & 0 deletions priv/repo/migrations/20240330000011_add_discord_user_id.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
defmodule SpaceAgeApi.Repo.Migrations.AddDiscordUserId do
use Ecto.Migration

def change do
alter table(:players) do
add :discord_user_id, :string, default: nil, null: true
end

create unique_index(:players, [:discord_user_id])
end
end
20 changes: 5 additions & 15 deletions register_discord_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,15 @@

# This is an example CHAT_INPUT or Slash Command, with a type of 1
json = {
"name": "sa",
"name": "salink",
"type": 1,
"description": "Commands for interacting with SpaceAge",
"description": "Link SpaceAge to Discord",
"options": [
{
"name": "operation",
"description": "What to do",
"name": "code",
"description": "Link code. Use ""unlink"" unlink any existing account",
"type": 3,
"required": True,
"choices": [
{
"name": "link",
"value": "link"
},
{
"name": "unlink",
"value": "unlink"
}
]
"required": True
}
]
}
Expand Down

0 comments on commit a00bce9

Please sign in to comment.