Skip to content

Commit 08e2222

Browse files
committed
fix: validation and remove XTLSFlow usage
1 parent 845a01d commit 08e2222

6 files changed

Lines changed: 26 additions & 63 deletions

File tree

app/models/stats.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from datetime import datetime as dt
22
from enum import Enum
33

4-
from pydantic import BaseModel, field_validator
4+
from pydantic import BaseModel, Field, field_validator
55

66
from app.utils.helpers import ensure_datetime_timezone
77

@@ -79,7 +79,7 @@ def validator_date(cls, v):
7979

8080
class UserCountMetricStatsList(StatList):
8181
metric: UserCountMetric
82-
count_during_period: int
82+
count_during_period: int = Field(default=0)
8383
stats: dict[int, list[UserCountMetricStat]]
8484

8585

app/routers/node.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import asyncio
22
from typing import Annotated, AsyncGenerator
33

4-
from fastapi import APIRouter, Depends, Request, status
4+
from fastapi import APIRouter, Depends, HTTPException, Request, status
55
from PasarGuardNodeBridge import NodeAPIError
66
from sse_starlette.sse import EventSourceResponse
77

@@ -36,6 +36,7 @@
3636
NodeUsageStatsList,
3737
UserCountMetric,
3838
UserCountMetricStatsList,
39+
validate_user_count_metric_scope,
3940
)
4041
from app.nats.node_rpc import node_nats_client
4142
from app.operation import OperatorType
@@ -155,6 +156,11 @@ async def get_user_count_metric(
155156
_: AdminDetails = Depends(check_sudo_admin),
156157
):
157158
"""Retrieve one user activity/status count metric from node user usage rows."""
159+
try:
160+
validate_user_count_metric_scope(metric, node_id=query.node_id, group_by_node=query.group_by_node)
161+
except ValueError as exc:
162+
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc
163+
158164
return await node_operator.get_user_count_metric(db=db, metric=metric, query=query)
159165

160166

