Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions hasura/functions/servers/get_server_connection.sql
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ BEGIN
RETURN NULL;
END IF;

-- A restricted server's connect info is also what lists it for guests
-- and players, so returning nothing hides it from everyone not allowed.
IF NOT can_connect_to_server(server, hasura_session) THEN
RETURN NULL;
END IF;

connection_string := CONCAT('connect ', get_server_host(server));

IF NULLIF(server.connect_password, '') IS NULL THEN
Expand Down Expand Up @@ -40,6 +46,10 @@ BEGIN
RETURN NULL;
END IF;

IF NOT can_connect_to_server(server, hasura_session) THEN
RETURN NULL;
END IF;

server_host := get_server_host(server);

RETURN CONCAT('steam://run/', CASE WHEN server.game = 'csgo' THEN '4465480' ELSE '730' END, '//+connect ', server_host);
Expand Down
123 changes: 123 additions & 0 deletions hasura/functions/servers/server_access.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
-- An event only lets its members in while it is running, judged the way the
-- web's eventPhase does: an event with no start date has not started, and one
-- with no end date runs until it is given one.
CREATE OR REPLACE FUNCTION public.server_access_event_is_live(event public.events)
RETURNS boolean
LANGUAGE sql
STABLE
AS $$
SELECT event.starts_at IS NOT NULL
AND event.starts_at <= now()
AND (event.ends_at IS NULL OR event.ends_at >= now());
$$;

-- Everyone a restricted server lets in. Staff always get in so a restricted
-- server can still be moderated. The event branches mirror is_event_member.
CREATE OR REPLACE FUNCTION public.server_allowed_steam_ids(_server_id uuid)
RETURNS TABLE (steam_id bigint)
LANGUAGE sql
STABLE
AS $$
WITH server AS (
SELECT s.access_min_role
FROM public.servers s
WHERE s.id = _server_id
),
live_events AS (
SELECT e.id, e.organizer_steam_id
FROM public.server_access_events sae
JOIN public.events e ON e.id = sae.event_id
WHERE sae.server_id = _server_id
AND public.server_access_event_is_live(e)
)
SELECT sap.steam_id
FROM public.server_access_players sap
WHERE sap.server_id = _server_id
UNION
SELECT p.steam_id
FROM public.players p
WHERE public.is_role_below('moderator', p.role)
OR EXISTS (
SELECT 1 FROM server
WHERE server.access_min_role IS NOT NULL
AND public.is_role_below(server.access_min_role, p.role)
)
UNION
SELECT le.organizer_steam_id FROM live_events le
UNION
SELECT eo.steam_id
FROM live_events le
JOIN public.event_organizers eo ON eo.event_id = le.id
UNION
SELECT ep.steam_id
FROM live_events le
JOIN public.event_players ep ON ep.event_id = le.id
UNION
SELECT tr.player_steam_id
FROM live_events le
JOIN public.event_teams et ON et.event_id = le.id
JOIN public.team_roster tr ON tr.team_id = et.team_id
UNION
SELECT ttr.player_steam_id
FROM live_events le
JOIN public.event_tournaments evt ON evt.event_id = le.id
JOIN public.tournament_team_roster ttr ON ttr.tournament_id = evt.tournament_id
UNION
SELECT torg.steam_id
FROM live_events le
JOIN public.event_tournaments evt ON evt.event_id = le.id
JOIN public.tournament_organizers torg ON torg.tournament_id = evt.tournament_id
UNION
SELECT tt.owner_steam_id
FROM live_events le
JOIN public.event_tournaments evt ON evt.event_id = le.id
JOIN public.tournament_teams tt ON tt.tournament_id = evt.tournament_id
WHERE tt.owner_steam_id IS NOT NULL;
$$;

-- Answers for one viewer without expanding the whole allowlist: a role rule on
-- a big deployment covers every registered player.
CREATE OR REPLACE FUNCTION public.can_connect_to_server(server public.servers, hasura_session json)
RETURNS boolean
LANGUAGE plpgsql
STABLE
AS $$
DECLARE
viewer bigint;
BEGIN
IF NOT server.access_restricted THEN
RETURN true;
END IF;

IF COALESCE(public.is_above_role('moderator', hasura_session), false) THEN
RETURN true;
END IF;

viewer := NULLIF(NULLIF(hasura_session ->> 'x-hasura-user-id', ''), '0')::bigint;

IF viewer IS NULL THEN
RETURN false;
END IF;

IF server.access_min_role IS NOT NULL
AND COALESCE(public.is_above_role(server.access_min_role, hasura_session), false) THEN
RETURN true;
END IF;

IF EXISTS (
SELECT 1 FROM public.server_access_players sap
WHERE sap.server_id = server.id AND sap.steam_id = viewer
) THEN
RETURN true;
END IF;

RETURN EXISTS (
SELECT 1
FROM public.server_access_events sae
JOIN public.events e ON e.id = sae.event_id
WHERE sae.server_id = server.id
AND public.server_access_event_is_live(e)
AND public.is_event_member(e, viewer)
);
END;
$$;
31 changes: 31 additions & 0 deletions hasura/metadata/actions.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -2688,3 +2688,34 @@ type ImportWorkshopCollectionOutput {
maps: [ImportedWorkshopMap!]!
skipped: Int!
}

