Skip to content

Commit

Permalink
Add ban evasion whitelist support
Browse files Browse the repository at this point in the history
  • Loading branch information
leighmacdonald committed Apr 17, 2024
1 parent 3d41148 commit e2b55bf
Show file tree
Hide file tree
Showing 16 changed files with 140 additions and 52 deletions.
3 changes: 3 additions & 0 deletions frontend/src/api/bans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ export interface SteamBanRecord extends BanBase {
report_id: number;
ban_type: BanType;
include_friends: boolean;
evade_ok: boolean;
}

export interface GroupBanRecord extends BanBase {
Expand Down Expand Up @@ -212,6 +213,7 @@ interface BanReasonPayload {
export interface BanPayloadSteam extends BanBasePayload, BanReasonPayload {
report_id?: number;
include_friends: boolean;
evade_ok: boolean;
ban_type: BanType;
}

Expand Down Expand Up @@ -309,6 +311,7 @@ export const apiUpdateBanSteam = async (
ban_id: number,
payload: UpdateBanPayload & {
include_friends: boolean;
evade_ok: boolean;
ban_type: BanType;
}
) =>
Expand Down
44 changes: 26 additions & 18 deletions frontend/src/component/TopBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { JSX, useMemo, useState, MouseEvent } from 'react';
import { Link as RouterLink } from 'react-router-dom';
import AccountCircleIcon from '@mui/icons-material/AccountCircle';
import ArticleIcon from '@mui/icons-material/Article';
import BlockIcon from '@mui/icons-material/Block';
import CellTowerIcon from '@mui/icons-material/CellTower';
import DarkModeIcon from '@mui/icons-material/DarkMode';
import DashboardIcon from '@mui/icons-material/Dashboard';
Expand Down Expand Up @@ -178,25 +179,32 @@ export const TopBar = () => {
leftIcon: <SubjectIcon sx={colourOpts} />
},
{
href: '/admin/ban/steam',
label: 'Ban Steam',
leftIcon: <NoAccountsIcon sx={colourOpts} />
},
{
href: '/admin/ban/cidr',
label: 'Ban CIDR',
leftIcon: <WifiOffIcon sx={colourOpts} />
},
{
href: '/admin/ban/group',
label: 'Ban Steam Group',
leftIcon: <GroupsIcon sx={colourOpts} />
},
{
href: '/admin/ban/asn',
label: 'Ban ASN',
leftIcon: <PublicOffIcon sx={colourOpts} />
label: 'Ban',
leftIcon: <BlockIcon sx={colourOpts} />,
items: [
{
href: '/admin/ban/steam',
label: 'Steam',
leftIcon: <NoAccountsIcon sx={colourOpts} />
},
{
href: '/admin/ban/cidr',
label: 'IP/CIDR',
leftIcon: <WifiOffIcon sx={colourOpts} />
},
{
href: '/admin/ban/group',
label: 'Steam Group',
leftIcon: <GroupsIcon sx={colourOpts} />
},
{
href: '/admin/ban/asn',
label: 'ASN',
leftIcon: <PublicOffIcon sx={colourOpts} />
}
]
},

{
href: '/admin/reports',
label: 'Reports',
Expand Down
29 changes: 29 additions & 0 deletions frontend/src/component/formik/EvadeOKField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Checkbox from '@mui/material/Checkbox';
import FormControlLabel from '@mui/material/FormControlLabel';
import FormGroup from '@mui/material/FormGroup';
import Tooltip from '@mui/material/Tooltip';
import { useFormikContext } from 'formik';

interface EvadeOKFieldValue {
evade_ok: boolean;
}

export const EvadeOKField = () => {
const { values, handleChange } = useFormikContext<EvadeOKFieldValue>();
return (
<FormGroup>
<Tooltip
title={
'Periodically update known friends lists and include them in the ban'
}
>
<FormControlLabel
control={<Checkbox checked={values.evade_ok} />}
label="Evade OK"
name={'evade_ok'}
onChange={handleChange}
/>
</Tooltip>
</FormGroup>
);
};
7 changes: 3 additions & 4 deletions frontend/src/component/formik/IncludeFriendsField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ interface IncludeFriendsFieldValue {
include_friends: boolean;
}

export const IncludeFriendsField = <T,>() => {
const { values, handleChange } = useFormikContext<
T & IncludeFriendsFieldValue
>();
export const IncludeFriendsField = () => {
const { values, handleChange } =
useFormikContext<IncludeFriendsFieldValue>();
return (
<FormGroup>
<Tooltip
Expand Down
8 changes: 7 additions & 1 deletion frontend/src/component/modal/BanSteamModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
} from '../formik/DurationCustomField';
import { DurationField, DurationFieldValidator } from '../formik/DurationField';
import { ErrorField } from '../formik/ErrorField';
import { EvadeOKField } from '../formik/EvadeOKField.tsx';
import { IncludeFriendsField } from '../formik/IncludeFriendsField';
import { NoteField, NoteFieldValidator } from '../formik/NoteField';
import { ReportIdField, ReportIdFieldValidator } from '../formik/ReportIdField';
Expand All @@ -56,6 +57,7 @@ type BanSteamFormValues = {
duration_custom: Date;
note: string;
include_friends: boolean;
evade_ok: boolean;
existing?: SteamBanRecord;
} & TargetIDInputValue;

Expand Down Expand Up @@ -96,6 +98,7 @@ export const BanSteamModal = NiceModal.create(
reason: values.reason,
reason_text: values.reason_text,
include_friends: values.include_friends,
evade_ok: values.evade_ok,
valid_until: values.duration_custom
}
);
Expand All @@ -111,7 +114,8 @@ export const BanSteamModal = NiceModal.create(
reason_text: values.reason_text,
report_id: values.report_id,
target_id: values.target_id,
include_friends: values.include_friends
include_friends: values.include_friends,
evade_ok: values.evade_ok
});
sendFlash('success', 'Created ban successfully');
modal.resolve(ban_record);
Expand Down Expand Up @@ -150,6 +154,7 @@ export const BanSteamModal = NiceModal.create(
reason_text: existing?.reason_text ?? '',
report_id: existing?.report_id ?? reportId,
include_friends: existing?.include_friends ?? false,
evade_ok: existing?.evade_ok ?? false,
existing: existing
}}
validateOnBlur={true}
Expand All @@ -172,6 +177,7 @@ export const BanSteamModal = NiceModal.create(
<BanReasonField />
<BanReasonTextField paired={true} />
<IncludeFriendsField />
<EvadeOKField />
<DurationField />
<DurationCustomField />
<NoteField />
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/component/table/BanSteamTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,17 @@ export const BanSteamTable = ({ newBans }: { newBans: SteamBanRecord[] }) => {
/>
)
},
{
label: 'E',
tooltip:
'Are othere players allowed to play from the same ip when a ban on that ip is active (eg. banned roomate/family)',
align: 'center',
width: '50px',
sortKey: 'evade_ok',
renderer: (row) => (
<TableCellBool enabled={row.evade_ok} />
)
},
{
label: 'A',
tooltip:
Expand Down
28 changes: 17 additions & 11 deletions frontend/src/page/AdminVotesPage.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { ChangeEvent, useCallback } from 'react';
import useUrlState from '@ahooksjs/use-url-state';
import FilterListIcon from '@mui/icons-material/FilterList';
import HowToVoteIcon from '@mui/icons-material/HowToVote';
import Stack from '@mui/material/Stack';
import Grid from '@mui/material/Unstable_Grid2';
import { Formik } from 'formik';
import { FormikHelpers } from 'formik/dist/types';
import { VoteResult } from '../api/votes.ts';
import { ContainerWithHeader } from '../component/ContainerWithHeader.tsx';
import { ContainerWithHeaderAndButtons } from '../component/ContainerWithHeaderAndButtons';
import { FilterButtons } from '../component/formik/FilterButtons.tsx';
import { SourceIDField } from '../component/formik/SourceIDField.tsx';
Expand Down Expand Up @@ -85,18 +87,22 @@ export const AdminVotesPage = () => {
onSubmit={onSubmit}
>
<Stack spacing={2}>
<Grid container spacing={2}>
<Grid xs={4} sm={4} md={4}>
<SourceIDField />
</Grid>
<Grid xs={4} sm={4} md={4}>
<TargetIDField />
</Grid>
<Grid xs={4} sm={4} md={4}>
<FilterButtons />
<ContainerWithHeader
title={'Filters'}
iconLeft={<FilterListIcon />}
>
<Grid container spacing={2}>
<Grid xs={4} sm={4} md={4}>
<SourceIDField />
</Grid>
<Grid xs={4} sm={4} md={4}>
<TargetIDField />
</Grid>
<Grid xs={4} sm={4} md={4}>
<FilterButtons />
</Grid>
</Grid>
</Grid>

</ContainerWithHeader>
<ContainerWithHeaderAndButtons
title={'Vote History'}
iconLeft={<HowToVoteIcon />}
Expand Down
23 changes: 12 additions & 11 deletions internal/ban/ban_steam_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func (r *banSteamRepository) getBanByColumn(ctx context.Context, column string,
Builder().
Select(
"b.ban_id", "b.target_id", "b.source_id", "b.ban_type", "b.reason",
"b.reason_text", "b.note", "b.origin", "b.valid_until", "b.created_on", "b.updated_on", "b.include_friends",
"b.reason_text", "b.note", "b.origin", "b.valid_until", "b.created_on", "b.updated_on", "b.include_friends", "b.evade_ok",
"b.deleted", "case WHEN b.report_id is null THEN 0 ELSE b.report_id END",
"b.unban_reason_text", "b.is_enabled", "b.appeal_state", "b.last_ip",
"s.personaname as source_personaname", "s.avatarhash",
Expand All @@ -105,7 +105,7 @@ func (r *banSteamRepository) getBanByColumn(ctx context.Context, column string,
if errScan := row.
Scan(&person.BanID, &targetID, &sourceID, &person.BanType, &person.Reason,
&person.ReasonText, &person.Note, &person.Origin, &person.ValidUntil, &person.CreatedOn,
&person.UpdatedOn, &person.IncludeFriends, &person.Deleted, &person.ReportID, &person.UnbanReasonText,
&person.UpdatedOn, &person.IncludeFriends, &person.EvadeOk, &person.Deleted, &person.ReportID, &person.UnbanReasonText,
&person.IsEnabled, &person.AppealState, &person.LastIP,
&person.SourceTarget.SourcePersonaname, &person.SourceTarget.SourceAvatarhash,
&person.SourceTarget.TargetPersonaname, &person.SourceTarget.TargetAvatarhash,
Expand Down Expand Up @@ -173,14 +173,14 @@ func (r *banSteamRepository) Save(ctx context.Context, ban *domain.BanSteam) err
func (r *banSteamRepository) insertBan(ctx context.Context, ban *domain.BanSteam) error {
const query = `
INSERT INTO ban (target_id, source_id, ban_type, reason, reason_text, note, valid_until,
created_on, updated_on, origin, report_id, appeal_state, include_friends, last_ip)
created_on, updated_on, origin, report_id, appeal_state, include_friends, evade_ok, last_ip)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, case WHEN $11 = 0 THEN null ELSE $11 END, $12, $13, $14)
RETURNING ban_id`

errQuery := r.db.
QueryRow(ctx, query, ban.TargetID.Int64(), ban.SourceID.Int64(), ban.BanType, ban.Reason, ban.ReasonText,
ban.Note, ban.ValidUntil, ban.CreatedOn, ban.UpdatedOn, ban.Origin, ban.ReportID, ban.AppealState,
ban.IncludeFriends, &ban.LastIP).
ban.IncludeFriends, ban.EvadeOk, &ban.LastIP).
Scan(&ban.BanID)

if errQuery != nil {
Expand Down Expand Up @@ -214,6 +214,7 @@ func (r *banSteamRepository) updateBan(ctx context.Context, ban *domain.BanSteam
Set("target_id", ban.TargetID.Int64()).
Set("appeal_state", ban.AppealState).
Set("include_friends", ban.IncludeFriends).
Set("evade_ok", ban.EvadeOk).
Where(sq.Eq{"ban_id": ban.BanID})

return r.db.DBErr(r.db.ExecUpdateBuilder(ctx, query))
Expand All @@ -224,7 +225,7 @@ func (r *banSteamRepository) ExpiredBans(ctx context.Context) ([]domain.BanSteam
Builder().
Select("ban_id", "target_id", "source_id", "ban_type", "reason", "reason_text", "note",
"valid_until", "origin", "created_on", "updated_on", "deleted", "case WHEN report_id is null THEN 0 ELSE report_id END",
"unban_reason_text", "is_enabled", "appeal_state", "include_friends").
"unban_reason_text", "is_enabled", "appeal_state", "include_friends", "evade_ok").
From("ban").
Where(sq.And{sq.Lt{"valid_until": time.Now()}, sq.Eq{"deleted": false}})

Expand All @@ -246,7 +247,7 @@ func (r *banSteamRepository) ExpiredBans(ctx context.Context) ([]domain.BanSteam

if errScan := rows.Scan(&ban.BanID, &targetID, &sourceID, &ban.BanType, &ban.Reason, &ban.ReasonText, &ban.Note,
&ban.ValidUntil, &ban.Origin, &ban.CreatedOn, &ban.UpdatedOn, &ban.Deleted, &ban.ReportID, &ban.UnbanReasonText,
&ban.IsEnabled, &ban.AppealState, &ban.IncludeFriends); errScan != nil {
&ban.IsEnabled, &ban.AppealState, &ban.IncludeFriends, &ban.EvadeOk); errScan != nil {
return nil, errors.Join(errScan, domain.ErrScanResult)
}

Expand All @@ -268,7 +269,7 @@ func (r *banSteamRepository) Get(ctx context.Context, filter domain.SteamBansQue
builder := r.db.
Builder().
Select("b.ban_id", "b.target_id", "b.source_id", "b.ban_type", "b.reason",
"b.reason_text", "b.note", "b.origin", "b.valid_until", "b.created_on", "b.updated_on", "b.include_friends",
"b.reason_text", "b.note", "b.origin", "b.valid_until", "b.created_on", "b.updated_on", "b.include_friends", "b.evade_ok",
"b.deleted", "case WHEN b.report_id is null THEN 0 ELSE b.report_id END",
"b.unban_reason_text", "b.is_enabled", "b.appeal_state",
"s.personaname as source_personaname", "s.avatarhash",
Expand Down Expand Up @@ -314,7 +315,7 @@ func (r *banSteamRepository) Get(ctx context.Context, filter domain.SteamBansQue
builder = filter.QueryFilter.ApplySafeOrder(builder, map[string][]string{
"b.": {
"ban_id", "target_id", "source_id", "ban_type", "reason",
"origin", "valid_until", "created_on", "updated_on", "include_friends",
"origin", "valid_until", "created_on", "updated_on", "include_friends", "evade_ok",
"deleted", "report_id", "is_enabled", "appeal_state",
},
"s.": {"source_personaname"},
Expand Down Expand Up @@ -355,7 +356,7 @@ func (r *banSteamRepository) Get(ctx context.Context, filter domain.SteamBansQue
if errScan := rows.
Scan(&person.BanID, &targetID, &sourceID, &person.BanType, &person.Reason,
&person.ReasonText, &person.Note, &person.Origin, &person.ValidUntil, &person.CreatedOn,
&person.UpdatedOn, &person.IncludeFriends, &person.Deleted, &person.ReportID, &person.UnbanReasonText,
&person.UpdatedOn, &person.IncludeFriends, &person.EvadeOk, &person.Deleted, &person.ReportID, &person.UnbanReasonText,
&person.IsEnabled, &person.AppealState,
&person.SourceTarget.SourcePersonaname, &person.SourceTarget.SourceAvatarhash,
&person.SourceTarget.TargetPersonaname, &person.SourceTarget.TargetAvatarhash,
Expand All @@ -382,7 +383,7 @@ func (r *banSteamRepository) GetOlderThan(ctx context.Context, filter domain.Que
Select("b.ban_id", "b.target_id", "b.source_id", "b.ban_type", "b.reason",
"b.reason_text", "b.note", "b.origin", "b.valid_until", "b.created_on", "b.updated_on", "b.deleted",
"case WHEN b.report_id is null THEN 0 ELSE s.report_id END", "b.unban_reason_text", "b.is_enabled",
"b.appeal_state", "b.include_friends").
"b.appeal_state", "b.include_friends", "b.evade_ok").
From("ban b").
Where(sq.And{sq.Lt{"b.updated_on": since}, sq.Eq{"b.deleted": false}})

Expand All @@ -404,7 +405,7 @@ func (r *banSteamRepository) GetOlderThan(ctx context.Context, filter domain.Que

if errQuery = rows.Scan(&ban.BanID, &targetID, &sourceID, &ban.BanType, &ban.Reason, &ban.ReasonText, &ban.Note,
&ban.Origin, &ban.ValidUntil, &ban.CreatedOn, &ban.UpdatedOn, &ban.Deleted, &ban.ReportID, &ban.UnbanReasonText,
&ban.IsEnabled, &ban.AppealState, &ban.AppealState); errQuery != nil {
&ban.IsEnabled, &ban.AppealState, &ban.IncludeFriends, &ban.EvadeOk); errQuery != nil {
return nil, errors.Join(errQuery, domain.ErrScanResult)
}

Expand Down
5 changes: 4 additions & 1 deletion internal/ban/ban_steam_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ type apiBanRequest struct {
DemoName string `json:"demo_name"`
DemoTick int `json:"demo_tick"`
IncludeFriends bool `json:"include_friends"`
EvadeOk bool `json:"evade_ok"`
}

func (h banHandler) onAPIPostBanSteamCreate() gin.HandlerFunc {
Expand Down Expand Up @@ -160,7 +161,7 @@ func (h banHandler) onAPIPostBanSteamCreate() gin.HandlerFunc {

var banSteam domain.BanSteam
if errBanSteam := domain.NewBanSteam(author.SteamID, targetID, duration, req.Reason, req.ReasonText, req.Note,
origin, req.ReportID, req.BanType, req.IncludeFriends, &banSteam,
origin, req.ReportID, req.BanType, req.IncludeFriends, req.EvadeOk, &banSteam,
); errBanSteam != nil {
httphelper.ResponseErr(ctx, http.StatusBadRequest, domain.ErrBadRequest)

Expand Down Expand Up @@ -409,6 +410,7 @@ func (h banHandler) onAPIPostBanUpdate() gin.HandlerFunc {
ReasonText string `json:"reason_text"`
Note string `json:"note"`
IncludeFriends bool `json:"include_friends"`
EvadeOk bool `json:"evade_ok"`
ValidUntil time.Time `json:"valid_until"`
}

Expand Down Expand Up @@ -454,6 +456,7 @@ func (h banHandler) onAPIPostBanUpdate() gin.HandlerFunc {
bannedPerson.BanType = req.BanType
bannedPerson.Reason = req.Reason
bannedPerson.IncludeFriends = req.IncludeFriends
bannedPerson.EvadeOk = req.EvadeOk
bannedPerson.ValidUntil = req.ValidUntil

if errSave := h.bu.Save(ctx, &bannedPerson.BanSteam); errSave != nil {
Expand Down
Loading

0 comments on commit e2b55bf

Please sign in to comment.