diff --git a/src/GZCTF/ClientApp/package.json b/src/GZCTF/ClientApp/package.json index 87a9e26c1..cb2417ba9 100644 --- a/src/GZCTF/ClientApp/package.json +++ b/src/GZCTF/ClientApp/package.json @@ -38,8 +38,8 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-pdf": "^7.1.2", - "react-router": "^6.14.0", - "react-router-dom": "^6.14.0", + "react-router": "^6.14.1", + "react-router-dom": "^6.14.1", "swr": "^2.2.0", "vite-tsconfig-paths": "^4.2.0" }, diff --git a/src/GZCTF/ClientApp/pnpm-lock.yaml b/src/GZCTF/ClientApp/pnpm-lock.yaml index bad5a2e6f..252bd07e0 100644 --- a/src/GZCTF/ClientApp/pnpm-lock.yaml +++ b/src/GZCTF/ClientApp/pnpm-lock.yaml @@ -87,11 +87,11 @@ dependencies: specifier: ^7.1.2 version: 7.1.2(react-dom@18.2.0)(react@18.2.0) react-router: - specifier: ^6.14.0 - version: 6.14.0(react@18.2.0) + specifier: ^6.14.1 + version: 6.14.1(react@18.2.0) react-router-dom: - specifier: ^6.14.0 - version: 6.14.0(react-dom@18.2.0)(react@18.2.0) + specifier: ^6.14.1 + version: 6.14.1(react-dom@18.2.0)(react@18.2.0) swr: specifier: ^2.2.0 version: 2.2.0(react@18.2.0) @@ -1254,8 +1254,8 @@ packages: react: 18.2.0 dev: false - /@remix-run/router@1.7.0: - resolution: {integrity: sha512-Eu1V3kz3mV0wUpVTiFHuaT8UD1gj/0VnoFHQYX35xlslQUpe8CuYoKFn9d4WZFHm3yDywz6ALZuGdnUPKrNeAw==} + /@remix-run/router@1.7.1: + resolution: {integrity: sha512-bgVQM4ZJ2u2CM8k1ey70o1ePFXsEzYVZoWghh6WjM8p59jQ7HxzbHW4SbnWFG7V9ig9chLawQxDTZ3xzOF8MkQ==} engines: {node: '>=14'} dev: false @@ -3320,26 +3320,26 @@ packages: use-sidecar: 1.1.2(@types/react@18.2.14)(react@18.2.0) dev: false - /react-router-dom@6.14.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-YEwlApKwzMMMbGbhh+Q7MsloTldcwMgHxUY/1g0uA62+B1hZo2jsybCWIDCL8zvIDB1FA0pBKY9chHbZHt+2dQ==} + /react-router-dom@6.14.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-ssF6M5UkQjHK70fgukCJyjlda0Dgono2QGwqGvuk7D+EDGHdacEN3Yke2LTMjkrpHuFwBfDFsEjGVXBDmL+bWw==} engines: {node: '>=14'} peerDependencies: react: '>=16.8' react-dom: '>=16.8' dependencies: - '@remix-run/router': 1.7.0 + '@remix-run/router': 1.7.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-router: 6.14.0(react@18.2.0) + react-router: 6.14.1(react@18.2.0) dev: false - /react-router@6.14.0(react@18.2.0): - resolution: {integrity: sha512-OD+vkrcGbvlwkspUFDgMzsu1RXwdjNh83YgG/28lBnDzgslhCgxIqoExLlxsfTpIygp7fc+Hd3esloNwzkm2xA==} + /react-router@6.14.1(react@18.2.0): + resolution: {integrity: sha512-U4PfgvG55LdvbQjg5Y9QRWyVxIdO1LlpYT7x+tMAxd9/vmiPuJhIwdxZuIQLN/9e3O4KFDHYfR9gzGeYMasW8g==} engines: {node: '>=14'} peerDependencies: react: '>=16.8' dependencies: - '@remix-run/router': 1.7.0 + '@remix-run/router': 1.7.1 react: 18.2.0 dev: false diff --git a/src/GZCTF/ClientApp/src/Api.ts b/src/GZCTF/ClientApp/src/Api.ts index 8628b8099..1fe843d1b 100644 --- a/src/GZCTF/ClientApp/src/Api.ts +++ b/src/GZCTF/ClientApp/src/Api.ts @@ -404,9 +404,15 @@ export interface TeamUserInfoModel { /** 队伍信息更改(Admin) */ export interface AdminTeamModel { - /** 队伍名称 */ + /** + * 队伍名称 + * @maxLength 15 + */ name?: string | null - /** 队伍签名 */ + /** + * 队伍签名 + * @maxLength 31 + */ bio?: string | null /** 是否锁定 */ locked?: boolean | null @@ -495,6 +501,107 @@ export interface WriteupInfoModel { uploadTimeUTC?: string } +/** 列表响应 */ +export interface ArrayResponseOfContainerInstanceModel { + /** 数据 */ + data: ContainerInstanceModel[] + /** + * 数据长度 + * @format int32 + */ + length: number + /** + * 总长度 + * @format int32 + */ + total?: number +} + +/** 容器实例信息(Admin) */ +export interface ContainerInstanceModel { + /** 队伍 */ + team?: TeamModel | null + /** 题目 */ + challenge?: ChallengeModel | null + /** 容器镜像 */ + image?: string + /** 容器数据库 ID */ + containerGuid?: string + /** 容器 ID */ + containerId?: string + /** + * 容器创建时间 + * @format date-time + */ + startedAt?: string + /** + * 容器期望终止时间 + * @format date-time + */ + expectStopAt?: string + /** 公开 IP */ + publicIP?: string | null + /** + * 公开端口 + * @format int32 + */ + publicPort?: number | null +} + +/** 队伍信息 */ +export interface TeamModel { + /** + * 队伍 ID + * @format int32 + */ + id?: number + /** 队名 */ + name?: string +} + +/** 题目信息 */ +export interface ChallengeModel { + /** + * 题目 ID + * @format int32 + */ + id?: number + /** 题目名称 */ + title?: string + /** 题目标签 */ + tag?: ChallengeTag +} + +/** 题目标签 */ +export enum ChallengeTag { + Misc = 'Misc', + Crypto = 'Crypto', + Pwn = 'Pwn', + Web = 'Web', + Reverse = 'Reverse', + Blockchain = 'Blockchain', + Forensics = 'Forensics', + Hardware = 'Hardware', + Mobile = 'Mobile', + PPC = 'PPC', +} + +/** 列表响应 */ +export interface ArrayResponseOfLocalFile { + /** 数据 */ + data: LocalFile[] + /** + * 数据长度 + * @format int32 + */ + length: number + /** + * 总长度 + * @format int32 + */ + total?: number +} + export interface LocalFile { /** * 文件哈希 @@ -785,20 +892,6 @@ export interface ChallengeEditDetailModel { flags: FlagInfoModel[] } -/** 题目标签 */ -export enum ChallengeTag { - Misc = 'Misc', - Crypto = 'Crypto', - Pwn = 'Pwn', - Web = 'Web', - Reverse = 'Reverse', - Blockchain = 'Blockchain', - Forensics = 'Forensics', - Hardware = 'Hardware', - Mobile = 'Mobile', - PPC = 'PPC', -} - export enum ChallengeType { StaticAttachment = 'StaticAttachment', StaticContainer = 'StaticContainer', @@ -2485,7 +2578,64 @@ export class Api extends HttpClient mutate(`/api/admin/writeups/${id}/all`, data, options), /** - * @description 使用此接口获取全部日志,需要Admin权限 + * @description 使用此接口获取全部容器实例,需要Admin权限 + * + * @tags Admin + * @name AdminInstances + * @summary 获取全部容器实例 + * @request GET:/api/admin/instances + */ + adminInstances: (params: RequestParams = {}) => + this.request({ + path: `/api/admin/instances`, + method: 'GET', + format: 'json', + ...params, + }), + /** + * @description 使用此接口获取全部容器实例,需要Admin权限 + * + * @tags Admin + * @name AdminInstances + * @summary 获取全部容器实例 + * @request GET:/api/admin/instances + */ + useAdminInstances: (options?: SWRConfiguration, doFetch: boolean = true) => + useSWR( + doFetch ? `/api/admin/instances` : null, + options + ), + + /** + * @description 使用此接口获取全部容器实例,需要Admin权限 + * + * @tags Admin + * @name AdminInstances + * @summary 获取全部容器实例 + * @request GET:/api/admin/instances + */ + mutateAdminInstances: ( + data?: ArrayResponseOfContainerInstanceModel | Promise, + options?: MutatorOptions + ) => mutate(`/api/admin/instances`, data, options), + + /** + * @description 使用此接口强制删除容器实例,需要Admin权限 + * + * @tags Admin + * @name AdminDestroyInstance + * @summary 删除容器实例 + * @request DELETE:/api/admin/instances/{id} + */ + adminDestroyInstance: (id: string, params: RequestParams = {}) => + this.request({ + path: `/api/admin/instances/${id}`, + method: 'DELETE', + ...params, + }), + + /** + * @description 使用此接口获取全部文件,需要Admin权限 * * @tags Admin * @name AdminFiles @@ -2507,7 +2657,7 @@ export class Api extends HttpClient - this.request({ + this.request({ path: `/api/admin/files`, method: 'GET', query: query, @@ -2515,7 +2665,7 @@ export class Api extends HttpClient extends HttpClient - useSWR(doFetch ? [`/api/admin/files`, query] : null, options), + useSWR( + doFetch ? [`/api/admin/files`, query] : null, + options + ), /** - * @description 使用此接口获取全部日志,需要Admin权限 + * @description 使用此接口获取全部文件,需要Admin权限 * * @tags Admin * @name AdminFiles @@ -2561,9 +2714,9 @@ export class Api extends HttpClient, + data?: ArrayResponseOfLocalFile | Promise, options?: MutatorOptions - ) => mutate([`/api/admin/files`, query], data, options), + ) => mutate([`/api/admin/files`, query], data, options), } assets = { /** diff --git a/src/GZCTF/ClientApp/src/components/ActionIconWithConfirm.tsx b/src/GZCTF/ClientApp/src/components/ActionIconWithConfirm.tsx index 8ea26c3ad..77c463564 100644 --- a/src/GZCTF/ClientApp/src/components/ActionIconWithConfirm.tsx +++ b/src/GZCTF/ClientApp/src/components/ActionIconWithConfirm.tsx @@ -28,10 +28,19 @@ export const ActionIconWithConfirm: FC = (props) => - + {props.message} - + +