app/routers/user.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
UserCountMetric,
1010
UserCountMetricStatsList,
1111
UserUsageStatsList,
12+
validate_user_count_metric_scope,
1213
)
1314
from app.models.user import (
1415
BulkUser,
@@ -506,6 +507,15 @@ async def get_users_count_metric(
506507
admin: AdminDetails = Depends(get_current),
507508
):
508509
"""Get one users activity/status count metric from usage rows."""
510+
try:
511+
validate_user_count_metric_scope(
512+
metric,
513+
node_id=query.node_id if admin.is_sudo else None,
514+
group_by_node=query.group_by_node if admin.is_sudo else False,
515+
)
516+
except ValueError as exc:
517+
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc
518+
509519
return await user_operator.get_users_count_metric(db, admin=admin, metric=metric, query=query)
510520

511521

dashboard/src/features/bulk/components/bulk-flow.tsx

Lines changed: 5 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {
1111
useBulkAddGroupsToUsers,
1212
useBulkRemoveUsersFromGroups,
1313
useBulkReallocateWireguardPeerIps,
14-
XTLSFlows,
1514
ShadowsocksMethods,
1615
UserStatus,
1716
} from '@/service/api'
@@ -27,7 +26,7 @@ import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group'
2726
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem } from '@/components/ui/command'
2827
import { useTranslation } from 'react-i18next'
2928
import { toast } from 'sonner'
30-
import { Settings, Group, User, Shield, CheckCircle, AlertTriangle, Plus, Minus, X, HardDrive, Calendar, Network, CheckCircle2, ChevronLeft, ChevronRight, Eye, Loader2 } from 'lucide-react'
29+
import { Settings, Group, User, Shield, CheckCircle, AlertTriangle, Plus, Minus, X, HardDrive, Calendar, CheckCircle2, ChevronLeft, ChevronRight, Eye, Loader2 } from 'lucide-react'
3130
import { BulkExpiredDateFilters } from '@/features/bulk/components/bulk-expired-date-filters'
3231
import { DecimalInput } from '@/components/common/decimal-input'
3332
import { SelectorPanel } from '@/features/bulk/components/selector-panel'
@@ -57,7 +56,6 @@ export default function BulkFlow({ operationType }: BulkFlowProps) {
5756

5857
const [currentStep, setCurrentStep] = useState<1 | 2 | 3>(1)
5958

60-
const [selectedFlow, setSelectedFlow] = useState<XTLSFlows | 'none' | undefined>(undefined)
6159
const [selectedMethod, setSelectedMethod] = useState<ShadowsocksMethods | undefined>(undefined)
6260

6361
const [dataLimit, setDataLimit] = useState<number | undefined>(undefined)
@@ -157,7 +155,7 @@ export default function BulkFlow({ operationType }: BulkFlowProps) {
157155
return true
158156
}
159157
if (operationType === 'proxy') {
160-
return selectedFlow || selectedMethod
158+
return selectedMethod
161159
}
162160
if (operationType === 'groups') {
163161
return selectedGroups.length > 0
@@ -172,7 +170,7 @@ export default function BulkFlow({ operationType }: BulkFlowProps) {
172170
case 2:
173171
switch (operationType) {
174172
case 'proxy':
175-
return selectedFlow || selectedMethod
173+
return selectedMethod
176174
case 'data':
177175
return dataLimit !== undefined
178176
case 'expire':
@@ -246,7 +244,6 @@ export default function BulkFlow({ operationType }: BulkFlowProps) {
246244
case 'proxy':
247245
return {
248246
...basePayload,
249-
flow: selectedFlow === 'none' ? ('' as XTLSFlows) : selectedFlow,
250247
method: selectedMethod,
251248
dry_run: false,
252249
}
@@ -348,7 +345,6 @@ export default function BulkFlow({ operationType }: BulkFlowProps) {
348345
toast.success(t('operationSuccess', { defaultValue: 'Operation successful!' }), { description })
349346

350347
setCurrentStep(1)
351-
setSelectedFlow(undefined)
352348
setSelectedMethod(undefined)
353349
setDataLimit(undefined)
354350
setExpireSeconds(undefined)
@@ -386,7 +382,6 @@ export default function BulkFlow({ operationType }: BulkFlowProps) {
386382
case 'proxy':
387383
return {
388384
...basePayload,
389-
flow: selectedFlow === 'none' ? ('' as XTLSFlows) : selectedFlow,
390385
method: selectedMethod,
391386
dry_run: true,
392387
}
@@ -541,28 +536,7 @@ export default function BulkFlow({ operationType }: BulkFlowProps) {
541536
<div className="space-y-3 sm:space-y-4">
542537
{operationType === 'proxy' && (
543538
<div className="space-y-3 sm:space-y-4">
544-
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 sm:gap-4">
545-
<div className="space-y-2">
546-
<Label htmlFor="flow" className="flex items-center gap-1.5 text-sm font-medium">
547-
<Network className="text-muted-foreground h-3.5 w-3.5" />
548-
{t('bulk.flowLabel', { defaultValue: 'Flow' })}
549-
</Label>
550-
<Select value={selectedFlow || ''} onValueChange={value => setSelectedFlow(value as XTLSFlows | 'none')}>
551-
<SelectTrigger>
552-
<SelectValue placeholder={t('bulk.selectFlowPlaceholder', { defaultValue: 'Select flow' })} />
553-
</SelectTrigger>
554-
<SelectContent>
555-
<SelectItem value="none">{t('none', { defaultValue: 'None' })}</SelectItem>
556-
{Object.values(XTLSFlows)
557-
.filter(flow => flow !== '')
558-
.map(flow => (
559-
<SelectItem key={flow} value={flow}>
560-
{flow}
561-
</SelectItem>
562-
))}
563-
</SelectContent>
564-
</Select>
565-
</div>
539+
<div className="grid grid-cols-1 gap-3 sm:gap-4">
566540
<div className="space-y-2">
567541
<Label htmlFor="method" className="flex items-center gap-1.5 text-sm font-medium">
568542
<Settings className="text-muted-foreground h-3.5 w-3.5" />
@@ -1019,7 +993,7 @@ export default function BulkFlow({ operationType }: BulkFlowProps) {
1019993
{operationType === 'proxy' && (
1020994
<div className="flex items-center justify-between">
1021995
<span className="text-muted-foreground">{t('bulk.settings', { defaultValue: 'Settings' })}:</span>
1022-
<span>{t('bulk.flowMethod', { flow: selectedFlow === 'none' || !selectedFlow ? t('none') : selectedFlow, method: selectedMethod || t('none') })}</span>
996+
<span>{selectedMethod || t('none')}</span>
1023997
</div>
1024998
)}
1025999

dashboard/src/features/templates/dialogs/user-template-modal.tsx

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import {
2020
useCreateUserTemplate,
2121
useModifyUserTemplate,
2222
UserStatusCreate,
23-
XTLSFlows,
2423
} from '@/service/api'
2524
import { formatBytes, gbToBytes } from '@/utils/formatByte'
2625
import { queryClient } from '@/utils/query-client.ts'
@@ -191,10 +190,9 @@ export default function UserTemplateModal({ isDialogOpen, onOpenChange, form, ed
191190
data_limit_reset_strategy: hasDataLimit ? values.data_limit_reset_strategy : undefined,
192191
reset_usages: values.reset_usages,
193192
extra_settings:
194-
values.method || values.flow
193+
values.method
195194
? {
196195
method: values.method,
197-
flow: values.flow,
198196
}
199197
: undefined,
200198
}
@@ -239,7 +237,6 @@ export default function UserTemplateModal({ isDialogOpen, onOpenChange, form, ed
239237
'on_hold_timeout',
240238
'data_limit_reset_strategy',
241239
'method',
242-
'flow',
243240
'reset_usages',
244241
]
245242
handleError({ error, fields, form, contextKey: 'groups' })
@@ -527,28 +524,6 @@ export default function UserTemplateModal({ isDialogOpen, onOpenChange, form, ed
527524
)}
528525
/>
529526

530-
<FormField
531-
control={form.control}
532-
name="flow"
533-
render={({ field }) => (
534-
<FormItem>
535-
<FormLabel>{t('templates.flow')}</FormLabel>
536-
<Select onValueChange={value => field.onChange(value === 'null' ? undefined : value)} value={field.value ?? 'null'}>
537-
<FormControl>
538-
<SelectTrigger>
539-
<SelectValue placeholder={t('userDialog.proxySettings.flow', { defaultValue: 'Flow' })} />
540-
</SelectTrigger>
541-
</FormControl>
542-
<SelectContent>
543-
<SelectItem value="null">{t('userDialog.proxySettings.flow.none', { defaultValue: 'None' })}</SelectItem>
544-
<SelectItem value={XTLSFlows['xtls-rprx-vision']}>xtls-rprx-vision</SelectItem>
545-
<SelectItem value={XTLSFlows['xtls-rprx-vision-udp443']}>xtls-rprx-vision-udp443</SelectItem>
546-
</SelectContent>
547-
</Select>
548-
<FormMessage />
549-
</FormItem>
550-
)}
551-
/>
552527
<FormField control={form.control} name="groups" render={({ field }) => <GroupsSelector control={form.control} name="groups" onGroupsChange={field.onChange} />} />
553528
</div>
554529
</div>

dashboard/src/features/templates/forms/user-template-form.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { DataLimitResetStrategy, ShadowsocksMethods, UserStatusCreate, XTLSFlows } from '@/service/api'
1+
import { DataLimitResetStrategy, ShadowsocksMethods, UserStatusCreate } from '@/service/api'
22
import { zodResolver } from '@hookform/resolvers/zod'
33
import type { TFunction } from 'i18next'
44
import type { FieldError, FieldErrors, Resolver } from 'react-hook-form'
@@ -16,7 +16,6 @@ const userTemplateFormObjectSchema = z.object({
1616
method: z
1717
.enum([ShadowsocksMethods['aes-128-gcm'], ShadowsocksMethods['aes-256-gcm'], ShadowsocksMethods['chacha20-ietf-poly1305'], ShadowsocksMethods['xchacha20-poly1305']])
1818
.default(ShadowsocksMethods['chacha20-ietf-poly1305']),
19-
flow: z.enum([XTLSFlows[''], XTLSFlows['xtls-rprx-vision'], XTLSFlows['xtls-rprx-vision-udp443']]).default(XTLSFlows['']),
2019
groups: z.array(z.number()).min(1, 'validation.required'),
2120
data_limit_reset_strategy: z
2221
.enum([
@@ -57,7 +56,6 @@ export const userTemplateFormDefaultValues: Partial<UserTemplatesFromValueInput>
5756
hwid_limit: undefined,
5857
expire_duration: 0,
5958
method: ShadowsocksMethods['chacha20-ietf-poly1305'],
60-
flow: XTLSFlows[''],
6159
on_hold_timeout: undefined,
6260
groups: [],
6361
reset_usages: false,

0 commit comments

Comments
 (0)