type Mutation {
setServerAccess(
server_id: uuid!
restricted: Boolean!
min_role: String
steam_ids: [String!]!
event_ids: [uuid!]!
): SuccessOutput
}

type Mutation {
setServerSettings(
server_id: uuid!
map_rotation: ServerMapRotationInput
plugins: [ServerPluginInput!]
access: ServerAccessInput
): SuccessOutput
}

input ServerMapRotationInput {
map_ids: [uuid!]!
shuffle: Boolean!
}

input ServerAccessInput {
restricted: Boolean!
min_role: String
steam_ids: [String!]!
event_ids: [uuid!]!
}
18 changes: 18 additions & 0 deletions hasura/metadata/actions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2022,6 +2022,22 @@ actions:
permissions:
- role: administrator
comment: Add every map in a Steam workshop collection to the map catalog
- name: setServerAccess
definition:
kind: synchronous
handler: '{{HASURA_GRAPHQL_ACTIONS_HOOK}}'
forward_client_headers: true
permissions:
- role: administrator
comment: Restrict who may connect to a community server
- name: setServerSettings
definition:
kind: synchronous
handler: '{{HASURA_GRAPHQL_ACTIONS_HOOK}}'
forward_client_headers: true
permissions:
- role: administrator
comment: Save a community server's rotation, plugins and access, restarting it at most once
- name: moveDedicatedServerToNode
definition:
kind: synchronous
Expand Down Expand Up @@ -2051,6 +2067,8 @@ custom_types:
- name: UtilityPlaybookStepInput
- name: UtilitySightlinePairInput
- name: ServerPluginInput
- name: ServerMapRotationInput
- name: ServerAccessInput
objects:
- name: Award
- name: AwardRecipient
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
table:
name: server_access_events
schema: public
object_relationships:
- name: event
using:
foreign_key_constraint_on: event_id
- name: server
using:
foreign_key_constraint_on: server_id
select_permissions:
- role: administrator
permission:
columns:
- event_id
- server_id
filter: {}
comment: ""
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
table:
name: server_access_players
schema: public
object_relationships:
- name: player
using:
foreign_key_constraint_on: steam_id
- name: server
using:
foreign_key_constraint_on: server_id
select_permissions:
- role: administrator
permission:
columns:
- server_id
- steam_id
filter: {}
comment: ""
16 changes: 16 additions & 0 deletions hasura/metadata/databases/default/tables/public_servers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,20 @@ object_relationships:
name: server_regions
schema: public
array_relationships:
- name: access_events
using:
foreign_key_constraint_on:
column: server_id
table:
name: server_access_events
schema: public
- name: access_players
using:
foreign_key_constraint_on:
column: server_id
table:
name: server_access_players
schema: public
- name: map_rotation
using:
foreign_key_constraint_on:
Expand Down Expand Up @@ -93,6 +107,8 @@ select_permissions:
- role: administrator
permission:
columns:
- access_min_role
- access_restricted
- api_password
- boot_status
- boot_status_detail
Expand Down
2 changes: 2 additions & 0 deletions hasura/metadata/databases/default/tables/tables.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@
- "!include public_plugin_versions.yaml"
- "!include public_push_subscriptions.yaml"
- "!include public_seasons.yaml"
- "!include public_server_access_events.yaml"
- "!include public_server_access_players.yaml"
- "!include public_server_map_rotation.yaml"
- "!include public_server_migrations.yaml"
- "!include public_server_plugins.yaml"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
DROP TABLE IF EXISTS public.server_access_events;

DROP TABLE IF EXISTS public.server_access_players;

ALTER TABLE public.servers
DROP CONSTRAINT IF EXISTS servers_access_min_role_fkey,
DROP COLUMN IF EXISTS access_min_role,
DROP COLUMN IF EXISTS access_restricted;
37 changes: 37 additions & 0 deletions hasura/migrations/default/1889000000800_server_access/up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
ALTER TABLE public.servers
ADD COLUMN IF NOT EXISTS access_restricted boolean NOT NULL DEFAULT false,
ADD COLUMN IF NOT EXISTS access_min_role text;

DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint WHERE conname = 'servers_access_min_role_fkey'
) THEN
ALTER TABLE public.servers
ADD CONSTRAINT servers_access_min_role_fkey FOREIGN KEY (access_min_role)
REFERENCES public.e_player_roles (value) ON UPDATE CASCADE ON DELETE SET NULL;
END IF;
END $$;

CREATE TABLE IF NOT EXISTS public.server_access_players (
server_id uuid NOT NULL,
steam_id bigint NOT NULL,
PRIMARY KEY (server_id, steam_id),
CONSTRAINT server_access_players_server_fkey FOREIGN KEY (server_id)
REFERENCES public.servers (id) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT server_access_players_player_fkey FOREIGN KEY (steam_id)
REFERENCES public.players (steam_id) ON UPDATE CASCADE ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS public.server_access_events (
server_id uuid NOT NULL,
event_id uuid NOT NULL,
PRIMARY KEY (server_id, event_id),
CONSTRAINT server_access_events_server_fkey FOREIGN KEY (server_id)
REFERENCES public.servers (id) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT server_access_events_event_fkey FOREIGN KEY (event_id)
REFERENCES public.events (id) ON UPDATE CASCADE ON DELETE CASCADE
);

CREATE INDEX IF NOT EXISTS server_access_events_event_idx
ON public.server_access_events (event_id);
Loading
Loading